Как исправить «Обработчик, полученный от MessageReceived, блокирует задачу шлюза». в DiscordBot

#.net-core #discord #discord.net

#.net-core #Discord #discord.net

Вопрос:

Я пытаюсь создать своего собственного бота Discord, который мягко запрещает людям, которые пишут расистские или антисемитские слова. Я пытаюсь сделать это с помощью MessageReceivedAsync, но он постоянно вылетает с ошибкой «Обработчик MessageReceived блокирует задачу шлюза».

Вот код моей Program.cs:

 namespace NoNetworcc
{
class Program : ModuleBase<SocketCommandContext>
    {
        static void Main(string[] args)
            => new Program().MainAsync().GetAwaiter().GetResult();

        public async Task MainAsync()
        {
            using (var services = ConfigureServices())
            {
                var client = services.GetRequiredService<DiscordSocketClient>();

                client.Log  = LogAsync;
                client.MessageReceived  = MessageReceivedAsync;
                services.GetRequiredService<CommandService>().Log  = LogAsync;

                await client.LoginAsync(TokenType.Bot, "NzEyNDA2MDAxMjAxOTcxMjcw.XsRF4A.8YENNInx3D4kqJyK9N8xjTU3mcs");
                await client.StartAsync();

                await services.GetRequiredService<CommandHandlingService>().InitializeAsync();

                await Task.Delay(Timeout.Infinite);
            }
        }

        private Task LogAsync(LogMessage log)
        {
            Console.WriteLine(log.ToString());

            return Task.CompletedTask;
        }

        private async Task MessageReceivedAsync(SocketMessage message)
        {
            using (BlacklistDatabaseContext lite = new BlacklistDatabaseContext())
            {
                var blacklistWords = lite.BlacklistWords;

                foreach(var word in blacklistWords)
                {
                    if(message.Content.Contains(word.Blacklistword.ToString()))
                    {
                        ulong roleID = 756500011331616840;
                        var role = Context.Guild.GetRole(roleID);
                        await ((IGuildUser)Context.User).AddRoleAsync(role);
                        await message.Channel.SendMessageAsync($"{Context.User} got softbanned for using the word '{word}'");
                    }
                }
            }
        }

        private ServiceProvider ConfigureServices()
        {
            return new ServiceCollection()
                .AddSingleton<DiscordSocketClient>()
                .AddSingleton<CommandService>()
                .AddSingleton<CommandHandlingService>()
                .AddSingleton<HttpClient>()
                .AddSingleton<PictureService>()
                .BuildServiceProvider();
        }
    }
}
  

И вот мой код для службы обработки:

 namespace NoNetworcc.Services
{
    public class CommandHandlingService
    {
        private readonly CommandService _commands;
        private readonly DiscordSocketClient _discord;
        private readonly IServiceProvider _services;

        public CommandHandlingService(IServiceProvider services)
        {
            _commands = services.GetRequiredService<CommandService>();
            _discord = services.GetRequiredService<DiscordSocketClient>();
            _services = services;

            _commands.CommandExecuted  = CommandExecutedAsync;
            _discord.MessageReceived  = MessageReceivedAsync;
        }

        public async Task InitializeAsync()
        {
            await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _services);
        }

        public async Task MessageReceivedAsync(SocketMessage rawMessage)
        {
            if (!(rawMessage is SocketUserMessage message)) return;
            if (message.Source != MessageSource.User) return;

            var argPos = 0;

            var context = new SocketCommandContext(_discord, message);
            await _commands.ExecuteAsync(context, argPos, _services); 
        }

        public async Task CommandExecutedAsync(Optional<CommandInfo> command, ICommandContext context, IResult result)
        {
            if (!command.IsSpecified)
                return;

            if (result.IsSuccess)
                return;

            await context.Channel.SendMessageAsync($"error: {result}");
       }
    }
 }
  

Как я могу исправить эту проблему?

Комментарии:

1. обработка кода в вашем обработчике занимает слишком много времени. Все, выполнение чего займет более 3 секунд, заблокирует регистрацию этого сообщения. Любой долго выполняющийся код должен выполняться в другой задаче (т.е. Не в задаче шлюза).

2. @Anu6is как мне это сделать, например? Не могли бы вы показать мне это при использовании моего кода?

3. Просто оберните всю логику внутри обработчика событий черного списка в Task.Run() . Кроме того, ваш Program.cs не должен наследоваться от ModuleBase и Context будет недействительным в этом классе, поскольку он фактически никогда не создавался.

4. @Anu6is Я все еще не понимаю. Не могли бы вы переписать мой код при использовании Task.Run()?

Ответ №1:

 private Task MessageReceivedAsync(SocketMessage message) {
    _ = Task.Run(async () => {
            using (BlacklistDatabaseContext lite = new BlacklistDatabaseContext()) {
                var blacklistWords = lite.BlacklistWords;
                foreach (var word in blacklistWords) {
                    if(message.Content.Contains(word.Blacklistword.ToString())) {
                        ulong roleID = 756500011331616840;
                        var role = (message.Channel as ITextChannel)?.Guild.GetRole(roleID);
                        if (role != null) {
                            await (message.Author as SocketGuildUser)?.AddRoleAsync(role);
                            await message.Channel.SendMessageAsync($"{message.Author} got softbanned for using the word '{word}'");
                        }
                    }
                }
            }
        });
        return Task.CompletedTask; 
}
  

Комментарии:

1. Но теперь я не могу использовать «using (BlacklistDatabaseContext lite = new BlacklistDatabaseContext ())»

2. Почему вы не можете его использовать?

3. В нем написано «недопустимое выражение»

4. это не должно иметь ничего общего с синтаксисом Task.Run() проверки вашего кода

5. ааааа, я забыл написать ‘async’ в Task.Run