using Discord.WebSocket; using Newtonsoft.Json.Linq; using System.Collections.Generic; using System.Threading.Tasks; namespace RegexBot.Modules.RegexModerator { /// /// The 'star' feature of Kerobot. Users define pattern-based rules with other constraints. /// When triggered, each rule executes one or more different actions. /// [RegexbotModule] public class RegexModerator : ModuleBase { public RegexModerator(RegexbotClient bot) : base(bot) { DiscordClient.MessageReceived += DiscordClient_MessageReceived; DiscordClient.MessageUpdated += DiscordClient_MessageUpdated; } public override Task CreateGuildStateAsync(ulong guildID, JToken config) { if (config == null) return Task.FromResult(null); var defs = new List(); if (config.Type != JTokenType.Array) throw new ModuleLoadException(this.Name + " configuration must be a JSON array."); // TODO better error reporting during this process foreach (var def in config.Children()) defs.Add(new ConfDefinition(def)); if (defs.Count == 0) return Task.FromResult(null); return Task.FromResult(defs.AsReadOnly()); } private Task DiscordClient_MessageUpdated(Discord.Cacheable arg1, SocketMessage arg2, ISocketMessageChannel arg3) => ReceiveIncomingMessage(arg2); private Task DiscordClient_MessageReceived(SocketMessage arg) => ReceiveIncomingMessage(arg); /// /// Does initial message checking before further processing. /// private async Task ReceiveIncomingMessage(SocketMessage msg) { if (msg.Author.Id == 0) { // TODO what changed to cause this? this wasn't happening before. System.Console.WriteLine($"Skip processing of message with empty metadata. Msg ID {msg.Id} - Msg content: {msg.Content} - Embed count: {msg.Embeds.Count}"); return; } // Ignore non-guild channels if (!(msg.Channel is SocketGuildChannel ch)) return; // Get config? var defs = GetGuildState>(ch.Guild.Id); if (defs == null) return; // Send further processing to thread pool. // Match checking is a CPU-intensive task, thus very little checking is done here. var msgProcessingTasks = new List(); foreach (var item in defs) { // Need to check sender's moderator status here. Definition can't access mod list. var isMod = GetModerators(ch.Guild.Id).IsListMatch(msg, true); var match = item.IsMatch(msg, isMod); msgProcessingTasks.Add(Task.Run(async () => await ProcessMessage(item, msg, isMod))); } await Task.WhenAll(msgProcessingTasks); } /// /// Does further message checking and response execution. /// Invocations of this method are meant to be placed onto a thread separate from the caller. /// private async Task ProcessMessage(ConfDefinition def, SocketMessage msg, bool isMod) { // Reminder: IsMatch handles matching execution time if (!def.IsMatch(msg, isMod)) return; // TODO logging options for match result; handle here? var executor = new ResponseExecutor(def, BotClient); await executor.Execute(msg); } } }