Esempio n. 1
0
        private async Task ExecuteCommandAsync(int counter, Guid correlationId, ILogger logger, CommandRegistrationFindResult findResult, ICommand command, Stopwatch stopwatch, TimeSpan verificationElapsed, TimeSpan parsingElapsed, TimeSpan gatewayPing)
        {
            IDisposable typingState = null;

            if (findResult.Registration.Flags.HasFlag(CommandFlags.TypingIndicator))
            {
                typingState = command.Message.Channel.EnterTypingState();
            }

            var result = CommandResult.Failed;

            try
            {
                using (var scope = _clientServiceProvider.CreateScope())
                {
                    var module        = scope.ServiceProvider.GetRequiredService(findResult.Registration.ModuleType);
                    var commandLogger = _loggerFactory.CreateLogger(findResult.Registration.ModuleType)
                                        .WithCommandScope(command.Message, correlationId, findResult.Registration, findResult.Usage);

                    await findResult.Registration.Handler.Invoke(module, command, commandLogger, default); // TODO: cancellation
                }

                result = CommandResult.Succeeded;
            }
            catch (Exceptions.AbortException ex)
            {
                if (ex.Pages != null)
                {
                    await _communicator.CommandReply(command.Message.Channel, ex.Pages);
                }
                else if (!string.IsNullOrEmpty(ex.Message))
                {
                    await _communicator.CommandReply(command.Message.Channel, ex.Message);
                }

                result = CommandResult.Succeeded;
            }
            catch (Exceptions.IncorrectParametersCommandException ex)
            {
                await _communicator.CommandReplyIncorrectParameters(command.Message.Channel, findResult.Registration, ex.Message, findResult.Prefix, ex.ShowUsage);
            }
            catch (Exceptions.UnclearParametersCommandException ex)
            {
                await _communicator.CommandReplyUnclearParameters(command.Message.Channel, findResult.Registration, ex.Message, findResult.Prefix, ex.ShowUsage);
            }
            catch (Exceptions.MissingPermissionsException ex)
            {
                await _communicator.CommandReplyMissingPermissions(command.Message.Channel, findResult.Registration, ex.Permissions, ex.Message);
            }
            catch (Exceptions.MissingBotPermissionsException ex)
            {
                await _communicator.CommandReplyMissingBotPermissions(command.Message.Channel, findResult.Registration, ex.Permissions);
            }
            catch (Exceptions.MissingBotChannelPermissionsException ex)
            {
                await _communicator.CommandReplyMissingBotPermissions(command.Message.Channel, findResult.Registration, ex.Permissions);
            }
            catch (Exceptions.CommandException ex)
            {
                await _communicator.CommandReplyError(command.Message.Channel, ex.Message);
            }
            catch (Discord.Net.HttpException ex) when(ex.DiscordCode == 50001)
            {
                await _communicator.CommandReplyMissingBotAccess(command.Message.Channel, findResult.Registration);
            }
            catch (Discord.Net.HttpException ex) when(ex.DiscordCode == 50013)
            {
                await _communicator.CommandReplyMissingBotPermissions(command.Message.Channel, findResult.Registration);
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "Exception encountered while processing command {Command} (nr: {CommandCounter}) in module {Module}", findResult.Registration.PrimaryUsage.InvokeUsage, counter, findResult.Registration.ModuleType);
                await _communicator.CommandReplyGenericFailure(command.Message.Channel);
            }
            finally
            {
                if (typingState != null)
                {
                    typingState.Dispose();
                }
            }

            var totalElapsed = stopwatch.Elapsed;

            logger.LogInformation("Command {CommandCounter} {Result} in {TotalElapsed:F3}s (v: {VerificationElapsed:F3}s, p: {ParsingElapsed:F3}s, e: {ExecutionElapsed:F3}s, g: {GatewayDelay:F3}s)", counter, result, totalElapsed.TotalSeconds, verificationElapsed.TotalSeconds, (parsingElapsed - verificationElapsed).TotalSeconds, (totalElapsed - parsingElapsed).TotalSeconds, gatewayPing.TotalSeconds);
        }
Esempio n. 2
0
        private async Task HandleCommand(SocketUserMessage message, CommandRegistrationFindResult findResult)
        {
            var correlationId = Guid.NewGuid();
            var logger        = _logger.WithCommandScope(message, correlationId, findResult.Registration, findResult.Usage);

            var stopwatch    = Stopwatch.StartNew();
            var gatewayDelay = DateTimeOffset.UtcNow - message.Timestamp;

            var counter = Interlocked.Increment(ref _commandCounter);
            var guild   = (message.Channel as IGuildChannel)?.Guild;

            // Don't log command content for non-guild channels, since these commands are usually meant to be private
            if (guild != null)
            {
                logger.LogInformation("Command {CommandCounter} {MessageContent} with {MessageAttachmentCount} attachments", counter, message.Content, message.Attachments.Count);
            }
            else
            {
                logger.LogInformation("Command {CommandCounter} {MessageContentRedacted} with {MessageAttachmentCount} attachments", counter, findResult.Prefix + findResult.Usage.InvokeUsage, message.Attachments.Count);
            }

            // Check if the channel type is valid for this command
            if (!IsValidCommandSource(message.Channel, findResult.Registration))
            {
                logger.LogInformation("Command {CommandCounter} rejected in {TotalElapsed:F3}s (g: {GatewayElapsed:F3}s) due to invalid channel type", counter, stopwatch.Elapsed.TotalSeconds, gatewayDelay.TotalSeconds);

                if (message.Channel is ITextChannel && findResult.Registration.Flags.HasFlag(CommandFlags.DirectMessageOnly))
                {
                    await _communicator.CommandReplyDirectMessageOnly(message.Channel, findResult.Registration);
                }

                return;
            }

            // Check owner
            if (findResult.Registration.Flags.HasFlag(CommandFlags.OwnerOnly) && !_ownerIDs.Contains(message.Author.Id))
            {
                logger.LogInformation("Command {CommandCounter} rejected in {TotalElapsed:F3}s (g: {GatewayElapsed:F3}s) due to the user not being an owner", counter, stopwatch.Elapsed.TotalSeconds, gatewayDelay.TotalSeconds);
                await _communicator.CommandReplyNotOwner(message.Channel, findResult.Registration);

                return;
            }

            // Check guild permisssions
            if (message.Channel is IGuildChannel guildChannel)
            {
                // User
                var guildUser          = message.Author as IGuildUser;
                var missingPermissions = findResult.Registration.UserPermissions.Where(x => !guildUser.GuildPermissions.Has(x));
                if (missingPermissions.Any())
                {
                    logger.LogInformation("Command {CommandCounter} rejected in {TotalElapsed:F3}s (g: {GatewayElapsed:F3}s) due to missing user permissions", counter, stopwatch.Elapsed.TotalSeconds, gatewayDelay.TotalSeconds);
                    await _communicator.CommandReplyMissingPermissions(message.Channel, findResult.Registration, missingPermissions);

                    return;
                }

                // Bot
                var selfUser = await guild.GetCurrentUserAsync();

                var missingBotPermissions = findResult.Registration.BotPermissions.Where(x => !selfUser.GuildPermissions.Has(x));
                if (missingBotPermissions.Any())
                {
                    logger.LogInformation("Command {CommandCounter} rejected in {TotalElapsed:F3}s (g: {GatewayElapsed:F3}s) due to missing bot permissions", counter, stopwatch.Elapsed.TotalSeconds, gatewayDelay.TotalSeconds);
                    await _communicator.CommandReplyMissingBotPermissions(message.Channel, findResult.Registration, missingBotPermissions);

                    return;
                }
            }

            var verificationElapsed = stopwatch.Elapsed;

            // Create command
            var parseResult = await _commandParser.Parse(message, findResult.Registration, findResult.Usage, findResult.Prefix);

            if (parseResult.Type != CommandParseResultType.Success)
            {
                string explanation = "";
                switch (parseResult.Type)
                {
                case CommandParseResultType.NotEnoughParameters: explanation = Properties.Resources.Command_NotEnoughParameters; break;

                case CommandParseResultType.TooManyParameters: explanation = Properties.Resources.Command_TooManyParameters; break;

                case CommandParseResultType.InvalidParameterFormat: explanation = string.Format(Properties.Resources.Command_InvalidParameterFormat, ((InvalidParameterCommandParseResult)parseResult).InvalidPosition); break;
                }

                logger.LogInformation("Command {CommandCounter} rejected in {TotalElapsed:F3}s (g: {GatewayElapsed:F3}s) due to incorrect parameters", counter, stopwatch.Elapsed.TotalSeconds, gatewayDelay.TotalSeconds);
                await _communicator.CommandReplyIncorrectParameters(message.Channel, findResult.Registration, explanation, findResult.Prefix);

                return;
            }

            var command        = new Command((SuccessCommandParseResult)parseResult, _communicator);
            var parsingElapsed = stopwatch.Elapsed;

            // Execute
            if (findResult.Registration.Flags.HasFlag(CommandFlags.Synchronous))
            {
                await ExecuteCommandAsync(counter, correlationId, logger, findResult, command, stopwatch, verificationElapsed, parsingElapsed, gatewayDelay);
            }
            else
            {
                TaskHelper.FireForget(() => ExecuteCommandAsync(counter, correlationId, logger, findResult, command, stopwatch, verificationElapsed, parsingElapsed, gatewayDelay),
                                      x => logger.LogError(x, "Uncaught exception while handling command."));
            }
        }