private async Task HandleCommandsAsync(SocketMessage m) { try { // Stats and stuff. MessagesReceived++; // Make sure that this object can be a SocketUserMessage before processing anything. // Then store the cast in "message" with C# magic. // Exit otherwise. if (!(m is SocketUserMessage message)) { return; } // Only continue if the author is not a bot. if (message.Author.IsBot) { return; } // Try to extract and upcast the channel. // Same logic as before but without SocketContext overhead. if (!(m.Channel is SocketGuildChannel channel)) { // TODO: Should we mock the D.NET behaviour here? // They seem to assign null if the cast is not possible. // This needs more investigation. // For now we'll just exit here. return; } // Check if invoker is banend if (_banService.IsBanned(message.Author.Id)) { return; } // Check the permissions of this channel if (await Utility.CheckReadWritePerms(channel.Guild, channel, false) == false) { return; } // Check the ratelimit of this author if (await _ratelimitingService.IsRatelimited(message.Author.Id)) { return; } // Permissions are present and author is eligible for commands. // Get a database instance. using (var soraContext = new SoraContext()) { //Hand it over to the AFK Service to do its thing. Don't await to not block command processing. _afkService.Client_MessageReceived(m, _services); // Look for a prefix but use a hardcoded fallback instead of creating a default guild. // TODO: Move this into the config file var prefix = Utility.GetGuildPrefixFast(soraContext, channel.Guild.Id, "$"); // Check if the message starts with the prefix or mention before doing anything else. // Also rely on stdlib stuff for that because #performance. int argPos = prefix.Length - 1; if (!(message.HasStringPrefix(prefix, ref argPos) || message.HasMentionPrefix(_client.CurrentUser, ref argPos))) { return; } // Detection finished. // We know it's *very likely* a command for us. // It's safe to create a context now. var context = new SocketCommandContext(_client, message); // Also allocate a default guild if needed since we skipped that part earlier. Utility.GetOrCreateGuild(channel.Guild.Id, soraContext); // Handoff control to D.NET var result = await _commands.ExecuteAsync( context, argPos, _services ); // Handle errors if needed if (result.IsSuccess) { CommandsExecuted++; _ratelimitingService.RateLimitMain(context.User.Id); } else { //await context.Channel.SendMessageAsync($"**FAILED**\n{result.ErrorReason}"); await HandleErrorAsync(result, context); } } } catch (Exception e) { Console.WriteLine(e); } }