コード例 #1
0
 /// <summary>
 /// Constructs a new <see cref="CommandListeningBehavior"/>, with the given dependencies.
 /// </summary>
 public CommandListeningBehavior(
     IServiceProvider serviceProvider,
     CommandService commandService,
     CommandErrorHandler commandErrorHandler,
     IDiscordClient discordClient,
     IAuthorizationService authorizationService)
 {
     ServiceProvider      = serviceProvider;
     CommandService       = commandService;
     CommandErrorHandler  = commandErrorHandler;
     DiscordClient        = discordClient;
     AuthorizationService = authorizationService;
 }
コード例 #2
0
 /// <summary>
 /// Constructs a new <see cref="CommandListeningBehavior"/>, with the given dependencies.
 /// </summary>
 public CommandListeningBehavior(
     ICommandPrefixParser commandPrefixParser,
     IServiceProvider serviceProvider,
     CommandService commandService,
     CommandErrorHandler commandErrorHandler,
     IDiscordClient discordClient,
     IAuthorizationService authorizationService,
     IDogStatsd stats = null)
 {
     _commandPrefixParser = commandPrefixParser;
     ServiceProvider      = serviceProvider;
     CommandService       = commandService;
     CommandErrorHandler  = commandErrorHandler;
     DiscordClient        = discordClient;
     AuthorizationService = authorizationService;
     _stats = stats;
 }
コード例 #3
0
 public ModixBot(
     DiscordSocketClient discordClient,
     DiscordRestClient restClient,
     IOptions <ModixConfig> modixConfig,
     CommandService commandService,
     DiscordSerilogAdapter serilogAdapter,
     IApplicationLifetime applicationLifetime,
     IServiceProvider serviceProvider,
     ILogger <ModixBot> logger,
     CommandErrorHandler commandErrorHandler)
 {
     _client              = discordClient ?? throw new ArgumentNullException(nameof(discordClient));
     _restClient          = restClient ?? throw new ArgumentNullException(nameof(restClient));
     _config              = modixConfig?.Value ?? throw new ArgumentNullException(nameof(modixConfig));
     _commands            = commandService ?? throw new ArgumentNullException(nameof(commandService));
     _provider            = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
     _serilogAdapter      = serilogAdapter ?? throw new ArgumentNullException(nameof(serilogAdapter));
     _applicationLifetime = applicationLifetime ?? throw new ArgumentNullException(nameof(applicationLifetime));
     Log = logger ?? throw new ArgumentNullException(nameof(logger));
     _commandErrorHandler = commandErrorHandler;
 }
コード例 #4
0
        /// <inheritdoc />
        public async Task HandleNotificationAsync(MessageReceivedNotification notification, CancellationToken cancellationToken = default)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            if (!(notification.Message is IUserMessage userMessage) ||
                (userMessage.Author is null))
            {
                return;
            }

            if (!(userMessage.Author is IGuildUser author) ||
                (author.Guild is null) ||
                author.IsBot ||
                author.IsWebhook)
            {
                return;
            }

            var argPos = 0;

            if (!userMessage.HasCharPrefix('!', ref argPos) && !userMessage.HasMentionPrefix(DiscordClient.CurrentUser, ref argPos))
            {
                return;
            }

            if (userMessage.Content.Length <= 1)
            {
                return;
            }

            var commandContext = new CommandContext(DiscordClient, userMessage);

            await AuthorizationService.OnAuthenticatedAsync(author);

            IResult commandResult = null;
            var     commandTimer  = Stopwatch.StartNew();

            try
            {
                commandResult = await CommandService.ExecuteAsync(commandContext, argPos, ServiceProvider);
            }
            finally
            {
                commandTimer.Stop();
                var duration = commandTimer.ElapsedMilliseconds;

                if (!(_stats is null) && (commandResult.IsSuccess || !string.Equals(commandResult.ErrorReason, "UnknownCommand", StringComparison.OrdinalIgnoreCase)))
                {
                    var commandInfo = CommandService.Search(commandContext, argPos).Commands.FirstOrDefault();
                    var name        = commandInfo.Command?.Name.ToLowerInvariant();

                    _stats?.Timer("command_duration_ms", duration,
                                  tags: new[] { $"guild:{commandContext.Guild.Name}", $"success:{commandResult.IsSuccess}", $"command:{name}" });
                }
            }

            if (!commandResult.IsSuccess)
            {
                var error = $"{commandResult.Error}: {commandResult.ErrorReason}";

                if (string.Equals(commandResult.ErrorReason, "UnknownCommand", StringComparison.OrdinalIgnoreCase))
                {
                    Log.Error(error);
                }
                else
                {
                    Log.Warning(error);
                }

                if (commandResult.Error == CommandError.Exception)
                {
                    await commandContext.Channel.SendMessageAsync($"Error: {FormatUtilities.SanitizeEveryone(commandResult.ErrorReason)}");
                }
                else
                {
                    await CommandErrorHandler.AssociateError(userMessage, error);
                }
            }

            stopwatch.Stop();
            Log.Information($"Command took {stopwatch.ElapsedMilliseconds}ms to process: {commandContext.Message}");
        }
コード例 #5
0
        /// <inheritdoc />
        public async Task HandleNotificationAsync(MessageReceivedNotification notification, CancellationToken cancellationToken = default)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            if (!(notification.Message is IUserMessage userMessage) ||
                (userMessage.Author is null))
            {
                return;
            }

            if (!(userMessage.Author is IGuildUser author) ||
                (author.Guild is null) ||
                author.IsBot ||
                author.IsWebhook)
            {
                return;
            }

            var argPos = 0;

            if (!userMessage.HasCharPrefix('!', ref argPos) && !userMessage.HasMentionPrefix(DiscordClient.CurrentUser, ref argPos))
            {
                return;
            }

            if (userMessage.Content.Length <= 1)
            {
                return;
            }

            var commandContext = new CommandContext(DiscordClient, userMessage);

            await AuthorizationService.OnAuthenticatedAsync(author);

            var commandResult = await CommandService.ExecuteAsync(commandContext, argPos, ServiceProvider);

            if (!commandResult.IsSuccess)
            {
                var error = $"{commandResult.Error}: {commandResult.ErrorReason}";

                if (string.Equals(commandResult.ErrorReason, "UnknownCommand", StringComparison.OrdinalIgnoreCase))
                {
                    Log.Error(error);
                }
                else
                {
                    Log.Warning(error);
                }

                if (commandResult.Error == CommandError.Exception)
                {
                    await commandContext.Channel.SendMessageAsync($"Error: {FormatUtilities.SanitizeEveryone(commandResult.ErrorReason)}");
                }
                else
                {
                    await CommandErrorHandler.AssociateError(userMessage, error);
                }
            }

            stopwatch.Stop();
            Log.Information($"Command took {stopwatch.ElapsedMilliseconds}ms to process: {commandContext.Message}");
        }
コード例 #6
0
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            Log.LogInformation("Starting bot background service.");

            IServiceScope scope = null;

            try
            {
                // Create a new scope for the session.
                scope = _provider.CreateScope();

                Log.LogTrace("Registering listeners for Discord client events.");

                _client.Disconnected    += OnDisconnect;
                _client.MessageReceived += HandleCommand;

                _client.Log   += _serilogAdapter.HandleLog;
                _commands.Log += _serilogAdapter.HandleLog;

                // Register with the cancellation token so we can stop listening to client events if the service is
                // shutting down or being disposed.
                stoppingToken.Register(OnStopping);

                Log.LogInformation("Running database migrations.");
                scope.ServiceProvider.GetRequiredService <ModixContext>()
                .Database.Migrate();

                Log.LogInformation("Starting behaviors.");
                await scope.ServiceProvider.GetRequiredService <IBehaviourConfigurationService>()
                .LoadBehaviourConfiguration();

                foreach (var behavior in scope.ServiceProvider.GetServices <IBehavior>())
                {
                    await behavior.StartAsync();

                    stoppingToken.Register(() => behavior.StopAsync().GetAwaiter().GetResult());
                }

                _errorHandler = scope.ServiceProvider.GetRequiredService <CommandErrorHandler>();

                // The only thing that could go wrong at this point is the client failing to login and start. Promote
                // our local service scope to a field so that it's available to the HandleCommand method once events
                // start firing after we've connected.
                _scope = scope;

                Log.LogInformation("Loading command modules...");

                await _commands.AddModulesAsync(typeof(ModixBot).Assembly, _scope.ServiceProvider);

                Log.LogInformation("{Modules} modules loaded, containing {Commands} commands",
                                   _commands.Modules.Count(), _commands.Modules.SelectMany(d => d.Commands).Count());

                Log.LogInformation("Logging into Discord and starting the client.");

                await StartClient(stoppingToken);

                Log.LogInformation("Discord client started successfully.");

                await Task.Delay(-1);
            }
            catch (Exception ex)
            {
                Log.LogError(ex, "An error occurred while attempting to start the background service.");

                try
                {
                    OnStopping();

                    Log.LogInformation("Logging out of Discord.");
                    await _client.LogoutAsync();
                }
                finally
                {
                    scope?.Dispose();
                    _scope = null;
                }

                throw;
            }

            void OnStopping()
            {
                Log.LogInformation("Stopping background service.");

                _client.Disconnected    -= OnDisconnect;
                _client.MessageReceived -= HandleCommand;

                _client.Log   -= _serilogAdapter.HandleLog;
                _commands.Log -= _serilogAdapter.HandleLog;
            }
        }