mirror of
https://github.com/barelyprofessional/KfChatDotNet.git
synced 2026-05-02 04:22:04 -04:00
Updated commands to remove the hide from help property, instead set the help text to null for whenever that eventually gets implemented.
Also refactored the way tasks are handled so instead of adding to an array and checking in on them next time someone sends a message, it instead delegates it to a very basic async handler that'll await the command, report errors and kill the task if it takes too long.
This commit is contained in:
@@ -7,9 +7,10 @@ namespace KfChatDotNetBot.Commands;
|
||||
internal interface ICommand
|
||||
{
|
||||
List<Regex> Patterns { get; }
|
||||
string HelpText { get; }
|
||||
bool HideFromHelp { get; }
|
||||
// Set to null to disable help for a given command
|
||||
string? HelpText { get; }
|
||||
UserRight RequiredRight { get; }
|
||||
TimeSpan Timeout { get; }
|
||||
|
||||
Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx);
|
||||
}
|
||||
@@ -14,6 +14,7 @@ public class JuiceCommand : ICommand
|
||||
public string HelpText => "Get juice!";
|
||||
public bool HideFromHelp => false;
|
||||
public UserRight RequiredRight => UserRight.Guest;
|
||||
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
{
|
||||
await using var db = new ApplicationDbContext();
|
||||
@@ -50,12 +51,13 @@ public class JuiceCommand : ICommand
|
||||
public class JuiceStatsCommand : ICommand
|
||||
{
|
||||
public List<Regex> Patterns => [
|
||||
new Regex("^juice stats"),
|
||||
new Regex("^juice stats$"),
|
||||
new Regex(@"^juice stats (?<top>\d+)$")
|
||||
];
|
||||
public string HelpText => "Get juice stats!";
|
||||
public bool HideFromHelp => false;
|
||||
public UserRight RequiredRight => UserRight.Guest;
|
||||
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
{
|
||||
int top;
|
||||
|
||||
@@ -7,10 +7,9 @@ namespace KfChatDotNetBot.Commands;
|
||||
public class InsanityCommand : ICommand
|
||||
{
|
||||
public List<Regex> Patterns => [new Regex("^insanity")];
|
||||
public string HelpText => "Insanity";
|
||||
public bool HideFromHelp => false;
|
||||
public string? HelpText => "Insanity";
|
||||
public UserRight RequiredRight => UserRight.Guest;
|
||||
|
||||
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
{
|
||||
// ReSharper disable once StringLiteralTypo
|
||||
@@ -21,10 +20,9 @@ public class InsanityCommand : ICommand
|
||||
public class TwistedCommand : ICommand
|
||||
{
|
||||
public List<Regex> Patterns => [new Regex("^twisted")];
|
||||
public string HelpText => "Get it twisted";
|
||||
public bool HideFromHelp => false;
|
||||
public string? HelpText => "Get it twisted";
|
||||
public UserRight RequiredRight => UserRight.Guest;
|
||||
|
||||
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
{
|
||||
// ReSharper disable once StringLiteralTypo
|
||||
@@ -35,10 +33,9 @@ public class TwistedCommand : ICommand
|
||||
public class HelpMeCommand : ICommand
|
||||
{
|
||||
public List<Regex> Patterns => [new Regex("^helpme")];
|
||||
public string HelpText => "Somebody please help me";
|
||||
public bool HideFromHelp => false;
|
||||
public string? HelpText => "Somebody please help me";
|
||||
public UserRight RequiredRight => UserRight.Guest;
|
||||
|
||||
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
{
|
||||
// ReSharper disable once StringLiteralTypo
|
||||
@@ -49,10 +46,9 @@ public class HelpMeCommand : ICommand
|
||||
public class SentCommand : ICommand
|
||||
{
|
||||
public List<Regex> Patterns => [new Regex("^sent$")];
|
||||
public string HelpText => "Sent love";
|
||||
public bool HideFromHelp => false;
|
||||
public string? HelpText => "Sent love";
|
||||
public UserRight RequiredRight => UserRight.Guest;
|
||||
|
||||
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
{
|
||||
// ReSharper disable once StringLiteralTypo
|
||||
|
||||
@@ -12,9 +12,9 @@ public class RainbetStatsCommand : ICommand
|
||||
public List<Regex> Patterns => [
|
||||
new Regex(@"^rainbet stats (?<window>\d+)$")
|
||||
];
|
||||
public string HelpText => "Get betting statistics in the given window";
|
||||
public bool HideFromHelp => false;
|
||||
public string? HelpText => "Get betting statistics in the given window";
|
||||
public UserRight RequiredRight => UserRight.Guest;
|
||||
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
{
|
||||
var window = Convert.ToInt32(arguments["window"].Value);
|
||||
@@ -28,7 +28,7 @@ public class RainbetStatsCommand : ICommand
|
||||
return;
|
||||
}
|
||||
var output = $"Rainbet stats for the last {window} hours (as seen on the bet feed):[br]" +
|
||||
$"Bets: {bets.Count:N0}; Payout: ${bets.Sum(b => b.Payout):C}; Wagered: {bets.Sum(b => b.Value):C}";
|
||||
$"Bets: {bets.Count:N0}; Payout: {bets.Sum(b => b.Payout):C}; Wagered: {bets.Sum(b => b.Value):C}";
|
||||
botInstance.SendChatMessage(output, true);
|
||||
}
|
||||
}
|
||||
@@ -38,9 +38,9 @@ public class RainbetRecentBetCommand : ICommand
|
||||
public List<Regex> Patterns => [
|
||||
new Regex(@"^rainbet recent$")
|
||||
];
|
||||
public string HelpText => "Get the most recent 3 bets";
|
||||
public bool HideFromHelp => false;
|
||||
public string? HelpText => "Get the most recent 3 bets";
|
||||
public UserRight RequiredRight => UserRight.Guest;
|
||||
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
{
|
||||
var settings = await Helpers.GetMultipleValues([
|
||||
|
||||
@@ -13,10 +13,10 @@ public class EditTestCommand : ICommand
|
||||
new Regex("^test edit (?<msg>.+)")
|
||||
];
|
||||
|
||||
public string HelpText => "Test the editing functionality";
|
||||
public bool HideFromHelp => true;
|
||||
public string? HelpText => null;
|
||||
public UserRight RequiredRight => UserRight.Admin;
|
||||
|
||||
// Increased timeout as it has to wait for Sneedchat to echo the message and that can be slow sometimes
|
||||
public TimeSpan Timeout => TimeSpan.FromSeconds(60);
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
{
|
||||
var logger = LogManager.GetCurrentClassLogger();
|
||||
@@ -50,3 +50,35 @@ public class EditTestCommand : ICommand
|
||||
botInstance.KfClient.DeleteMessage(status.ChatMessageId!.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public class TimeoutTestCommand : ICommand
|
||||
{
|
||||
public List<Regex> Patterns => [
|
||||
new Regex("^test timeout$")
|
||||
];
|
||||
|
||||
public string? HelpText => null;
|
||||
public UserRight RequiredRight => UserRight.Admin;
|
||||
// Increased timeout as it has to wait for Sneedchat to echo the message and that can be slow sometimes
|
||||
public TimeSpan Timeout => TimeSpan.FromSeconds(15);
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromMinutes(1), ctx);
|
||||
}
|
||||
}
|
||||
|
||||
public class ExceptionTestCommand : ICommand
|
||||
{
|
||||
public List<Regex> Patterns => [
|
||||
new Regex("^test exception$")
|
||||
];
|
||||
|
||||
public string? HelpText => null;
|
||||
public UserRight RequiredRight => UserRight.Admin;
|
||||
// Increased timeout as it has to wait for Sneedchat to echo the message and that can be slow sometimes
|
||||
public TimeSpan Timeout => TimeSpan.FromSeconds(15);
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
{
|
||||
throw new Exception("Caused by the test exception command");
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,9 @@ namespace KfChatDotNetBot.Commands;
|
||||
public class TimeCommand : ICommand
|
||||
{
|
||||
public List<Regex> Patterns => [new Regex("^time")];
|
||||
public string HelpText => "Get current time in BMT";
|
||||
public bool HideFromHelp => false;
|
||||
public string? HelpText => "Get current time in BMT";
|
||||
public UserRight RequiredRight => UserRight.Guest;
|
||||
|
||||
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
{
|
||||
var bmt = new DateTimeOffset(TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow,
|
||||
|
||||
@@ -11,10 +11,9 @@ public class WhoisCommand : ICommand
|
||||
new Regex("^whois (?<user>.+)")
|
||||
];
|
||||
|
||||
public string HelpText => "Lookup user IDs by username";
|
||||
public bool HideFromHelp => false;
|
||||
public string? HelpText => "Lookup user IDs by username";
|
||||
public UserRight RequiredRight => UserRight.Guest;
|
||||
|
||||
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
{
|
||||
await using var db = new ApplicationDbContext();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Humanizer;
|
||||
using System.Text.RegularExpressions;
|
||||
using Humanizer;
|
||||
using KfChatDotNetBot.Commands;
|
||||
using KfChatDotNetBot.Models.DbModels;
|
||||
using KfChatDotNetWsClient.Models.Events;
|
||||
using NLog;
|
||||
|
||||
@@ -14,7 +16,6 @@ internal class BotCommands
|
||||
private char CommandPrefix = '!';
|
||||
private IEnumerable<ICommand> Commands;
|
||||
private CancellationToken _cancellationToken;
|
||||
private List<Task> _commandTasks = [];
|
||||
|
||||
internal BotCommands(ChatBot bot, CancellationToken? ctx = null)
|
||||
{
|
||||
@@ -63,28 +64,29 @@ internal class BotCommands
|
||||
_bot.SendChatMessage($"@{message.Author.Username}, you do not have access to use this command. Your rank: {user.UserRight.Humanize()}; Required rank: {command.RequiredRight.Humanize()}", true);
|
||||
break;
|
||||
}
|
||||
var task = Task.Run(() => command.RunCommand(_bot, message, user, match.Groups, _cancellationToken), _cancellationToken);
|
||||
_commandTasks.Add(task);
|
||||
_ = ProcessMessageAsync(command, message, user, match.Groups);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check on the state of the tasks, there's no way to know what error they produce if they failed otherwise
|
||||
List<Task> removals = [];
|
||||
foreach (var task in _commandTasks)
|
||||
private async Task ProcessMessageAsync(ICommand command, MessageModel message, UserDbModel user, GroupCollection arguments)
|
||||
{
|
||||
var task = Task.Run(() => command.RunCommand(_bot, message, user, arguments, _cancellationToken), _cancellationToken);
|
||||
try
|
||||
{
|
||||
if (!task.IsCompleted) continue;
|
||||
if (task.IsFaulted)
|
||||
{
|
||||
_logger.Error("Command task failed at some point");
|
||||
_logger.Error(task.Exception);
|
||||
}
|
||||
|
||||
removals.Add(task);
|
||||
await task.WaitAsync(command.Timeout, _cancellationToken);
|
||||
}
|
||||
// .NET doesn't support modifying a collection you're iterating over
|
||||
foreach (var removal in removals)
|
||||
catch (Exception e)
|
||||
{
|
||||
_commandTasks.Remove(removal);
|
||||
_logger.Error("Caught an exception while waiting for the command to complete");
|
||||
_logger.Error(e);
|
||||
return;
|
||||
}
|
||||
if (task.IsFaulted)
|
||||
{
|
||||
_logger.Error("Command task failed");
|
||||
_logger.Error(task.Exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user