From ba1021c5e678bef1890d1412feec0223cd4c30de Mon Sep 17 00:00:00 2001 From: Guillermo Marcel Date: Wed, 26 Mar 2025 15:41:39 -0300 Subject: [PATCH] refactor: extract commands --- src/CasaBot/CasaBotApp/BotCommand.cs | 12 ++++ src/CasaBot/CasaBotApp/BotHandler.cs | 92 ++++++++++++++++++---------- src/CasaBot/CasaBotApp/Program.cs | 62 +++++++------------ 3 files changed, 95 insertions(+), 71 deletions(-) create mode 100644 src/CasaBot/CasaBotApp/BotCommand.cs diff --git a/src/CasaBot/CasaBotApp/BotCommand.cs b/src/CasaBot/CasaBotApp/BotCommand.cs new file mode 100644 index 0000000..392617c --- /dev/null +++ b/src/CasaBot/CasaBotApp/BotCommand.cs @@ -0,0 +1,12 @@ +using System.Net.Mime; +using Telegram.Bots.Types; + +namespace CasaBotApp; + +public class BotCommand +{ + public string Command { get; set; } = "/example"; + public string Description { get; set; } = "Start the bot"; + public Func>> Responder { get; set; } = (_, _) => Task.FromResult>(null); + public Func? Action { get; set; } +} \ No newline at end of file diff --git a/src/CasaBot/CasaBotApp/BotHandler.cs b/src/CasaBot/CasaBotApp/BotHandler.cs index 88b4a73..d3ed355 100644 --- a/src/CasaBot/CasaBotApp/BotHandler.cs +++ b/src/CasaBot/CasaBotApp/BotHandler.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using System.Text; using System.Xml.Schema; using Telegram.Bots; using Telegram.Bots.Extensions.Polling; @@ -14,6 +15,7 @@ public class BotHandler : IUpdateHandler private readonly ILogger _logger; private readonly TelegramOptions _telegramOptions; private readonly List _subscribers = []; + private readonly Dictionary _commands; private readonly IBotClient _bot; @@ -22,6 +24,27 @@ public class BotHandler : IUpdateHandler _logger = logger; _telegramOptions = telegramConfiguration.Value; _bot = bot; + _commands = []; + RegisterCommand(new() + { + Command = "/register", + Description = "Register to receive messages on every update", + Action = RegisterUser, + Responder = Respond + }); + RegisterCommand(new() + { + Command = "/photo", + Description = "Get a photo", + Action = SendImageTest, + Responder = Respond + }); + } + + public void RegisterCommand(BotCommand command) + { + command.Responder = Respond; + _commands[command.Command] = command; } @@ -149,11 +172,11 @@ public class BotHandler : IUpdateHandler } } - private async Task SendImageTest(long id) + private async Task SendImageTest(TextMessage msg, BotCommand _) { await using var stream = File.OpenRead(@"C:\Users\GuillermoMarcel\Pictures\prueba.jpeg"); - var send = new SendPhotoFile(id.ToString(), stream); + var send = new SendPhotoFile(msg.Chat.Id.ToString(), stream); await _bot.HandleAsync(send); } @@ -161,38 +184,43 @@ public class BotHandler : IUpdateHandler private async Task OnMessage(TextMessage msg) { - - switch (msg.Text) + if(!_commands.TryGetValue(msg.Text, out var command)) { - case "/register": - if (_subscribers.Any(c => c.Id == msg.Chat.Id)) - { - await Respond(msg, "You are already registered to receive messages"); - return; - } - - _subscribers.Add(msg.Chat); - _logger.LogInformation("User {User} ({id}) registered to receive messages", msg.Chat.FirstName, msg.Chat.Id); - await Respond(msg, "You are registered to receive messages every minute"); - - return; - - case "/photo": - await SendImageTest(msg.Chat.Id); - return; - - case "/soyandre": - await Respond(msg, "Hola vida, te amo mucho ❤️"); - return; - - default: - _logger.LogInformation("Received '{Text}' in {Chat}", msg.Text, msg.Chat); - - const string commands = - "Commands: \n/help to show the commands \n/register to get messages every minute \n/photo to get a photo \n/soyandre por si sos andre"; - await Respond(msg, commands); - break; + await SendHelp(msg); + return; } + + if (command?.Action is null) + { + _logger.LogError("Command {Command} has no action", msg.Text); + } + + await command!.Action!(msg, command); + } + + private async Task SendHelp(TextMessage msg) + { + _logger.LogInformation("Received '{Text}' in {Chat}", msg.Text, msg.Chat); + var message = new StringBuilder(); + message.AppendLine("Commands:"); + foreach (var command in _commands.Values) + { + message.AppendLine($"{command.Command} - {command.Description}"); + } + await Respond(msg, message.ToString()); + } + + private async Task RegisterUser(TextMessage msg, BotCommand _) + { + if (_subscribers.Any(c => c.Id == msg.Chat.Id)) + { + await Respond(msg, "You are already registered to receive messages"); + return; + } + + _subscribers.Add(msg.Chat); + _logger.LogInformation("User {User} ({id}) registered to receive messages", msg.Chat.FirstName, msg.Chat.Id); + await Respond(msg, "You are registered to receive messages every minute"); } diff --git a/src/CasaBot/CasaBotApp/Program.cs b/src/CasaBot/CasaBotApp/Program.cs index 5e845eb..cc59806 100644 --- a/src/CasaBot/CasaBotApp/Program.cs +++ b/src/CasaBot/CasaBotApp/Program.cs @@ -1,13 +1,14 @@ using AutoScan; using AutoScan.Options; using CasaBotApp; +using CasaBotApp.Extensions; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using Telegram.Bots; using Telegram.Bots.Extensions.Polling; +using Telegram.Bots.Http; var environment = Environment.GetEnvironmentVariable("CASABOT_ENVIRONMENT"); IConfigurationRoot configuration = new ConfigurationBuilder() @@ -20,18 +21,9 @@ var hostBuilder = new HostBuilder(); hostBuilder.ConfigureServices((_, services) => { services.AddSingleton(configuration); - services.AddLogging(builder => - { - builder.AddConfiguration(configuration.GetSection("Logging")); - //add time to logs - builder.AddSimpleConsole(options => - { - options.IncludeScopes = true; - options.SingleLine = true; - options.TimestampFormat = "[HH:mm:ss] "; - }); - }); - + + services.AddLogging(configuration); + services.Configure(configuration.GetSection("Telegram")); services.Configure(configuration.GetSection("AutoScan")); services.Configure(configuration.GetSection("Shinobi")); @@ -43,9 +35,20 @@ hostBuilder.ConfigureServices((_, services) => services.AddPolling(); services.AddSingleton(sp => sp.GetService()!); - + + // To get notifications when a retry is performed + services.AddAutoScan(); - services.AddHttpClient(); + + services.AddPolicyRegistry().Add("RetryPolicy", RetryPolicyExtension.GetRetryPolicy()); + services.AddHttpClient().AddPolicyHandler(RetryPolicyExtension.GetRetryPolicy()); + + + services.Configure(hostOptions => + { + hostOptions.BackgroundServiceExceptionBehavior = BackgroundServiceExceptionBehavior.Ignore; + }); + }); @@ -56,39 +59,20 @@ var logger = host.Services.GetService>()!; var botHandler = host.Services.GetService()!; var autoScanApp = host.Services.GetService()!; +CommandRegister.RegisterCommands(botHandler, autoScanApp); + using var cts = new CancellationTokenSource(); _ = autoScanApp.Run(cts.Token); botHandler.Start(cts.Token); -autoScanApp.OnScanCompleted = async options => -{ - logger.LogInformation("Scan completed at {At}", DateTime.Now); - try - { - //list all the images in the detection folder - if (options.Scanner?.DetectionFolder is null) - return; - var images = Directory.GetFiles(options.Scanner.DetectionFolder , "*.jpg"); - botHandler.Update($"Scan completed, found {images.Length} images"); - botHandler.UpdatePhotos(images); - }catch(Exception ex) - { - logger.LogError(ex, "Error while sending message"); - } - -}; - - -_ = host.RunAsync(cts.Token); +CommandRegister.UpdateOnScanCompleted(botHandler, autoScanApp, logger); logger.LogInformation("Bot started"); -logger.LogInformation("Press any key to stop the bot..."); -Console.ReadLine(); +await host.RunAsync(cts.Token); + await cts.CancelAsync(); // stop the bot -return; -