RegexBot/Modules/AutoResponder/AutoResponder.cs

74 lines
3 KiB
C#
Raw Normal View History

2022-04-23 20:01:27 +00:00
using System.Diagnostics;
2022-04-23 20:01:27 +00:00
namespace RegexBot.Modules.AutoResponder;
/// <summary>
/// Provides the capability to define text responses to pattern-based triggers for fun or informational
/// purposes. Although in essence similar to <see cref="RegexModerator.RegexModerator"/>, it is a better
/// fit for non-moderation use cases and has specific features suitable to that end.
/// </summary>
[RegexbotModule]
internal class AutoResponder : RegexbotModule {
2022-04-23 20:01:27 +00:00
public AutoResponder(RegexbotClient bot) : base(bot) {
DiscordClient.MessageReceived += DiscordClient_MessageReceived;
}
public override Task<object?> CreateGuildStateAsync(ulong guildID, JToken config) {
if (config == null) return Task.FromResult<object?>(null);
var defs = new List<Definition>();
if (config.Type != JTokenType.Array)
throw new ModuleLoadException(Name + " configuration must be a JSON array.");
foreach (var def in config.Children<JObject>())
defs.Add(new Definition(def));
if (defs.Count == 0) return Task.FromResult<object?>(null);
Log(DiscordClient.GetGuild(guildID), $"Loaded {defs.Count} definition(s).");
return Task.FromResult<object?>(defs.AsReadOnly());
}
2022-04-23 20:01:27 +00:00
private async Task DiscordClient_MessageReceived(SocketMessage arg) {
2022-07-09 20:22:39 +00:00
if (!Common.Utilities.IsValidUserMessage(arg, out var ch)) return;
2022-04-23 20:01:27 +00:00
var definitions = GetGuildState<IEnumerable<Definition>>(ch.Guild.Id);
if (definitions == null) return; // No configuration in this guild; do no further processing
foreach (var def in definitions) {
2022-07-29 02:33:49 +00:00
await ProcessMessageAsync(arg, def, ch);
}
2022-04-23 20:01:27 +00:00
}
2022-07-29 02:33:49 +00:00
private async Task ProcessMessageAsync(SocketMessage msg, Definition def, SocketTextChannel ch) {
2022-04-23 20:01:27 +00:00
if (!def.Match(msg)) return;
2022-07-29 02:33:49 +00:00
Log(ch.Guild, $"Definition '{def.Label}' triggered by {msg.Author}.");
2022-04-23 20:01:27 +00:00
if (def.Command == null) {
await msg.Channel.SendMessageAsync(def.GetResponse());
2022-04-23 20:01:27 +00:00
} else {
var cmdline = def.Command.Split(new char[] { ' ' }, 2);
2022-04-23 20:01:27 +00:00
var ps = new ProcessStartInfo() {
FileName = cmdline[0],
2022-07-29 02:33:49 +00:00
Arguments = cmdline.Length == 2 ? cmdline[1] : "",
2022-04-23 20:01:27 +00:00
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}).");
2022-04-23 20:01:27 +00:00
}
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.");
2022-04-23 20:01:27 +00:00
p.Kill();
}
}
}
}