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); }