using System.Diagnostics; namespace RegexBot.Modules.AutoResponder; /// /// Provides the capability to define text responses to pattern-based triggers for fun or informational /// purposes. Although in essence similar to , it is a better /// fit for non-moderation use cases and has specific features suitable to that end. /// [RegexbotModule] internal class AutoResponder : RegexbotModule { public AutoResponder(RegexbotClient bot) : base(bot) { DiscordClient.MessageReceived += DiscordClient_MessageReceived; } 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(Name + " configuration must be a JSON array."); foreach (var def in config.Children()) defs.Add(new Definition(def)); if (defs.Count == 0) return Task.FromResult(null); Log(DiscordClient.GetGuild(guildID), $"Loaded {defs.Count} definition(s)."); return Task.FromResult(defs.AsReadOnly()); } private async Task DiscordClient_MessageReceived(SocketMessage arg) { if (!Common.Utilities.IsValidUserMessage(arg, out var ch)) return; var definitions = GetGuildState>(ch.Guild.Id); if (definitions == null) return; // No configuration in this guild; do no further processing foreach (var def in definitions) { await ProcessMessageAsync(arg, def, ch); } } private async Task ProcessMessageAsync(SocketMessage msg, Definition def, SocketTextChannel ch) { if (!def.Match(msg)) return; Log(ch.Guild, $"Definition '{def.Label}' triggered by {msg.Author}."); if (def.Command == null) { await msg.Channel.SendMessageAsync(def.GetResponse()); } else { var cmdline = def.Command.Split(new char[] { ' ' }, 2); var ps = new ProcessStartInfo() { FileName = cmdline[0], Arguments = cmdline.Length == 2 ? cmdline[1] : "", UseShellExecute = false, // ??? CreateNoWindow = true, RedirectStandardOutput = true }; using var p = Process.Start(ps)!; p.WaitForExit(5000); // waiting 5 seconds at most if (p.HasExited) { if (p.ExitCode != 0) { Log(ch.Guild, $"Command execution: Process exited abnormally (with code {p.ExitCode})."); } using var stdout = p.StandardOutput; var result = await stdout.ReadToEndAsync(); if (!string.IsNullOrWhiteSpace(result)) await msg.Channel.SendMessageAsync(result); } else { Log(ch.Guild, $"Command execution: Process has not exited in 5 seconds. Killing process."); p.Kill(); } } } }