Exemplo n.º 1
0
        public ICompileResult CreateModules(Snowflake id, string code)
        {
            Logger.LogInformation("Compiling module code...");
            var sw     = Stopwatch.StartNew();
            var result = CompileUtils.CompileCommandModule(id.ToString(), code);

            sw.Stop();
            Logger.LogInformation("Finished compiling module code in {0}ms.", sw.ElapsedMilliseconds);

            if (result is SuccessfulCompileResult successfulResult)
            {
                var context = successfulResult.AssemblyLoadContext;
                if (context.Assemblies.Count() != 1)
                {
                    throw new Exception("Assemblies loaded in load context is not equal to 1.  This should not happen.");
                }

                var assembly = context.Assemblies.First();


                var modules = _commandService.AddModules(assembly);
                Logger.LogInformation("Added {0} module(s).", modules.Count);

                _loadedModules.Add(id, new CommandModuleLoadContext(context, modules));
            }

            return(result);
        }
Exemplo n.º 2
0
        private void LoadCommands()
        {
            _prefixes.Add(_config.Prefix);
            if (_config.AllowMentionPrefix)
            {
                _prefixes.Add($"<@{discordClient.CurrentUser.Id}>");
                _prefixes.Add($"<@!{discordClient.CurrentUser.Id}>");
            }

            _logger.LogInformation($"Using {_prefixes.Count} prefix{(_prefixes.Count > 1 ? "es" : "")}; {string.Join(", ", _prefixes)}.");

            _commands.AddTypeParser(new SocketUserParser <SocketUser>());
            _commands.AddTypeParser(new SocketUserParser <SocketGuildUser>());
            _commands.AddTypeParser(new SocketGuildChannelParser <SocketGuildChannel>());
            _commands.AddTypeParser(new SocketGuildChannelParser <SocketTextChannel>());
            _commands.AddTypeParser(new SocketGuildChannelParser <SocketCategoryChannel>());
            _commands.AddTypeParser(new SocketGuildChannelParser <SocketVoiceChannel>());
            _commands.AddTypeParser(new SocketRoleParser());
            _commands.AddTypeParser(new CaseParser());
            _commands.AddTypeParser(new TimeSpanParser());
            _commands.AddTypeParser(new BanParser());


            _commands.AddModules(Assembly.GetEntryAssembly(), action: m =>
            {
            });
        }
Exemplo n.º 3
0
        private IReadOnlyList <(Plugin Plugin, int ModuleCount, int CommandCount)> AddPluginCommands()
        {
            void MutateModule(ModuleBuilder moduleBuilder)
            {
                var methods = moduleBuilder.Type.GetMethods(BindingFlags.Static | BindingFlags.Public);
                var method  = methods.FirstOrDefault(x => x.GetCustomAttribute <MutateModuleAttribute>() != null);

                if (method == null)
                {
                    return;
                }

                method.Invoke(null, new object[] { moduleBuilder });
            }

            var addedCommands = new List <(Plugin, int, int)>();

            foreach (var plugin in Plugins)
            {
                var addedModules = _commandService.AddModules(plugin.Assembly, action: MutateModule);
                addedCommands.Add((plugin, addedModules.Count, addedModules.SelectMany(CommandUtilities.EnumerateAllCommands).Count()));
            }

            return(addedCommands);
        }
Exemplo n.º 4
0
        public async Task InitializeAsync()
        {
            var clientConfig = new DiscordSocketConfig()
            {
                AlwaysDownloadUsers = true,
                DefaultRetryMode    = RetryMode.Retry502,
                MessageCacheSize    = 50,
                LogLevel            = LogSeverity.Info
            };

            var commandConfig = new CommandServiceConfiguration()
            {
                DefaultRunMode        = RunMode.Parallel,
                StringComparison      = StringComparison.OrdinalIgnoreCase,
                IgnoresExtraArguments = true
            };

            Client         = new DiscordShardedClient(clientConfig);
            CommandService = new CommandService(commandConfig);
            Config         = MakeConfig();
            ScrapClient    = new ScrapClient(Config["scrapApi"]);
            Provider       = MakeProvider();
            Logger         = Provider.GetRequiredService <LoggerService>();

            CommandService.AddModules(Assembly.GetEntryAssembly());
            InitializeTypeParsers();

            await InitializeServicesAsync();
        }
Exemplo n.º 5
0
        public BotStartup(IServiceProvider services)
        {
            Services       = services;
            DiscordClient  = services.GetRequiredService <DiscordClient>();
            CommandService = services.GetRequiredService <CommandService>();

            CommandService.AddModules(services.GetRequiredService <Assembly>());
            DiscordClient.MemberJoined += DiscordClient_UserJoined;
        }
Exemplo n.º 6
0
        async Task ICommandHandler.Initialize(ISlackConnection connection)
        {
            _connection = connection;
            _connection.OnMessageReceived += MessageReceived;

            _commandService.AddModules(Assembly.GetEntryAssembly());
            _commandService.CommandErrored += CommandServiceOnCommandErrored;

            await Task.CompletedTask;
        }
Exemplo n.º 7
0
        public void Initialize()
        {
            IServiceCollection services = new ServiceCollection();

            Provider = ConfigureServices(services);

            Commands = Provider.GetRequiredService <CommandService>();
            Commands.AddModules(Assembly.GetEntryAssembly()); //Add Modules to the CommandService

            Client = Provider.GetRequiredService <DiscordSocketClient>();
        }
Exemplo n.º 8
0
        public async Task InitializeAsync()
        {
            _service.AddTypeParsers();
            var sw     = Stopwatch.StartNew();
            var loaded = _service.AddModules(Assembly.GetEntryAssembly());

            sw.Stop();
            await _logger.Log(LogSeverity.Info, LogSource.DepressedBot,
                              $"Loaded {loaded.Count} modules and {loaded.Sum(m => m.Commands.Count)} commands loaded in {sw.ElapsedMilliseconds}ms.");

            _client.Log += async(m) => await _logger.Log(new LogEventArgs(m));

            _client.Ready += async() => await OnReady(new ReadyEventArgs(_client));

            _client.MessageReceived += async(s) =>
            {
                if (!(s is SocketUserMessage msg))
                {
                    return;
                }
                if (msg.Author.IsBot)
                {
                    return;
                }
                if (msg.Channel is IDMChannel dm)
                {
                    if (msg.Content.StartsWith($"{Config.CommandPrefix}confess", StringComparison.OrdinalIgnoreCase))
                    {
                        return;
                    }
                    await dm.SendMessageAsync("I do not support commands via DM.");

                    return;
                }

                var args = new MessageReceivedEventArgs(msg);
                await HandleMessageReceivedAsync(args);
            };
            _client.MessageReceived += async(s) =>
            {
                if (!(s is SocketUserMessage msg))
                {
                    return;
                }
                if (msg.Author.IsBot)
                {
                    return;
                }
                await _confessional.HandleMessageAsync(new DepressedBotContext(_client, msg, _provider));
            };
        }
Exemplo n.º 9
0
        public async Task InitializeAsync()
        {
            await _client.LoginAsync(TokenType.Bot, (await _database.BotConfigs.AsNoTracking().FirstAsync()).BotToken);

            await _client.StartAsync();

            _commands.AddModules(Assembly.GetEntryAssembly());

            _events.Initialize();
            _reaction.Initialize();
            _jobs.Initialize();

            await Task.Delay(-1);
        }
Exemplo n.º 10
0
        public async Task InitializeAsync(IServiceProvider provider)
        {
            var sw = Stopwatch.StartNew();
            var l  = await _service.AddTypeParsersAsync();

            sw.Stop();
            _logger.Info(LogSource.Volte, $"Loaded TypeParsers: [{l.Select(x => x.SanitizeParserName()).Join(", ")}] in {sw.ElapsedMilliseconds}ms.");
            sw = Stopwatch.StartNew();

            var loaded = _service.AddModules(GetType().Assembly);

            sw.Stop();
            _logger.Info(LogSource.Volte,
                         $"Loaded {loaded.Count} modules and {loaded.Sum(m => m.Commands.Count)} commands loaded in {sw.ElapsedMilliseconds}ms.");
            await _client.RegisterVolteEventHandlersAsync(provider);
        }
Exemplo n.º 11
0
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            var assembly = Assembly.GetEntryAssembly();

            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.UtcNow);
                _command.AddModules(assembly);
                _provider.GetRequiredService <CommandHandling>();
                _provider.GetRequiredService <LogService>();
                await _client.LoginAsync(TokenType.Bot, _config["Token"]);

                await _client.StartAsync();

                await Task.Delay(-1, stoppingToken);
            }
        }
Exemplo n.º 12
0
        public void Initialize()
        {
            _commands.AddModules(Assembly.GetEntryAssembly());

            _client.MessageCreated += OnMessageReceivedAsync;

            _commands.CommandExecuted += OnCommandExecuted;
            _commands.CommandErrored  += OnCommandErrored;

            _commands.AddTypeParser(new DiscordMemberTypeParser());
            _commands.AddTypeParser(new DiscordGuildTypeParser());
            _commands.AddTypeParser(new DiscordUserTypeParser());
            _commands.AddTypeParser(new DiscordChannelTypeParser());
            _commands.AddTypeParser(new DiscordRoleTypeParser());
            _commands.AddTypeParser(new SkeletonUserTypeParser());
            _commands.AddTypeParser(new UriTypeParser());
            _commands.AddTypeParser(new TimeSpanTypeParser());
            _commands.AddTypeParser(new RegionTypeParser());
        }
Exemplo n.º 13
0
        private void LoadCommands()
        {
            var sw          = Stopwatch.StartNew();
            var modulesInfo = JObject.Parse(File.ReadAllText(_commandsPath))
                              .SelectToken("modules")?
                              .ToObject <List <ModuleInfo> >();

            if (modulesInfo is null)
            {
                throw new KeyNotFoundException("The modules node array couldn't be loaded");
            }

            var assembly = Assembly.GetAssembly(typeof(Rias));

            _commandService.AddModules(assembly, null, module => SetUpModule(module, modulesInfo));

            sw.Stop();
            Log.Information($"Commands loaded: {sw.ElapsedMilliseconds} ms");
        }
Exemplo n.º 14
0
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Service starting up");

            #warning If your commands are in a different assembly, you should edit this line appropriately.
            var modules = _commands.AddModules(Assembly.GetEntryAssembly());

            _logger.LogInformation("Registered {0} commands in {1} modules",
                                   _commands.GetAllCommands().Count,
                                   modules.Count);

            _logger.LogInformation("Connecting the Discord client");

            #warning Ensure that this configuration variable is set.
            await _client.LoginAsync(TokenType.Bot, _config["token"], true);

            await _client.StartAsync();

            _logger.LogInformation("Client started up successfully");
        }
Exemplo n.º 15
0
        private async Task RunAsync(StatsContext stats)
        {
            _stats    = stats;
            _client   = new DiscordSocketClient();
            _commands = new CommandService();
            await _commands.AddModules(Assembly.GetEntryAssembly());

            _map = new DependencyMap();
            _map.Add(_client);
            _map.Add(_stats);

            _client.MessageReceived += HandleCommand;
            _client.MessageReceived += HandleMessage;

            Console.WriteLine("Logging in...");
            await _client.LoginAsync(TokenType.Bot, config["Token"]);

            await _client.ConnectAsync();

            Console.WriteLine("Bot is ready.");
            await Task.Delay(-1);
        }
Exemplo n.º 16
0
        public async Task InitializeAsync()
        {
            var commandConfig = new CommandServiceConfiguration()
            {
                DefaultRunMode        = RunMode.Parallel,
                StringComparison      = StringComparison.OrdinalIgnoreCase,
                IgnoresExtraArguments = true
            };


            CommandService = new CommandService(commandConfig);
            Config         = MakeConfig();
            Client         = new TelegramBotClient(Config["tokens:telegram"])
            {
                Timeout = TimeSpan.FromSeconds(20),
            };
            Provider = MakeProvider();

            await InitializeServicesAsync();

            CommandService.AddModules(Assembly.GetEntryAssembly());
            InitializeTypeParsers();
        }
Exemplo n.º 17
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // API/Website Config
            services.AddControllers();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo
                {
                    Title       = "Faforever.Qai",
                    Version     = "v1",
                    Description = "The API for the Faforever.Qai and Dostya bots."
                });
            });

            // Bot Services Config
            DatabaseConfiguration dbConfig = new()
            {
                DataSource = $"Data Source={Configuration["Config:DataSource"]}"
            };

#if DEBUG
            // For use when the DB is Database/db-name.db
            if (!Directory.Exists("Database"))
            {
                Directory.CreateDirectory("Database");
            }
#endif

            string json         = File.ReadAllText(Path.Join("Config", "games_config.json"));
            var    botFunConfig = JsonConvert.DeserializeObject <BotFunConfiguration>(json);

            json = File.ReadAllText(Path.Join("Config", "url_config.json"));
            var urlConfig = JsonConvert.DeserializeObject <UrlConfiguration>(json);

            TwitchClientConfig twitchCfg = new()
            {
                ClientId     = Configuration["Config:TwitchClientId"],
                ClientSecret = Environment.GetEnvironmentVariable("TWITCH_CLIENT_SECRET")
            };

            services.AddLogging(options => options.AddConsole())
            .AddDbContext <QAIDatabaseModel>(options =>
            {
                options.UseSqlite(dbConfig.DataSource);
            }, ServiceLifetime.Singleton, ServiceLifetime.Singleton)
            .AddSingleton <RelayService>()
            // Command Service Registration
            .AddSingleton((x) =>
            {
                var options = new CommandService(new CommandServiceConfiguration()
                {
                    // Additional configuration for the command service goes here.
                });

                // Command modules go here.
                options.AddModules(System.Reflection.Assembly.GetAssembly(typeof(CustomCommandContext)));
                // Argument converters go here.
                options.AddTypeParser(new DiscordChannelTypeConverter());
                options.AddTypeParser(new DiscordRoleTypeConverter());
                options.AddTypeParser(new BotUserCapsuleConverter());
                options.AddTypeParser(new DiscordMemberConverter());
                options.AddTypeParser(new DiscordUserConverter());
                return(options);
            })
            .AddSingleton <QCommandsHandler>()
            .AddSingleton(typeof(TwitchClientConfig), twitchCfg)
            // Operation Service Registration
            .AddSingleton <IBotFunService>(new BotFunService(botFunConfig))
            .AddSingleton <IUrlService>(new UrlService(urlConfig))
            .AddSingleton <DiscordEventHandler>()
            .AddSingleton <AccountLinkService>()
            .AddTransient <IFetchPlayerStatsOperation, ApiFetchPlayerStatsOperation>()
            .AddTransient <IFindPlayerOperation, ApiFindPlayerOperation>()
            .AddTransient <ISearchUnitDatabaseOperation, UnitDbSearchUnitDatabaseOpeartion>()
            .AddTransient <IPlayerService, OperationPlayerService>()
            .AddTransient <GameService>()
            .AddTransient <ISearchMapOperation, ApiSearchMapOperation>()
            .AddTransient <IFetchLadderPoolOperation, ApiFetchLadderPoolOperation>()
            .AddTransient <IFetchReplayOperation, ApiFetchReplayOperation>()
            .AddTransient <IFetchClanOperation, ApiFetchClanOperation>()
            .AddTransient <IFetchTwitchStreamsOperation, FetchTwitchStreamsOperation>()
            .AddTransient <FafApiClient>();



            // HTTP Client Mapping
            services.AddHttpClient <ApiHttpClient>(client =>
            {
                client.BaseAddress = ApiUri;
            });

            services.AddHttpClient <UnitClient>(client =>
            {
                client.BaseAddress = new Uri(UnitDbUtils.UnitApi);
            });

            services.AddHttpClient <TwitchClient>();
            // Discord Information Setup
            DiscordBotConfiguration discordConfig = new()
            {
                Prefix = Configuration["Config:BotPrefix"],
                Shards = 1,
                Token  = Environment.GetEnvironmentVariable("DISCORD_TOKEN")
            };

            var dcfg = new DiscordConfiguration
            {
                Token           = discordConfig.Token,
                TokenType       = TokenType.Bot,
                MinimumLogLevel = LogLevel.Debug,
                ShardCount      = discordConfig.Shards, // Default to 1 for automatic sharding.
                Intents         = DiscordIntents.Guilds | DiscordIntents.GuildMessages | DiscordIntents.DirectMessages,
            };

            services.AddSingleton(discordConfig)
            .AddSingleton <DiscordShardedClient>(x =>
            {
                return(new(dcfg));
            })
            .AddSingleton <DiscordRestClient>(x =>
            {
                return(new(dcfg));
            })
            .AddSingleton <DiscordBot>();

            // IRC Information Setup
            var user = Configuration["Config:Irc:User"];
            var pass = Environment.GetEnvironmentVariable("IRC_PASS");
            IrcConfiguration ircConfig = new()
            {
                Connection = Configuration["Config:Irc:Connection"],
                Channels   = Configuration["Config:Irc:Channels"].Split(',').Select(s => s.Trim()).ToArray(),
                UserName   = user,
                NickName   = user,
                RealName   = user,
                Password   = pass
            };

            var ircConnInfo = new IrcUserRegistrationInfo
            {
                NickName = ircConfig.NickName,
                RealName = ircConfig.RealName,
                Password = ircConfig.Password,
                UserName = ircConfig.UserName
            };

            services.AddSingleton(ircConfig)
            .AddSingleton(ircConnInfo as IrcRegistrationInfo)
            .AddSingleton <QaIrc>();

            // Setup the OAuth2 settings
            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultSignInScheme       = CookieAuthenticationDefaults.AuthenticationScheme;

                options.DefaultChallengeScheme = "FAF";
            })
            .AddCookie()
            .AddOAuth("FAF", options =>
            {
                options.AuthorizationEndpoint = $"{ApiUri}oauth/authorize";                // FAF API Endpoint.

                options.CallbackPath     = new PathString("/authorization-code/callback"); // local auth endpoint
                options.AccessDeniedPath = new PathString("/api/link/denied");

                // Other FAF OAtuh configuration settings
                options.ClientId      = Configuration["Config:Faf:ClientId"];
                options.ClientSecret  = Environment.GetEnvironmentVariable("FAF_CLIENT_SECRET");
                options.TokenEndpoint = $"{ApiUri}oauth/token";

                options.Scope.Add("public_profile");

                options.Events = new OAuthEvents
                {
                    OnCreatingTicket = async context =>
                    {
                        // Get the FAF user information
                        var req = new HttpRequestMessage(HttpMethod.Get, $"{ApiUri}me");

                        req.Headers.Authorization = new("Bearer", context.AccessToken);

                        var res = await context.Backchannel.SendAsync(req);

                        if (res.IsSuccessStatusCode)
                        {     // if the request is valid, get the JSON data from it
                            var rawJson = await res.Content.ReadAsStreamAsync();

                            var faf = await System.Text.Json.JsonSerializer.DeserializeAsync <FafUser>(rawJson);

                            if (context.Request.Cookies.TryGetValue("token", out var token))
                            {
                                var link = context.HttpContext.RequestServices.GetRequiredService <AccountLinkService>();

                                try
                                {     // bind the information to the link with the token from the cookies
                                    link.BindFafUser(token, faf.Data.Attributes.UserId, faf.Data.Attributes.UserName);
                                }
                                catch (Exception ex)
                                {
                                    context.Response.Cookies.Append("error", ex.Message);
                                }

                                context.Success();
                            }
                            else
                            {
                                context.Response.Cookies.Append("error", "No token found.");
                            }
                        }
                        else
                        {
                            context.Response.Cookies.Append("error", "Failed to get user information from access token");
                        }
                    },
                    OnRemoteFailure = context =>
                    {
                        // TODO remove token from cookies and delete server token cache.
                        Console.WriteLine(context.Failure.Message);

                        return(Task.CompletedTask);
                    }
                };
            })
            // OAuth2 setup for authenticating with Discord.
            .AddOAuth("DISCORD", options =>
            {
                options.AuthorizationEndpoint = $"{Configuration["Config:Discord:Api"]}/oauth2/authorize";

                options.CallbackPath     = new PathString("/authorization-code/discord-callback"); // local auth endpoint
                options.AccessDeniedPath = new PathString("/api/link/denied");

                options.ClientId      = Configuration["Config:Discord:ClientId"];
                options.ClientSecret  = Environment.GetEnvironmentVariable("DISCORD_CLIENT_SECRET");
                options.TokenEndpoint = $"{Configuration["Config:Discord:TokenEndpoint"]}";

                options.Scope.Add("identify");

                options.Events = new OAuthEvents
                {
                    OnCreatingTicket = async context =>
                    {
                        // get user data
                        var client = new DiscordRestClient(new()
                        {
                            Token     = context.AccessToken,
                            TokenType = TokenType.Bearer
                        });

                        var user = await client.GetCurrentUserAsync();

                        if (context.Request.Cookies.TryGetValue("token", out var token))
                        {
                            var link = context.HttpContext.RequestServices.GetRequiredService <AccountLinkService>();

                            try
                            {     // verify the user information grabbed matches the user info
                                  // saved from the inital command
                                if (!link.VerifyDiscord(token, user.Id))
                                {
                                    context.Response.Cookies.Append("error", "Discord ID used for sign in did not match Discord ID from the Discord Application.");
                                }
                            }
                            catch (Exception ex)
                            {
                                context.Response.Cookies.Append("error", ex.Message);
                            }

                            context.Success();
                        }
                        else
                        {
                            context.Response.Cookies.Append("error", "No token found.");
                        }
                    },
                    OnRemoteFailure = context =>
                    {
                        // TODO remove token from cookies and delete server token cache.

                        return(Task.CompletedTask);
                    }
                };
            });
        }
Exemplo n.º 18
0
        private static void Main(string[] args)
        {
            var configuration = new ConfigurationBuilder()
                                .AddCommandLine(args)
                                .Build();

            if (configuration.GetSection("GenerateMarkdown").Exists())
            {
                var service = new CommandService();
                service.AddModules(typeof(CharacterMainCommands).Assembly);
                GenerateCommandMarkdown(service);
                return;
            }

            using var host = new HostBuilder()
                             .ConfigureAppConfiguration(x =>
            {
                x.AddEnvironmentVariables("SHINE_");
            })
                             .ConfigureLogging(x =>
            {
                var logger = new LoggerConfiguration()
                             .MinimumLevel.Override("Microsoft", LogEventLevel.Error)
                             .WriteTo.Console(
                    outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}")
                             .WriteTo.File("Logs/log_.txt",
                                           outputTemplate: "{Timestamp:HH:mm:ss} [{Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}",
                                           rollingInterval: RollingInterval.Day)
                             .CreateLogger();

                x.AddSerilog(logger, true);

                x.Services.Remove(x.Services.First(y => y.ServiceType == typeof(ILogger <>)));
                x.Services.AddSingleton(typeof(ILogger <>), typeof(DummyLogger <>));
            })
                             .ConfigureServices((context, services) =>
            {
                services.AddSingleton <Random>();
                services.AddSingleton <HttpClient>();
                services.AddDbContext <ShineDbContext>(options =>
                {
                    var connectionString = context.Configuration["DB_CONNECTION_STRING"];
                    options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
                });
            })
                             .ConfigureDiscordBot((context, bot) =>
            {
                bot.Token    = context.Configuration["TOKEN"];
                bot.OwnerIds = new Snowflake[]
                {
                    167452465317281793,
                    114926832440180738,
                    176081685702639616
                };
                bot.Prefixes   = new[] { PREFIX };
                bot.Activities = new[]
                {
                    new LocalActivity(PREFIX, ActivityType.Playing)
                };
            })
                             .Build();

            host.Run();
        }
Exemplo n.º 19
0
        public async Task RunBotAsync()
        {
            var config = new Config("./config.json");

            var clashClient = new ClashClient(new ClashClientConfig
            {
                Token = config.ClashToken
            });

            var bandClient = new BandClient(new BandClientConfig
            {
                Token = config.BandToken
            });

            var asm = Assembly.GetEntryAssembly();

            _services = new ServiceCollection()
                        .AddSingleton(_client = new DiscordSocketClient(new DiscordSocketConfig
            {
                LogLevel            = LogSeverity.Verbose,
                AlwaysDownloadUsers = true,
                MessageCacheSize    = 100
            }))
                        .AddSingleton(_commands = new CommandService(new CommandServiceConfiguration
            {
                StringComparison = StringComparison.InvariantCultureIgnoreCase
            })
                                                  .AddTypeParsers(asm))
                        .AddSingleton(clashClient)
                        .AddSingleton(bandClient)
                        .AddSingleton <TaskQueue>()
                        .AddServices(asm.FindTypesWithAttribute <ServiceAttribute>())
                        .BuildServiceProvider();

            var tcs = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously);

            Task OnReadyAsync()
            {
                tcs.SetResult(true);
                _client.Ready -= OnReadyAsync;
                return(Task.CompletedTask);
            }

            _client.Ready += OnReadyAsync;

            _client.UserJoined += user =>
            {
                Task.Run(async() =>
                {
                    var guild  = _services.GetService <DatabaseService>().Guild;
                    var dGuild = _client.GetGuild(guild.Id);

                    var channel = dGuild.GetTextChannel(guild.WelcomeChannelId);
                    var role    = dGuild.GetRole(guild.NotVerifiedRoleId);

                    await user.AddRoleAsync(role);

                    var builder = new EmbedBuilder
                    {
                        Color        = new Color(0x11f711),
                        ThumbnailUrl = dGuild.CurrentUser.GetAvatarUrl(),
                        Title        = "Welcome to the Discord!",
                        Description  = $"{user.GetDisplayName()} welcome to Reddit Rise!\nHere are some premade, perfect FWA bases. Please click the link that corresponds to your TH.\n" +
                                       $"{Format.Url("TH12", "https://link.clashofclans.com/en?action=OpenLayout&id=TH12%3AWB%3AAAAAHQAAAAFw3gmOJJOUocokY9SNAt9V")}\n" +
                                       $"{Format.Url("TH11", "https://link.clashofclans.com/en?action=OpenLayout&id=TH11%3AWB%3AAAAAOwAAAAE4a6sCQApcIa9kDl5W1N3C")}\n" +
                                       $"{Format.Url("TH10", "https://link.clashofclans.com/en?action=OpenLayout&id=TH10%3AWB%3AAAAAFgAAAAF-L9A_pnLR3BtoRk7SZjD_")}\n" +
                                       $"{Format.Url("TH9", "https://link.clashofclans.com/en?action=OpenLayout&id=TH9%3AWB%3AAAAAHQAAAAFw3chc3wBw2ipMxGm6Mq8P")}\n" +
                                       "and if you're feeling nice post your in game player tag (e.g. #YRQ2Y0UC) so we know who you are!"
                    };

                    await channel.SendMessageAsync(user.Mention, embed: builder.Build());
                });
                return(Task.CompletedTask);
            };

            var logger = _services.GetService <LogService>();

            _client.Log += message =>
            {
                var(source, severity, lMessage, exception) = LogFactory.FromDiscord(message);
                return(logger.LogAsync(source, severity, lMessage, exception));
            };

            //TODO do this properly
            _client.UserLeft += (user) =>
            {
                var channel = _client.GetChannel(533650294509404181) as SocketTextChannel;
                return(channel.SendMessageAsync($"{user.GetDisplayName()} left"));
            };

            clashClient.Log   += message => logger.LogAsync(Source.Clash, Severity.Verbose, message);
            clashClient.Error += error => logger.LogAsync(Source.Clash, Severity.Error, error.Message);

            bandClient.Log   += message => logger.LogAsync(Source.Band, Severity.Verbose, message);
            bandClient.Error += error => logger.LogAsync(Source.Band, Severity.Error, error.Message);

            await _client.LoginAsync(TokenType.Bot, config.BotToken);

            await _client.StartAsync();

            _commands.AddModules(Assembly.GetEntryAssembly());

            await tcs.Task;

            _services.GetService <MessageService>();

            //Task.Run(() => _services.GetService<BigBrotherService>().RunServiceAsync());

#if !DEBUG
            Task.Run(() => _services.GetService <WarReminderService>().StartRemindersAsync());
            Task.Run(() => _services.GetService <WarReminderService>().StartPollingServiceAsync());
            Task.Run(() => _services.GetService <StartTimeService>().StartServiceAsync());
#endif

            await Task.Delay(-1);
        }