DeukBot4/DeukBot4/MessageHandlers/CommandHandler/CommandHandler.cs

120 lines
4.7 KiB
C#
Raw Normal View History

2018-03-28 23:34:48 +00:00
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using DeukBot4.MessageHandlers.CommandHandler.RequestStructure;
using DeukBot4.MessageHandlers.Permissions;
using DeukBot4.Utilities;
2018-03-29 19:57:16 +00:00
using Discord;
2018-03-28 23:34:48 +00:00
using Discord.WebSocket;
namespace DeukBot4.MessageHandlers.CommandHandler
{
public static class CommandHandler
{
2018-03-30 12:51:38 +00:00
public static Dictionary<string, Command> Commands { get; } = new Dictionary<string, Command>();
public const char CommandTrigger = '!';
2018-03-28 23:34:48 +00:00
public static void Build()
{
var commandContainers = typeof(CommandHandler).Assembly.GetTypes()
.Where(x => typeof(CommandContainerBase).IsAssignableFrom(x) && !x.IsAbstract);
foreach (var commandContainer in commandContainers)
{
if (!(Activator.CreateInstance(commandContainer) is CommandContainerBase obj))
continue;
var commands = obj.GetCommands();
foreach (var command in commands)
{
Commands.Add(command.Name.ToLowerInvariant(), command);
foreach (var commandAlternative in command.Alternatives)
{
Commands.Add(commandAlternative.ToLowerInvariant(), command);
}
2018-03-28 23:34:48 +00:00
}
2018-08-13 16:41:59 +00:00
Logger.Main.Log(
2018-03-30 12:51:38 +00:00
$"Loaded following commands for container {obj.Name}: {commands.Select(x => x.Name).Join(", ")}");
2018-03-28 23:34:48 +00:00
}
}
public static async Task HandleMessage(SocketMessage message)
{
2018-03-29 17:38:23 +00:00
if (string.IsNullOrWhiteSpace(message.Content))
return;
if (message.Content[0] != CommandTrigger && message.MentionedUsers.All(x => x.Id != Program.BotId))
2018-03-30 12:51:38 +00:00
return;
if (message.Content[1] == '!')
return;
2018-03-30 12:51:38 +00:00
var req = await CommandRequest.Create(message);
var resultCode = req.Response;
2018-03-30 12:51:38 +00:00
switch (resultCode)
2018-03-28 23:34:48 +00:00
{
2018-03-30 12:51:38 +00:00
case CommandRequest.RequestCode.Invalid:
2018-08-13 16:41:59 +00:00
await Logger.Main.LogError("Invalid content: " + message.Content);
2018-03-30 12:51:38 +00:00
return;
case CommandRequest.RequestCode.InvalidParameters:
2018-08-13 16:41:59 +00:00
await Logger.Main.LogError("Invalid parameters: " + message.Content);
break;
2018-03-30 12:51:38 +00:00
case CommandRequest.RequestCode.Forbidden:
2018-08-13 16:41:59 +00:00
await Logger.Main.Log(
2018-03-30 12:51:38 +00:00
$"Unauthorized user tried to run command: {message.Author.Username} -> {message.Content}");
break;
case CommandRequest.RequestCode.OK:
if (!(message.Channel is IGuildChannel) && req.Request.Command.ForbidInPm)
2018-03-30 12:51:38 +00:00
{
2018-08-13 16:41:59 +00:00
await Logger.Main.Log(
2018-03-30 12:51:38 +00:00
$"User is trying to use blocked command in PM: {message.Author.Username}");
return;
}
try
{
await req.Request.Command.Invoke(req.Request);
}
catch (Exception e)
{
2018-08-13 16:41:59 +00:00
await Logger.Main.Log("An error occured: \n" + e);
}
2018-03-30 12:51:38 +00:00
break;
case CommandRequest.RequestCode.UnknownCommand:
var permission = await PermissionValidator.GetUserPermissionLevel(message);
var similar = await GetSimilarCommand(req.CommandName, permission);
2018-03-30 12:51:38 +00:00
await message.Channel.SendMessageAsync(
$"Unknown command: ``{req.CommandName}``. Did you mean: ``{similar}``? " +
$"Alternatively, use ``{CommandTrigger}help`` for a list of all commands");
2018-03-30 12:51:38 +00:00
break;
default:
throw new ArgumentOutOfRangeException();
2018-03-28 23:34:48 +00:00
}
2018-03-30 12:51:38 +00:00
}
2018-03-29 19:57:16 +00:00
private static async Task<string> GetSimilarCommand(string command, PermissionLevel permission)
2018-03-30 12:51:38 +00:00
{
var closestString = "";
var similarity = int.MaxValue;
foreach (var cmd in Commands)
2018-03-28 23:34:48 +00:00
{
if (cmd.Value.Permission > permission)
continue;
2018-03-30 12:51:38 +00:00
var distance = Lehvenstein.LevenshteinDistance(command, cmd.Key);
if (distance >= similarity)
continue;
similarity = distance;
closestString = cmd.Key;
2018-03-28 23:34:48 +00:00
}
2018-03-30 12:51:38 +00:00
return closestString;
2018-03-28 23:34:48 +00:00
}
public static Command GetCommand(string name)
{
return Commands.TryGetValue(name.ToLowerInvariant(), out var com) ? com : null;
}
}
}