RegexBot/Module/ModCommands/ModCommands.cs
Noikoio 1773fd2fc2 Changed module configuration model
-Changed a few method names to better reflect its capabilities.
--Specifically, references to "Config" were renamed to "State".
-Changed the way that what is now CreateInstanceState is called
--It is now always called instead of only when configuration exists
--A basic null check was added to prevent issues resulting from this
--General exception handler added to configuration loader
2018-03-22 00:30:22 -07:00

86 lines
3.1 KiB
C#

using Discord;
using Discord.WebSocket;
using Newtonsoft.Json.Linq;
using Noikoio.RegexBot.ConfigItem;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Noikoio.RegexBot.Module.ModCommands
{
/// <summary>
/// This class manages reading configuration and creating instances based on it.
/// It processes input and looks for messages that intend to invoke commands defined in configuration.
/// </summary>
/// <remarks>
/// Discord.Net has its own recommended way of implementing commands, but it's not exactly
/// done in a way that would easily allow for flexibility and modifications during runtime.
/// Thus, reinventing the wheel right here.
/// </remarks>
class ModCommands : BotModule
{
public ModCommands(DiscordSocketClient client) : base(client)
{
client.MessageReceived += Client_MessageReceived;
}
private async Task Client_MessageReceived(SocketMessage arg)
{
// Always ignore these
if (arg.Author.IsBot || arg.Author.IsWebhook) return;
if (arg.Channel is IGuildChannel) await CommandCheckInvoke(arg);
}
public override async Task<object> CreateInstanceState(JToken configSection)
{
if (configSection == null) return null;
// Constructor throws exception on config errors
var conf = new ConfigItem(this, configSection);
// Log results
if (conf.Commands.Count > 0)
await Log(conf.Commands.Count + " command definition(s) loaded.");
return conf;
}
public new Task Log(string text) => base.Log(text);
private async Task CommandCheckInvoke(SocketMessage arg)
{
SocketGuild g = ((SocketGuildUser)arg.Author).Guild;
// Get guild config
ServerConfig sc = RegexBot.Config.Servers.FirstOrDefault(s => s.Id == g.Id);
if (sc == null) return;
// Disregard if not a bot moderator
if (!sc.Moderators.ExistsInList(arg)) return;
// Disregard if the message contains a newline character
if (arg.Content.Contains("\n")) return;
// Check for and invoke command
string cmdchk;
int spc = arg.Content.IndexOf(' ');
if (spc != -1) cmdchk = arg.Content.Substring(0, spc);
else cmdchk = arg.Content;
if (GetState<ConfigItem>(g.Id).Commands.TryGetValue(cmdchk, out var c))
{
try
{
await c.Invoke(g, arg);
// TODO Custom invocation log messages? Not by the user, but by the command.
await Log($"{g.Name}/#{arg.Channel.Name}: {arg.Author} invoked {arg.Content}");
}
catch (Exception ex)
{
await Log($"Encountered an unhandled exception while processing '{c.Label}'. Details follow:");
await Log(ex.ToString());
}
}
}
}
}