diff --git a/KfChatDotNetBot/Commands/AdminCommands.cs b/KfChatDotNetBot/Commands/AdminCommands.cs index 66d63b6..9c597f3 100644 --- a/KfChatDotNetBot/Commands/AdminCommands.cs +++ b/KfChatDotNetBot/Commands/AdminCommands.cs @@ -325,4 +325,95 @@ public class UnignoreCommand : ICommand await db.SaveChangesAsync(ctx); await botInstance.SendChatMessageAsync($"No longer ignoring {targetUser.KfUsername}", true); } +} + +public class SetAlmanacTextCommand : ICommand +{ + public List Patterns => [ + new Regex("^admin almanac set text (?.+)$") + ]; + + public string? HelpText => "Set the almanac text to whatever"; + public UserRight RequiredRight => UserRight.TrueAndHonest; + public TimeSpan Timeout => TimeSpan.FromSeconds(10); + + public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + CancellationToken ctx) + { + await Helpers.SetValue(BuiltIn.Keys.BotAlmanacText, arguments["text"].Value); + await botInstance.SendChatMessageAsync($"@{message.Author.Username}, updated text for the almanac shill", true); + } +} + +public class SetAlmanacIntervalCommand : ICommand +{ + public List Patterns => [ + new Regex("^admin almanac set interval (?.+)$") + ]; + + public string? HelpText => "Set the almanac interval to whatever in seconds"; + public UserRight RequiredRight => UserRight.TrueAndHonest; + public TimeSpan Timeout => TimeSpan.FromSeconds(10); + + public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + CancellationToken ctx) + { + var interval = Convert.ToInt32(arguments["interval"].Value); + if (interval < 300) + { + await botInstance.SendChatMessageAsync("Not going to let you use an interval below 300 seconds", true); + return; + } + await Helpers.SetValue(BuiltIn.Keys.BotAlmanacInterval, arguments["interval"].Value); + await botInstance.BotServices.AlmanacShill.StopShillTaskAsync(); + botInstance.BotServices.AlmanacShill.StartShillTask(); + await botInstance.SendChatMessageAsync($"@{message.Author.Username}, updated interval and restarted the shill task", true); + } +} +public class StopAlmanacCommand : ICommand +{ + public List Patterns => [ + new Regex("^admin almanac stop$") + ]; + + public string? HelpText => "Stop the almanac reminder"; + public UserRight RequiredRight => UserRight.TrueAndHonest; + public TimeSpan Timeout => TimeSpan.FromSeconds(10); + + public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + CancellationToken ctx) + { + if (!botInstance.BotServices.AlmanacShill.IsShillTaskRunning()) + { + await botInstance.SendChatMessageAsync("Looks like the task isn't even running", true); + return; + } + + await botInstance.BotServices.AlmanacShill.StopShillTaskAsync(); + await botInstance.SendChatMessageAsync("Asked it nicely to stop", true); + } +} + +public class StartAlmanacCommand : ICommand +{ + public List Patterns => [ + new Regex("^admin almanac start") + ]; + + public string? HelpText => "Start the almanac reminder"; + public UserRight RequiredRight => UserRight.TrueAndHonest; + public TimeSpan Timeout => TimeSpan.FromSeconds(10); + + public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + CancellationToken ctx) + { + if (botInstance.BotServices.AlmanacShill.IsShillTaskRunning()) + { + await botInstance.SendChatMessageAsync("Looks like the task is already running", true); + return; + } + + botInstance.BotServices.AlmanacShill.StartShillTask(); + await botInstance.SendChatMessageAsync("Asked it nicely to start", true); + } } \ No newline at end of file diff --git a/KfChatDotNetBot/Commands/MemeCommands.cs b/KfChatDotNetBot/Commands/MemeCommands.cs index f96b234..1ecfb15 100644 --- a/KfChatDotNetBot/Commands/MemeCommands.cs +++ b/KfChatDotNetBot/Commands/MemeCommands.cs @@ -239,4 +239,24 @@ public class LastStreamCommand : ICommand var username = await Helpers.GetValue(BuiltIn.Keys.TwitchBossmanJackUsername); await botInstance.SendChatMessageAsync($"{username.Value} last streamed on Twitch approximately {timespan.Humanize(precision: 2, minUnit: TimeUnit.Minute, maxUnit: TimeUnit.Hour)} ago at {agt:dddd h:mm tt} AGT", true); } +} + +public class AlmanacCommand : ICommand +{ + public List Patterns => [ + new Regex("^almanac", RegexOptions.IgnoreCase) + ]; + public string? HelpText => "Return details on how to submit almanac entries"; + 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 text = await Helpers.GetValue(BuiltIn.Keys.BotAlmanacText); + if (message.MessageRaw.Contains("almanac plain")) + { + await botInstance.SendChatMessageAsync($"@{user.KfUsername}, [plain]{text.Value}", true); + return; + } + await botInstance.SendChatMessageAsync($"@{user.KfUsername}, {text.Value}", true); + } } \ No newline at end of file diff --git a/KfChatDotNetBot/Services/AlmanacShill.cs b/KfChatDotNetBot/Services/AlmanacShill.cs new file mode 100644 index 0000000..b5a30cb --- /dev/null +++ b/KfChatDotNetBot/Services/AlmanacShill.cs @@ -0,0 +1,50 @@ +using KfChatDotNetBot.Settings; +using NLog; + +namespace KfChatDotNetBot.Services; + +public class AlmanacShill(ChatBot kfChatBot) : IDisposable +{ + private readonly Logger _logger = LogManager.GetCurrentClassLogger(); + private Task? _almanacShillTask; + private CancellationTokenSource _almanacShillCts = new(); + + private async Task AlmanacShillTask() + { + var interval = await Helpers.GetValue(BuiltIn.Keys.BotAlmanacInterval); + using var timer = new PeriodicTimer(TimeSpan.FromSeconds(Convert.ToInt32(interval.Value))); + while (await timer.WaitForNextTickAsync(_almanacShillCts.Token)) + { + _logger.Info("Time to shill the almanac in chat"); + var text = await Helpers.GetValue(BuiltIn.Keys.BotAlmanacText); + await kfChatBot.SendChatMessageAsync($":!: {text.Value}", true); + } + } + + public bool IsShillTaskRunning() + { + if (_almanacShillTask == null) return false; + if (_almanacShillTask.Status != TaskStatus.Running) return false; + if (_almanacShillCts.IsCancellationRequested) return false; + return true; + } + + public async Task StopShillTaskAsync() + { + await _almanacShillCts.CancelAsync(); + _almanacShillTask?.Dispose(); + } + + public void StartShillTask() + { + _almanacShillCts = new CancellationTokenSource(); + _almanacShillTask = Task.Run(AlmanacShillTask, _almanacShillCts.Token); + } + + public void Dispose() + { + _almanacShillCts.Cancel(); + _almanacShillTask?.Dispose(); + GC.SuppressFinalize(this); + } +} \ No newline at end of file diff --git a/KfChatDotNetBot/Services/BotServices.cs b/KfChatDotNetBot/Services/BotServices.cs index a0d5e67..280517a 100644 --- a/KfChatDotNetBot/Services/BotServices.cs +++ b/KfChatDotNetBot/Services/BotServices.cs @@ -28,6 +28,7 @@ public class BotServices private Rainbet _rainbet; private Chipsgg _chipsgg; private Clashgg _clashgg; + public AlmanacShill AlmanacShill; private Task? _websocketWatchdog; private Task? _howlggGetUserTimer; @@ -71,7 +72,8 @@ public class BotServices BuildChipsgg(), BuildKick(), BuildTwitch(), - BuildClashgg() + BuildClashgg(), + BuildAlmanacShill() ]; try { @@ -240,6 +242,13 @@ public class BotServices await _twitchChat.StartWsClient(); } + private async Task BuildAlmanacShill() + { + AlmanacShill = new AlmanacShill(_chatBot); + AlmanacShill.StartShillTask(); + _logger.Info("Built the almanac shill task"); + } + private async Task WebsocketWatchdog() { using var timer = new PeriodicTimer(TimeSpan.FromSeconds(10)); diff --git a/KfChatDotNetBot/Settings/BuiltIn.cs b/KfChatDotNetBot/Settings/BuiltIn.cs index 317834f..8d15b55 100644 --- a/KfChatDotNetBot/Settings/BuiltIn.cs +++ b/KfChatDotNetBot/Settings/BuiltIn.cs @@ -890,6 +890,26 @@ public static class BuiltIn IsSecret = false, CacheDuration = TimeSpan.FromHours(1), ValueType = SettingValueType.Array + }, + new BuiltInSettingsModel + { + Key = Keys.BotAlmanacText, + Regex = ".+", + Description = "Text to send when reminding people of the Almanac", + Default = "Placeholder text for the Almanac", + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1), + ValueType = SettingValueType.Text + }, + new BuiltInSettingsModel + { + Key = Keys.BotAlmanacInterval, + Regex = @"\d+", + Description = "Interval for Almanac reminders in seconds", + Default = "14400", // 4 hours + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1), + ValueType = SettingValueType.Text } ]; @@ -964,5 +984,7 @@ public static class BuiltIn public static string BotKeesSeen = "Bot.KeesSeen"; public static string ClashggEnabled = "Clashgg.Enabled"; public static string ClashggBmjIds = "Clashgg.BmjIds"; + public static string BotAlmanacText = "Bot.Almanac.Text"; + public static string BotAlmanacInterval = "Bot.Almanac.Interval"; } } \ No newline at end of file