Ejemplo n.º 1
0
        /// <summary>
        /// Wrapper for asynchronous entry point.
        /// </summary>
        /// <param name="args">Command-line arguments for the binary.</param>
        internal static void Main(string[] args)
        {
            // pass the execution to the asynchronous entry point
            var async = new AsyncExecutor();

            async.Execute(MainAsync(args));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Asynchronous entry point of the bot's binary.
        /// </summary>
        /// <param name="args">Command-line arguments for the binary.</param>
        /// <returns></returns>
        private static async Task MainAsync(string[] args)
        {
            Console.WriteLine("Loading Companion Cube...");
            Console.Write("[1/4] Loading configuration         ");

            // locate the config file
            var cfgFile = new FileInfo("config.json");

            // load the config file and validate it
            var cfgLoader = new CompanionCubeConfigLoader();

            if (!cfgFile.Exists)
            {
                await cfgLoader.SaveConfigurationAsync(new CompanionCubeConfig(), cfgFile);

                return;
            }
            var cfg = await cfgLoader.LoadConfigurationAsync(cfgFile).ConfigureAwait(false);

            cfgLoader.ValidateConfiguration(cfg);

            Console.Write("\r[2/4] Loading unicode data          ");

            // load unicode data
            using (var utfloader = new UnicodeDataLoader("unicode_data.json.gz"))
                await utfloader.LoadCodepointsAsync().ConfigureAwait(false);

            Console.Write("\r[3/4] Validating PostgreSQL database");

            Console.Write("\r[4/4] Creating and booting shards   ");

            // create shards
            Shards = new Dictionary <int, CompanionCubeBot>();
            var async = new AsyncExecutor();

            for (int i = 0; i < cfg.Discord.ShardCount; i++)
            {
                Shards[i] = new CompanionCubeBot(cfg, i, async);
            }

            // --- LOADING COMPLETED ---
            Console.WriteLine("\rLoading completed, booting the shards");
            Console.WriteLine("-------------------------------------");

            // boot shards
            foreach (var(k, shard) in Shards)
            {
                await shard.StartAsync();
            }

            // do a minimal cleanup
            GC.Collect();

            // wait forever
            await Task.Delay(-1);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Asynchronous entry point of the bot's binary.
        /// </summary>
        /// <param name="args">Command-line arguments for the binary.</param>
        /// <returns></returns>
        private static async Task MainAsync(string[] args)
        {
            Console.WriteLine("Loading Companion Cube...");
            Console.Write("[1/4] Loading configuration         ");

            // locate the config file
            var dockerSecret = Environment.GetEnvironmentVariable("DOCKER_SECRET");
            var cfgFile      = new FileInfo(dockerSecret != null ? Path.Combine("/run/secrets", dockerSecret) : "config.json");

            // load the config file and validate it
            var cfgLoader = new CompanionCubeConfigLoader();
            var cfg       = await cfgLoader.LoadConfigurationAsync(cfgFile);

            cfgLoader.ValidateConfiguration(cfg);

            Console.Write("\r[2/4] Loading unicode data          ");

            // load unicode data
            using (var utfloader = new UnicodeDataLoader("unicode_data.json.gz"))
                await utfloader.LoadCodepointsAsync();

            Console.Write("\r[3/4] Validating PostgreSQL database");

            // create database type mapping
            NpgsqlConnection.GlobalTypeMapper.MapEnum <DatabaseEntityKind>("entity_kind");
            NpgsqlConnection.GlobalTypeMapper.MapEnum <DatabaseTagKind>("tag_kind");

            // create database connection and validate schema
            var dbcsp = new ConnectionStringProvider(cfg.PostgreSQL);

            using (var db = new DatabaseContext(dbcsp))
            {
                var dbv = db.Metadata.SingleOrDefault(x => x.MetaKey == "schema_version");
                if (dbv == null || dbv.MetaValue != "8")
                {
                    throw new InvalidDataException("Database schema version mismatch.");
                }
                dbv = db.Metadata.SingleOrDefault(x => x.MetaKey == "project");
                if (dbv == null || dbv.MetaValue != "Companion Cube")
                {
                    throw new InvalidDataException("Database schema type mismatch.");
                }
            }

            Console.Write("\r[4/4] Creating and booting shards   ");

            // create shards
            Shards = new Dictionary <int, CompanionCubeBot>();
            var async = new AsyncExecutor();

            for (int i = 0; i < cfg.Discord.ShardCount; i++)
            {
                Shards[i] = new CompanionCubeBot(cfg, i, async);
            }

            // --- LOADING COMPLETED ---
            Console.WriteLine("\rLoading completed, booting the shards");
            Console.WriteLine("-------------------------------------");

            // boot shards
            foreach (var(k, shard) in Shards)
            {
                await shard.StartAsync();
            }

            // do a minimal cleanup
            GC.Collect();

            // wait forever
            await Task.Delay(-1);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Creates a new instance of Companion Cube bot shard handler.
        /// </summary>
        /// <param name="cfg">Configuration options for the shard.</param>
        /// <param name="shardId">ID of this shard.</param>
        /// <param name="async">Synchronous executor of asynchronous tasks.</param>
        public CompanionCubeBot(CompanionCubeConfig cfg, int shardId, AsyncExecutor async)
        {
            // assign the properties
            this.ShardId                  = shardId;
            this.BotVersion               = CompanionCubeUtilities.GetBotVersion();
            this.Configuration            = cfg;
            this.ConnectionStringProvider = new ConnectionStringProvider(cfg.PostgreSQL);
            this.AsyncExecutor            = async;

            // create discord client instance
            this.Discord = new DiscordClient(new DiscordConfiguration
            {
                Token      = cfg.Discord.Token,
                TokenType  = TokenType.Bot,
                ShardCount = cfg.Discord.ShardCount,
                ShardId    = this.ShardId,

                AutoReconnect           = true,
                ReconnectIndefinitely   = true,
                GatewayCompressionLevel = GatewayCompressionLevel.Stream,
                LargeThreshold          = 250,

                UseInternalLogHandler = false,
                LogLevel = LogLevel.Info
            });

            // attach log handler
            this.Discord.DebugLogger.LogMessageReceived += this.DebugLogger_LogMessageReceived;

            // attach event handlers
            this.Discord.Ready += this.Discord_Ready;
            this.Discord.GuildDownloadCompleted += this.Discord_GuildDownloadCompleted;
            this.Discord.ClientErrored          += this.Discord_ClientErrored;
            this.Discord.SocketErrored          += this.Discord_SocketErrored;
            this.Discord.GuildAvailable         += this.Discord_GuildAvailable;
            this.Discord.VoiceStateUpdated      += this.Discord_VoiceStateUpdated;

            // create service provider
            this.Services = new ServiceCollection()
                            .AddTransient <CSPRNG>()
                            .AddSingleton(this.ConnectionStringProvider)
                            .AddSingleton <MusicService>()
                            .AddScoped <DatabaseContext>()
                            .AddSingleton(new LavalinkService(cfg.Lavalink, this.Discord))
                            .AddSingleton(new YouTubeSearchProvider(cfg.YouTube))
                            .AddSingleton <HttpClient>()
                            .AddSingleton(this)
                            .BuildServiceProvider(true);

            // create CommandsNext
            this.CommandsNext = this.Discord.UseCommandsNext(new CommandsNextConfiguration
            {
                CaseSensitive        = false,
                EnableDms            = false,
                IgnoreExtraArguments = false,

                EnableDefaultHelp = true,
                DefaultHelpChecks = new[] { new NotBlacklistedAttribute() },

                EnableMentionPrefix = cfg.Discord.EnableMentionPrefix,
                PrefixResolver      = this.ResolvePrefixAsync,

                Services = this.Services
            });

            // set help formatter
            this.CommandsNext.SetHelpFormatter <CompanionCubeHelpFormatter>();

            // register type converters
            this.CommandsNext.RegisterConverter(new TagTypeConverter());
            this.CommandsNext.RegisterUserFriendlyTypeName <TagType>("tag type");

            // attach event handlers
            this.CommandsNext.CommandExecuted += this.CommandsNext_CommandExecuted;
            this.CommandsNext.CommandErrored  += this.CommandsNext_CommandErrored;

            // create commands
            this.CommandsNext.RegisterCommands(Assembly.GetExecutingAssembly());

            // create interactivity
            this.Interactivity = this.Discord.UseInteractivity(new InteractivityConfiguration
            {
                Timeout = TimeSpan.FromSeconds(30)
            });

            // create lavalink
            this.Lavalink = this.Discord.UseLavalink();
        }