Exemplo n.º 1
0
        public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
        .UseServiceProviderFactory(new AutofacServiceProviderFactory())
        .ConfigureWebHostDefaults(whb => whb

                                  .UseConfiguration(InitUtils.BuildConfiguration(args).Build())
                                  .ConfigureKestrel(opts => { opts.ListenAnyIP(5000); })
                                  .UseStartup <Startup>());
Exemplo n.º 2
0
        public ServiceProvider BuildServiceProvider() => new ServiceCollection()
        .AddTransient(_ => _config.GetSection("PluralKit").Get <CoreConfig>() ?? new CoreConfig())
        .AddTransient(_ => _config.GetSection("PluralKit").GetSection("Bot").Get <BotConfig>() ?? new BotConfig())

        .AddSingleton <DbConnectionCountHolder>()
        .AddTransient <DbConnectionFactory>()

        .AddSingleton <IDiscordClient, DiscordShardedClient>(_ => new DiscordShardedClient(new DiscordSocketConfig
        {
            MessageCacheSize    = 5,
            ExclusiveBulkDelete = true
        }))
        .AddSingleton <Bot>()

        .AddSingleton(_ => new CommandService(new CommandServiceConfig
        {
            CaseSensitiveCommands = false,
            QuotationMarkAliasMap = new Dictionary <char, char>
            {
                { '"', '"' },
                { '\'', '\'' },
                { '‘', '’' },
                { '“', '”' },
                { '„', '‟' },
            },
            // We're already asyncing stuff by forking off at the client event handlers
            // So adding an additional layer of forking is pointless
            // and leads to the service scope being disposed of prematurely
            DefaultRunMode = RunMode.Sync
        }))
        .AddTransient <EmbedService>()
        .AddTransient <ProxyService>()
        .AddTransient <LogChannelService>()
        .AddTransient <DataFileService>()
        .AddTransient <WebhookExecutorService>()

        .AddTransient <ProxyCacheService>()
        .AddSingleton <WebhookCacheService>()

        .AddTransient <SystemStore>()
        .AddTransient <MemberStore>()
        .AddTransient <MessageStore>()
        .AddTransient <SwitchStore>()

        .AddSingleton(svc => InitUtils.InitMetrics(svc.GetRequiredService <CoreConfig>()))
        .AddSingleton <PeriodicStatCollector>()

        .AddScoped(_ => new Sentry.Scope(null))
        .AddTransient <PKEventHandler>()

        .AddScoped <EventIdProvider>()
        .AddSingleton(svc => new LoggerProvider(svc.GetRequiredService <CoreConfig>(), "bot"))
        .AddScoped(svc => svc.GetRequiredService <LoggerProvider>().RootLogger.ForContext("EventId", svc.GetRequiredService <EventIdProvider>().EventId))

        .AddMemoryCache()

        .BuildServiceProvider();
Exemplo n.º 3
0
 public void ConfigureContainer(ContainerBuilder builder)
 {
     builder.RegisterInstance(InitUtils.BuildConfiguration(Environment.GetCommandLineArgs()).Build())
     .As <IConfiguration>();
     builder.RegisterModule(new ConfigModule <ApiConfig>("API"));
     builder.RegisterModule(new LoggingModule("api"));
     builder.RegisterModule(new MetricsModule("API"));
     builder.RegisterModule <DataStoreModule>();
     builder.RegisterModule <APIModule>();
 }
Exemplo n.º 4
0
    public static async Task Main(string[] args)
    {
        InitUtils.InitStatic();
        await BuildInfoService.LoadVersion();

        var host   = CreateHostBuilder(args).Build();
        var config = host.Services.GetRequiredService <CoreConfig>();
        await host.Services.GetRequiredService <RedisService>().InitAsync(config);

        await host.RunAsync();
    }
Exemplo n.º 5
0
 public static IHostBuilder CreateHostBuilder(string[] args) =>
 Host.CreateDefaultBuilder(args)
 .UseServiceProviderFactory(new AutofacServiceProviderFactory())
 .UseSerilog()
 .ConfigureWebHostDefaults(whb => whb
                           .UseConfiguration(InitUtils.BuildConfiguration(args).Build())
                           .ConfigureKestrel(opts =>
 {
     opts.ListenAnyIP(opts.ApplicationServices.GetRequiredService <ApiConfig>().Port);
 })
                           .UseStartup <Startup>());
Exemplo n.º 6
0
 public void ConfigureContainer(ContainerBuilder builder)
 {
     builder.RegisterInstance(InitUtils.BuildConfiguration(Environment.GetCommandLineArgs()).Build())
     .As <IConfiguration>();
     builder.RegisterModule(new ConfigModule <ApiConfig>("API"));
     builder.RegisterModule(new LoggingModule("api",
                                              cfg: new LoggerConfiguration().Filter.ByExcluding(exc => exc.Exception is PKError || exc.Exception.IsUserError())));
     builder.RegisterModule(new MetricsModule("API"));
     builder.RegisterModule <DataStoreModule>();
     builder.RegisterModule <APIModule>();
 }
Exemplo n.º 7
0
        public ServiceProvider BuildServiceProvider() => new ServiceCollection()
        .AddTransient(_ => _config.GetSection("PluralKit").Get <CoreConfig>() ?? new CoreConfig())
        .AddTransient(_ => _config.GetSection("PluralKit").GetSection("Bot").Get <BotConfig>() ?? new BotConfig())

        .AddSingleton <DbConnectionCountHolder>()
        .AddTransient <DbConnectionFactory>()

        .AddSingleton <IDiscordClient, DiscordShardedClient>(_ => new DiscordShardedClient(new DiscordSocketConfig
        {
            MessageCacheSize    = 5,
            ExclusiveBulkDelete = true,
            DefaultRetryMode    = RetryMode.AlwaysRetry,
            // Commented this out since Debug actually sends, uh, quite a lot that's not necessary in production
            // but leaving it here in case I (or someone else) get[s] confused about why logging isn't working again :p
            // LogLevel = LogSeverity.Debug // We filter log levels in Serilog, so just pass everything through (Debug is lower than Verbose)
        }))
        .AddSingleton <Bot>()
        .AddTransient <CommandTree>()

        .AddTransient <SystemCommands>()
        .AddTransient <MemberCommands>()
        .AddTransient <SwitchCommands>()
        .AddTransient <LinkCommands>()
        .AddTransient <APICommands>()
        .AddTransient <ImportExportCommands>()
        .AddTransient <HelpCommands>()
        .AddTransient <ModCommands>()
        .AddTransient <MiscCommands>()

        .AddTransient <EmbedService>()
        .AddTransient <ProxyService>()
        .AddTransient <LogChannelService>()
        .AddTransient <DataFileService>()
        .AddTransient <WebhookExecutorService>()

        .AddTransient <ProxyCacheService>()
        .AddSingleton <WebhookCacheService>()

        .AddTransient <IDataStore, PostgresDataStore>()

        .AddSingleton(svc => InitUtils.InitMetrics(svc.GetRequiredService <CoreConfig>()))
        .AddSingleton <PeriodicStatCollector>()

        .AddScoped(_ => new Sentry.Scope(null))
        .AddTransient <PKEventHandler>()

        .AddScoped <EventIdProvider>()
        .AddSingleton(svc => new LoggerProvider(svc.GetRequiredService <CoreConfig>(), "bot"))
        .AddScoped(svc => svc.GetRequiredService <LoggerProvider>().RootLogger.ForContext("EventId", svc.GetRequiredService <EventIdProvider>().EventId))

        .AddMemoryCache()

        .BuildServiceProvider();
Exemplo n.º 8
0
        public ServiceProvider BuildServiceProvider() => new ServiceCollection()
        .AddTransient(_ => _config.GetSection("PluralKit").Get <CoreConfig>() ?? new CoreConfig())
        .AddTransient(_ => _config.GetSection("PluralKit").GetSection("Bot").Get <BotConfig>() ?? new BotConfig())

        .AddSingleton <DbConnectionCountHolder>()
        .AddTransient <DbConnectionFactory>()

        .AddSingleton <IDiscordClient, DiscordShardedClient>(_ => new DiscordShardedClient(new DiscordSocketConfig
        {
            MessageCacheSize    = 5,
            ExclusiveBulkDelete = true,
            DefaultRetryMode    = RetryMode.AlwaysRetry
        }))
        .AddSingleton <Bot>()
        .AddTransient <CommandTree>()

        .AddTransient <SystemCommands>()
        .AddTransient <MemberCommands>()
        .AddTransient <SwitchCommands>()
        .AddTransient <LinkCommands>()
        .AddTransient <APICommands>()
        .AddTransient <ImportExportCommands>()
        .AddTransient <HelpCommands>()
        .AddTransient <ModCommands>()
        .AddTransient <MiscCommands>()

        .AddTransient <EmbedService>()
        .AddTransient <ProxyService>()
        .AddTransient <LogChannelService>()
        .AddTransient <DataFileService>()
        .AddTransient <WebhookExecutorService>()

        .AddTransient <ProxyCacheService>()
        .AddSingleton <WebhookCacheService>()

        .AddTransient <SystemStore>()
        .AddTransient <MemberStore>()
        .AddTransient <MessageStore>()
        .AddTransient <SwitchStore>()

        .AddSingleton(svc => InitUtils.InitMetrics(svc.GetRequiredService <CoreConfig>()))
        .AddSingleton <PeriodicStatCollector>()

        .AddScoped(_ => new Sentry.Scope(null))
        .AddTransient <PKEventHandler>()

        .AddScoped <EventIdProvider>()
        .AddSingleton(svc => new LoggerProvider(svc.GetRequiredService <CoreConfig>(), "bot"))
        .AddScoped(svc => svc.GetRequiredService <LoggerProvider>().RootLogger.ForContext("EventId", svc.GetRequiredService <EventIdProvider>().EventId))

        .AddMemoryCache()

        .BuildServiceProvider();
Exemplo n.º 9
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            InitUtils.Init();

            var config = Configuration.GetSection("PluralKit").Get <CoreConfig>();

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            services
            .AddScoped <IDbConnection, NpgsqlConnection>(_ => new NpgsqlConnection(config.Database))
            .AddTransient <SystemStore>()
            .AddTransient <MemberStore>()
            .AddSingleton(config);
        }
Exemplo n.º 10
0
        private async Task MainAsync()
        {
            ThreadPool.SetMinThreads(32, 32);
            ThreadPool.SetMaxThreads(128, 128);

            Console.WriteLine("Starting PluralKit...");

            InitUtils.Init();

            // Set up a CancellationToken and a SIGINT hook to properly dispose of things when the app is closed
            // The Task.Delay line will throw/exit (forgot which) and the stack and using statements will properly unwind
            var token = new CancellationTokenSource();

            Console.CancelKeyPress += delegate(object e, ConsoleCancelEventArgs args)
            {
                args.Cancel = true;
                token.Cancel();
            };

            using (var services = BuildServiceProvider())
            {
                var logger     = services.GetRequiredService <ILogger>().ForContext <Initialize>();
                var coreConfig = services.GetRequiredService <CoreConfig>();
                var botConfig  = services.GetRequiredService <BotConfig>();
                var schema     = services.GetRequiredService <SchemaService>();

                using (Sentry.SentrySdk.Init(coreConfig.SentryUrl))
                {
                    logger.Information("Connecting to database");
                    await schema.ApplyMigrations();

                    logger.Information("Connecting to Discord");
                    var client = services.GetRequiredService <IDiscordClient>() as DiscordShardedClient;
                    await client.LoginAsync(TokenType.Bot, botConfig.Token);

                    logger.Information("Initializing bot");
                    await services.GetRequiredService <Bot>().Init();

                    await client.StartAsync();

                    try
                    {
                        await Task.Delay(-1, token.Token);
                    }
                    catch (TaskCanceledException) { } // We'll just exit normally
                    logger.Information("Shutting down");
                }
            }
        }
Exemplo n.º 11
0
        static Task Main(string[] args)
        {
            // Load configuration and run global init stuff
            var config = InitUtils.BuildConfiguration(args).Build();

            InitUtils.InitStatic();

            // Set up DI container and modules
            var services = BuildContainer(config);

            return(RunWrapper(services, async ct =>
            {
                var logger = services.Resolve <ILogger>().ForContext <Init>();

                // Initialize Sentry SDK, and make sure it gets dropped at the end
                using var _ = Sentry.SentrySdk.Init(services.Resolve <CoreConfig>().SentryUrl);

                // "Connect to the database" (ie. set off database migrations and ensure state)
                logger.Information("Connecting to database");
                await services.Resolve <IDatabase>().ApplyMigrations();

                // Init the bot instance itself, register handlers and such to the client before beginning to connect
                logger.Information("Initializing bot");
                var bot = services.Resolve <Bot>();
                bot.Init();

                // Install observer for request/responses
                DiscordRequestObserver.Install(services);

                // Start the Discord shards themselves (handlers already set up)
                logger.Information("Connecting to Discord");
                var info = await services.Resolve <DiscordApiClient>().GetGatewayBot();
                await services.Resolve <Cluster>().Start(info);
                logger.Information("Connected! All is good (probably).");

                // Lastly, we just... wait. Everything else is handled in the DiscordClient event loop
                try
                {
                    await Task.Delay(-1, ct);
                }
                catch (TaskCanceledException)
                {
                    // Once the CancellationToken fires, we need to shut stuff down
                    // (generally happens given a SIGINT/SIGKILL/Ctrl-C, see calling wrapper)
                    await bot.Shutdown();
                }
            }));
        }
Exemplo n.º 12
0
    public static async Task Main(string[] args)
    {
        _metrics = AppMetrics.CreateDefaultBuilder()
                   .OutputMetrics.AsPrometheusPlainText()
                   .OutputMetrics.AsPrometheusProtobuf()
                   .Build();

        InitUtils.InitStatic();
        await BuildInfoService.LoadVersion();

        var host   = CreateHostBuilder(args).Build();
        var config = host.Services.GetRequiredService <CoreConfig>();
        await host.Services.GetRequiredService <RedisService>().InitAsync(config);

        await host.RunAsync();
    }
Exemplo n.º 13
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors();
            services.AddMvc(opts => { })
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
            .AddJsonOptions(opts => { opts.SerializerSettings.BuildSerializerSettings(); });

            services
            .AddTransient <IDataStore, PostgresDataStore>()

            .AddSingleton(svc => InitUtils.InitMetrics(svc.GetRequiredService <CoreConfig>(), "API"))

            .AddScoped <TokenAuthService>()

            .AddTransient(_ => Configuration.GetSection("PluralKit").Get <CoreConfig>() ?? new CoreConfig())
            .AddSingleton(svc => InitUtils.InitLogger(svc.GetRequiredService <CoreConfig>(), "api"))

            .AddTransient <DbConnectionCountHolder>()
            .AddTransient <DbConnectionFactory>();
        }
Exemplo n.º 14
0
    private static async Task Main(string[] args)
    {
        // Load configuration and run global init stuff
        var config = InitUtils.BuildConfiguration(args).Build();

        InitUtils.InitStatic();

        await BuildInfoService.LoadVersion();

        var services = BuildContainer(config);

        var cfg = services.Resolve <CoreConfig>();

        if (cfg.UseRedisMetrics)
        {
            await services.Resolve <RedisService>().InitAsync(cfg);
        }

        services.Resolve <TaskHandler>().Run();

        await Task.Delay(-1);
    }
Exemplo n.º 15
0
 public static IHostBuilder CreateHostBuilder(string[] args) =>
 Host.CreateDefaultBuilder(args)
 .ConfigureMetrics(_metrics)
 .UseMetricsWebTracking()
 .UseMetricsEndpoints()
 .UseMetrics(
     options =>
 {
     options.EndpointOptions = endpointsOptions =>
     {
         endpointsOptions.MetricsTextEndpointOutputFormatter = _metrics.OutputMetricsFormatters.OfType <MetricsPrometheusTextOutputFormatter>().First();
         endpointsOptions.MetricsEndpointOutputFormatter     = _metrics.OutputMetricsFormatters.OfType <MetricsPrometheusProtobufOutputFormatter>().First();
     };
 })
 .UseServiceProviderFactory(new AutofacServiceProviderFactory())
 .UseSerilog()
 .ConfigureWebHostDefaults(whb => whb
                           .UseConfiguration(InitUtils.BuildConfiguration(args).Build())
                           .ConfigureKestrel(opts =>
 {
     opts.ListenAnyIP(opts.ApplicationServices.GetRequiredService <ApiConfig>().Port);
 })
                           .UseStartup <Startup>());
Exemplo n.º 16
0
    private static async Task Main(string[] args)
    {
        // Load configuration and run global init stuff
        var config = InitUtils.BuildConfiguration(args).Build();

        InitUtils.InitStatic();

        // init version service
        await BuildInfoService.LoadVersion();

        // Set up DI container and modules
        var services = BuildContainer(config);

        await RunWrapper(services, async ct =>
        {
            var logger = services.Resolve <ILogger>().ForContext <Init>();

            // Initialize Sentry SDK, and make sure it gets dropped at the end

            using var _ = SentrySdk.Init(opts =>
            {
                opts.Dsn                 = services.Resolve <CoreConfig>().SentryUrl;
                opts.Release             = BuildInfoService.FullVersion;
                opts.AutoSessionTracking = true;
                opts.DisableTaskUnobservedTaskExceptionCapture();
            });

            var config     = services.Resolve <BotConfig>();
            var coreConfig = services.Resolve <CoreConfig>();

            // initialize Redis
            var redis = services.Resolve <RedisService>();
            if (config.UseRedisRatelimiter)
            {
                await redis.InitAsync(coreConfig);
            }

            if (config.Cluster == null)
            {
                // "Connect to the database" (ie. set off database migrations and ensure state)
                logger.Information("Connecting to database");
                await services.Resolve <IDatabase>().ApplyMigrations();

                // Clear shard status from Redis
                if (redis.Connection != null)
                {
                    await redis.Connection.GetDatabase().KeyDeleteAsync("pluralkit:shardstatus");
                }
            }

            // Init the bot instance itself, register handlers and such to the client before beginning to connect
            logger.Information("Initializing bot");
            var bot = services.Resolve <Bot>();
            bot.Init();


            // Start the Discord shards themselves (handlers already set up)
            logger.Information("Connecting to Discord");
            await StartCluster(services);
            logger.Information("Connected! All is good (probably).");

            // Lastly, we just... wait. Everything else is handled in the DiscordClient event loop
            try
            {
                await Task.Delay(-1, ct);
            }
            catch (TaskCanceledException)
            {
                // Once the CancellationToken fires, we need to shut stuff down
                // (generally happens given a SIGINT/SIGKILL/Ctrl-C, see calling wrapper)
                await bot.Shutdown();
            }
        });
    }
Exemplo n.º 17
0
        private async Task MainAsync()
        {
            ThreadPool.SetMinThreads(32, 32);
            ThreadPool.SetMaxThreads(128, 128);

            Console.WriteLine("Starting PluralKit...");

            InitUtils.Init();

            // Set up a CancellationToken and a SIGINT hook to properly dispose of things when the app is closed
            // The Task.Delay line will throw/exit (forgot which) and the stack and using statements will properly unwind
            var token = new CancellationTokenSource();

            Console.CancelKeyPress += delegate(object e, ConsoleCancelEventArgs args)
            {
                args.Cancel = true;
                token.Cancel();
            };

            var builder = new ContainerBuilder();

            builder.RegisterInstance(_config);
            builder.RegisterModule(new ConfigModule <BotConfig>("Bot"));
            builder.RegisterModule(new LoggingModule("bot"));
            builder.RegisterModule(new MetricsModule());
            builder.RegisterModule <DataStoreModule>();
            builder.RegisterModule <BotModule>();

            using var services = builder.Build();

            var logger = services.Resolve <ILogger>().ForContext <Initialize>();

            try
            {
                SchemaService.Initialize();

                var coreConfig = services.Resolve <CoreConfig>();
                var botConfig  = services.Resolve <BotConfig>();
                var schema     = services.Resolve <SchemaService>();

                using var _ = Sentry.SentrySdk.Init(coreConfig.SentryUrl);

                logger.Information("Connecting to database");
                await schema.ApplyMigrations();

                logger.Information("Connecting to Discord");
                var client = services.Resolve <DiscordShardedClient>();
                await client.LoginAsync(TokenType.Bot, botConfig.Token);

                logger.Information("Initializing bot");
                await client.StartAsync();

                await services.Resolve <Bot>().Init();

                try
                {
                    await Task.Delay(-1, token.Token);
                }
                catch (TaskCanceledException) { } // We'll just exit normally
            }
            catch (Exception e)
            {
                logger.Fatal(e, "Unrecoverable error while initializing bot");
            }

            logger.Information("Shutting down");
        }
Exemplo n.º 18
0
        static void Main(string[] args) => new Initialize
        {
            _config = InitUtils.BuildConfiguration(args).Build()
        }

        .MainAsync().GetAwaiter().GetResult();
Exemplo n.º 19
0
 public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
 WebHost.CreateDefaultBuilder(args)
 .UseConfiguration(InitUtils.BuildConfiguration(args).Build())
 .ConfigureKestrel(opts => { opts.ListenAnyIP(5000); })
 .UseStartup <Startup>();
Exemplo n.º 20
0
 public static void Main(string[] args)
 {
     InitUtils.Init();
     CreateHostBuilder(args).Build().Run();
 }