From 1a8a999d5b2e4acd7d5439d4d9ed3e4d1999b8d1 Mon Sep 17 00:00:00 2001 From: Dmitri Shimanski Date: Wed, 19 Mar 2025 11:12:13 +0200 Subject: [PATCH] Create project --- .gitignore | 5 ++ Examples/Telegram.Examples/Program.cs | 14 +++ .../Telegram.Examples.csproj | 15 ++++ .../Telegram.Examples/UpdatePolling/Update.cs | 40 +++++++++ README.md | 90 +++++++++++++++++++ Telegram.Net.sln | 22 +++++ Telegram.Net/Attributes/CallbackAttribute.cs | 59 ++++++++++++ Telegram.Net/Attributes/CommandAttribute.cs | 59 ++++++++++++ .../Attributes/EditMessageAttribute.cs | 54 +++++++++++ Telegram.Net/Attributes/InlineAttribute.cs | 60 +++++++++++++ .../Attributes/PreCheckoutAttribute.cs | 50 +++++++++++ Telegram.Net/Attributes/UpdateAttribute.cs | 49 ++++++++++ Telegram.Net/Interfaces/ITelegramBotConfig.cs | 20 +++++ .../Interfaces/IUpdatePollingSerivce.cs | 9 ++ Telegram.Net/Models/TelegramBotConfig.cs | 17 ++++ Telegram.Net/ServiceBindings.cs | 14 +++ .../Services/TelegramHostedService.cs | 68 ++++++++++++++ Telegram.Net/Telegram.Net.csproj | 14 +++ 18 files changed, 659 insertions(+) create mode 100644 .gitignore create mode 100644 Examples/Telegram.Examples/Program.cs create mode 100644 Examples/Telegram.Examples/Telegram.Examples.csproj create mode 100644 Examples/Telegram.Examples/UpdatePolling/Update.cs create mode 100644 README.md create mode 100644 Telegram.Net.sln create mode 100644 Telegram.Net/Attributes/CallbackAttribute.cs create mode 100644 Telegram.Net/Attributes/CommandAttribute.cs create mode 100644 Telegram.Net/Attributes/EditMessageAttribute.cs create mode 100644 Telegram.Net/Attributes/InlineAttribute.cs create mode 100644 Telegram.Net/Attributes/PreCheckoutAttribute.cs create mode 100644 Telegram.Net/Attributes/UpdateAttribute.cs create mode 100644 Telegram.Net/Interfaces/ITelegramBotConfig.cs create mode 100644 Telegram.Net/Interfaces/IUpdatePollingSerivce.cs create mode 100644 Telegram.Net/Models/TelegramBotConfig.cs create mode 100644 Telegram.Net/ServiceBindings.cs create mode 100644 Telegram.Net/Services/TelegramHostedService.cs create mode 100644 Telegram.Net/Telegram.Net.csproj diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..add57be --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +bin/ +obj/ +/packages/ +riderModule.iml +/_ReSharper.Caches/ \ No newline at end of file diff --git a/Examples/Telegram.Examples/Program.cs b/Examples/Telegram.Examples/Program.cs new file mode 100644 index 0000000..ae1d2ca --- /dev/null +++ b/Examples/Telegram.Examples/Program.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.Hosting; +using Telegram.Net; + +var webHost = Host.CreateDefaultBuilder() + .ConfigureServices(k => + { + k.ConnectTelegram(new("YOUR-TOKEN") + { + errorHandler = async (client, exception, ctx) => + { + await Console.Out.WriteLineAsync(exception.Message); + } + }); + }); \ No newline at end of file diff --git a/Examples/Telegram.Examples/Telegram.Examples.csproj b/Examples/Telegram.Examples/Telegram.Examples.csproj new file mode 100644 index 0000000..1622ed8 --- /dev/null +++ b/Examples/Telegram.Examples/Telegram.Examples.csproj @@ -0,0 +1,15 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + + diff --git a/Examples/Telegram.Examples/UpdatePolling/Update.cs b/Examples/Telegram.Examples/UpdatePolling/Update.cs new file mode 100644 index 0000000..622baf1 --- /dev/null +++ b/Examples/Telegram.Examples/UpdatePolling/Update.cs @@ -0,0 +1,40 @@ +using Telegram.Bot; +using Telegram.Bot.Types; +using Telegram.Net.Attributes; +using Telegram.Net.Interfaces; + +namespace Telegram.Examples.UpdatePolling; + +public class Update : IUpdatePollingSerivce +{ + [Update] + public async Task UpdateExample(ITelegramBotClient client, Bot.Types.Update update, CancellationToken ctx) + { + if (update.Poll != null) + { + Console.WriteLine(update.Poll.IsClosed); + } + } + + [Callback("act-")] + public async Task CallbackExample(ITelegramBotClient client, CallbackQuery query, CancellationToken ctx) + { + Console.WriteLine(query.Message!.Text); + } + + [Command("/start")] + public async Task StartCommand(ITelegramBotClient client, Message message, CancellationToken ctx) + { + if (message.Text!.Contains(" ") && message.Text.Split(" ")[1] == "test") + await client.SendMessage(message.From!.Id, "Hello, I`m example bot. And this - command with subparam", cancellationToken: ctx); + else + await client.SendMessage(message.From!.Id, "Hello, I`m example bot.", cancellationToken: ctx); + } + + [EditMessage] + public async Task EditMessageExmaple(ITelegramBotClient client, Message message, CancellationToken ctx) + { + Console.WriteLine($"new message text: {message.Text}"); + } + +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..9d519e8 --- /dev/null +++ b/README.md @@ -0,0 +1,90 @@ +# Telegram Bot Attribute Handlers + +This project provides a set of C# attributes to facilitate the handling of different types of Telegram bot updates using reflection. + +## Features +- **Inline Query Handling** (`InlineAttribute`) +- **Edited Message Handling** (`EditMessageAttribute`) +- **Command Handling** (`CommandHandlerAttribute`) +- **Callback Query Handling** (`CallbackAttribute`) +- **PreCheckout Query Handling** (`PreCheckoutAttribute`) +- **General Update Handling** (`UpdateAttribute`) +- **Auto-generate telegram client** + +## Installation +Ensure you have the required dependencies installed: + +```sh + dotnet add package Telegram.Bot +``` + +## Usage + +### Inline Query Handling +Use the `InlineAttribute` to register a method as an inline query handler. + +```csharp +[Inline("example_query")] +public static async Task HandleInlineQuery(ITelegramBotClient bot, InlineQuery query, CancellationToken cancellationToken) +{ + // Handle inline query +} +``` + +### Edited Message Handling +Use the `EditMessageAttribute` to register a method as a handler for edited messages. + +```csharp +[EditMessage] +public static async Task HandleEditedMessage(ITelegramBotClient bot, Message message, CancellationToken cancellationToken) +{ + // Handle edited message +} +``` + +### Command Handling +Use the `CommandHandlerAttribute` to register a method as a command handler. +You can provide only begin of command text. Like, `/start act-` +```csharp +[CommandHandler("/start")] +public static async Task StartCommand(ITelegramBotClient bot, Message message, CancellationToken cancellationToken) +{ + // Handle start command +} +``` + +### Callback Query Handling +Use the `CallbackAttribute` to register a method as a callback query handler. +You can provide only begin of callback data text +```csharp +[Callback("button_click")] +public static async Task HandleCallbackQuery(ITelegramBotClient bot, CallbackQuery query, CancellationToken cancellationToken) +{ + // Handle callback query +} +``` + +### PreCheckout Query Handling +Use the `PreCheckoutAttribute` to register a method as a pre-checkout query handler. + +```csharp +[PreCheckout] +public static async Task HandlePreCheckoutQuery(ITelegramBotClient bot, PreCheckoutQuery query, CancellationToken cancellationToken) +{ + // Handle pre-checkout query +} +``` + +### General Update Handling +Use the `UpdateAttribute` to register a method as a generic update handler. + +```csharp +[Update] +public static async Task HandleUpdate(ITelegramBotClient bot, Update update, CancellationToken cancellationToken) +{ + // Handle general update +} +``` + +## License +This project is open-source and available under the MIT License. \ No newline at end of file diff --git a/Telegram.Net.sln b/Telegram.Net.sln new file mode 100644 index 0000000..362a68f --- /dev/null +++ b/Telegram.Net.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegram.Net", "Telegram.Net\Telegram.Net.csproj", "{137609A1-3482-465E-9B76-7E3F78FFC906}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegram.Examples", "Examples\Telegram.Examples\Telegram.Examples.csproj", "{073E66F2-F82E-4378-B390-C2364DFDC491}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {137609A1-3482-465E-9B76-7E3F78FFC906}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {137609A1-3482-465E-9B76-7E3F78FFC906}.Debug|Any CPU.Build.0 = Debug|Any CPU + {137609A1-3482-465E-9B76-7E3F78FFC906}.Release|Any CPU.ActiveCfg = Release|Any CPU + {137609A1-3482-465E-9B76-7E3F78FFC906}.Release|Any CPU.Build.0 = Release|Any CPU + {073E66F2-F82E-4378-B390-C2364DFDC491}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {073E66F2-F82E-4378-B390-C2364DFDC491}.Debug|Any CPU.Build.0 = Debug|Any CPU + {073E66F2-F82E-4378-B390-C2364DFDC491}.Release|Any CPU.ActiveCfg = Release|Any CPU + {073E66F2-F82E-4378-B390-C2364DFDC491}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/Telegram.Net/Attributes/CallbackAttribute.cs b/Telegram.Net/Attributes/CallbackAttribute.cs new file mode 100644 index 0000000..bc4f28e --- /dev/null +++ b/Telegram.Net/Attributes/CallbackAttribute.cs @@ -0,0 +1,59 @@ +using System.Reflection; +using Telegram.Bot; +using Telegram.Bot.Types; +using Telegram.Net.Interfaces; +using Telegram.Net.Services; + +namespace Telegram.Net.Attributes; + +/// +/// Attribute for registering callback query handlers in a Telegram bot. +/// +[AttributeUsage(AttributeTargets.Method)] +public class CallbackAttribute : Attribute +{ + public bool IsReusable => true; + public string QueryId { get; } + + /// + /// Initializes a new instance of the class, + /// registering methods marked with this attribute as callback query handlers. + /// + /// [Callback("auth-")] // You can use id like with StartsWith + /// public async Task PreCheckout(ITelegramBotClient client, CallbackQuery callback, CancellationToken ctx){ + /// Console.WriteLine(callback.Data); + /// } + /// + /// + /// The unique identifier for the callback query. + public CallbackAttribute(string queryId) + { + this.QueryId = queryId; + + var methods = typeof(IUpdatePollingSerivce).GetMethods() + .Where(m => m.GetCustomAttribute(this.GetType()) != null); + + foreach (var method in methods) + { + if (IsValidHandlerMethod(method)) + { + var attr = method.GetCustomAttribute(); + var handler = (Func) + Delegate.CreateDelegate(typeof(Func), null, + method); + + TelegramHostedService.CallbackQueryHandler.Add(attr!.QueryId, handler); + } + } + } + + static bool IsValidHandlerMethod(MethodInfo method) + { + var parameters = method.GetParameters(); + return method.ReturnType == typeof(Task) && + parameters.Length == 3 && + parameters[0].ParameterType == typeof(ITelegramBotClient) && + parameters[1].ParameterType == typeof(CallbackQuery) && + parameters[2].ParameterType == typeof(CancellationToken); + } +} \ No newline at end of file diff --git a/Telegram.Net/Attributes/CommandAttribute.cs b/Telegram.Net/Attributes/CommandAttribute.cs new file mode 100644 index 0000000..89c7072 --- /dev/null +++ b/Telegram.Net/Attributes/CommandAttribute.cs @@ -0,0 +1,59 @@ +using System.Reflection; +using Telegram.Bot; +using Telegram.Bot.Types; +using Telegram.Net.Interfaces; +using Telegram.Net.Services; + +namespace Telegram.Net.Attributes; + +/// +/// Attribute for registering command handlers in a Telegram bot. +/// +[AttributeUsage(AttributeTargets.Method)] +public class CommandAttribute : Attribute +{ + public bool IsReusable => true; + public string Command { get; set; } + + /// + /// Initializes a new instance of the class, + /// registering methods marked with this attribute as command handlers. + /// + /// [Command("/start")] // You can use it like with StartsWith + /// public async Task Start(ITelegramBotClient client, Message message, CancellationToken ctx){ + /// Console.WriteLine(message.Text); + /// } + /// + /// + /// The command to be handled. + public CommandAttribute(string command) + { + Command = command; + + var methods = typeof(IUpdatePollingSerivce).GetMethods() + .Where(m => m.GetCustomAttribute(this.GetType()) != null); + + foreach (var method in methods) + { + if (IsValidHandlerMethod(method)) + { + var attr = method.GetCustomAttribute(); + var handler = (Func) + Delegate.CreateDelegate(typeof(Func), null, + method); + + TelegramHostedService.CommandHandler.Add(attr!.Command, handler); + } + } + } + + static bool IsValidHandlerMethod(MethodInfo method) + { + var parameters = method.GetParameters(); + return method.ReturnType == typeof(Task) && + parameters.Length == 3 && + parameters[0].ParameterType == typeof(ITelegramBotClient) && + parameters[1].ParameterType == typeof(Message) && + parameters[2].ParameterType == typeof(CancellationToken); + } +} \ No newline at end of file diff --git a/Telegram.Net/Attributes/EditMessageAttribute.cs b/Telegram.Net/Attributes/EditMessageAttribute.cs new file mode 100644 index 0000000..0190c3c --- /dev/null +++ b/Telegram.Net/Attributes/EditMessageAttribute.cs @@ -0,0 +1,54 @@ +using System.Reflection; +using Telegram.Bot; +using Telegram.Bot.Types; +using Telegram.Net.Interfaces; +using Telegram.Net.Services; + +namespace Telegram.Net.Attributes; + +/// +/// Attribute for registering handlers for edited messages in a Telegram bot. +/// +[AttributeUsage(AttributeTargets.Method)] +public class EditMessageAttribute : Attribute +{ + public bool IsReusable => true; + + /// + /// Initializes a new instance of the class, + /// registering methods marked with this attribute as handlers for edited messages. + /// + /// [EditMessage] + /// public async Task EditMessage(ITelegramBotClient client, Message message, CancellationToken ctx){ + /// Console.WriteLine(message.Id); + /// } + /// + /// + public EditMessageAttribute() + { + var methods = typeof(IUpdatePollingSerivce).GetMethods() + .Where(m => m.GetCustomAttribute(this.GetType()) != null); + + foreach (var method in methods) + { + if (IsValidHandlerMethod(method)) + { + var handler = (Func) + Delegate.CreateDelegate(typeof(Func), null, + method); + + TelegramHostedService.EditedMessageHandler.Add(handler); + } + } + } + + static bool IsValidHandlerMethod(MethodInfo method) + { + var parameters = method.GetParameters(); + return method.ReturnType == typeof(Task) && + parameters.Length == 3 && + parameters[0].ParameterType == typeof(ITelegramBotClient) && + parameters[1].ParameterType == typeof(Message) && + parameters[2].ParameterType == typeof(CancellationToken); + } +} \ No newline at end of file diff --git a/Telegram.Net/Attributes/InlineAttribute.cs b/Telegram.Net/Attributes/InlineAttribute.cs new file mode 100644 index 0000000..bfaa31d --- /dev/null +++ b/Telegram.Net/Attributes/InlineAttribute.cs @@ -0,0 +1,60 @@ +using System.Reflection; +using Telegram.Bot; +using Telegram.Bot.Types; +using Telegram.Net.Interfaces; +using Telegram.Net.Services; + +namespace Telegram.Net.Attributes; + + +/// +/// Attribute for registering inline query handlers in a Telegram bot. +/// +[AttributeUsage(AttributeTargets.Method)] +public class InlineAttribute : Attribute +{ + public bool IsReusable => true; + public string InlineId { get; } + + + /// + /// Initializes a new instance of the class, + /// registering methods marked with this attribute as inline query handlers. + /// + /// [Inline("InlineId")] // You can use it like with StartsWith + /// public async Task Inline(ITelegramBotClient client, InlineQuery inline, CancellationToken ctx){ + /// Console.WriteLine(inline.From.Id); + /// } + /// + /// + /// Unique identifier for the inline query. + public InlineAttribute(string inlineId) + { + this.InlineId = inlineId; + var methods = typeof(IUpdatePollingSerivce).GetMethods() + .Where(m => m.GetCustomAttribute(this.GetType()) != null); + + foreach (var method in methods) + { + if (IsValidHandlerMethod(method)) + { + var attr = method.GetCustomAttribute(); + var handler = (Func) + Delegate.CreateDelegate(typeof(Func), null, + method); + + TelegramHostedService.InlineHandler.Add(attr!.InlineId, handler); + } + } + } + + static bool IsValidHandlerMethod(MethodInfo method) + { + var parameters = method.GetParameters(); + return method.ReturnType == typeof(Task) && + parameters.Length == 3 && + parameters[0].ParameterType == typeof(ITelegramBotClient) && + parameters[1].ParameterType == typeof(InlineQuery) && + parameters[2].ParameterType == typeof(CancellationToken); + } +} \ No newline at end of file diff --git a/Telegram.Net/Attributes/PreCheckoutAttribute.cs b/Telegram.Net/Attributes/PreCheckoutAttribute.cs new file mode 100644 index 0000000..924609c --- /dev/null +++ b/Telegram.Net/Attributes/PreCheckoutAttribute.cs @@ -0,0 +1,50 @@ +using System.Reflection; +using Telegram.Bot; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Payments; +using Telegram.Net.Interfaces; +using Telegram.Net.Services; + +namespace Telegram.Net.Attributes; + +/// +/// Attribute for pre checkout handler. Using: +/// +/// [PreCheckout] +/// public async Task PreCheckout(ITelegramBotClient client, PreCheckoutQuery preCheckout, CancellationToken ctx){ +/// Console.WriteLine(preCheckout.Id); +/// } +/// +/// +[AttributeUsage(AttributeTargets.Method)] +public class PreCheckoutAttribute : Attribute +{ + public bool IsReusable => true; + public PreCheckoutAttribute() + { + var methods = typeof(IUpdatePollingSerivce).GetMethods() + .Where(m => m.GetCustomAttribute(this.GetType()) != null); + + foreach (var method in methods) + { + if (IsValidHandlerMethod(method)) + { + var handler = (Func) + Delegate.CreateDelegate(typeof(Func), null, + method); + + TelegramHostedService.PreCheckoutHandler = (handler); + } + } + } + + static bool IsValidHandlerMethod(MethodInfo method) + { + var parameters = method.GetParameters(); + return method.ReturnType == typeof(Task) && + parameters.Length == 3 && + parameters[0].ParameterType == typeof(ITelegramBotClient) && + parameters[1].ParameterType == typeof(PreCheckoutQuery) && + parameters[2].ParameterType == typeof(CancellationToken); + } +} \ No newline at end of file diff --git a/Telegram.Net/Attributes/UpdateAttribute.cs b/Telegram.Net/Attributes/UpdateAttribute.cs new file mode 100644 index 0000000..597d53d --- /dev/null +++ b/Telegram.Net/Attributes/UpdateAttribute.cs @@ -0,0 +1,49 @@ +using System.Reflection; +using Telegram.Bot; +using Telegram.Bot.Types; +using Telegram.Net.Interfaces; +using Telegram.Net.Services; + +namespace Telegram.Net.Attributes; + +/// +/// Attribute for default update handler. Using: +/// +/// [Update] +/// public async Task UpdateHandler(ITelegramBotClient client, Update update, CancellationToken ctx){ +/// Console.WriteLine(Update.Message?.Text); +/// } +/// +/// +[AttributeUsage(AttributeTargets.Method)] +public class UpdateAttribute : Attribute +{ + public bool IsReusable => true; + public UpdateAttribute() + { + var methods = typeof(IUpdatePollingSerivce).GetMethods() + .Where(m => m.GetCustomAttribute(this.GetType()) != null); + + foreach (var method in methods) + { + if (IsValidHandlerMethod(method)) + { + var handler = (Func) + Delegate.CreateDelegate(typeof(Func), null, + method); + + TelegramHostedService.DefaultUpdateHandler.Add(handler); + } + } + } + + static bool IsValidHandlerMethod(MethodInfo method) + { + var parameters = method.GetParameters(); + return method.ReturnType == typeof(Task) && + parameters.Length == 3 && + parameters[0].ParameterType == typeof(ITelegramBotClient) && + parameters[1].ParameterType == typeof(Update) && + parameters[2].ParameterType == typeof(CancellationToken); + } +} \ No newline at end of file diff --git a/Telegram.Net/Interfaces/ITelegramBotConfig.cs b/Telegram.Net/Interfaces/ITelegramBotConfig.cs new file mode 100644 index 0000000..d928e70 --- /dev/null +++ b/Telegram.Net/Interfaces/ITelegramBotConfig.cs @@ -0,0 +1,20 @@ +using Telegram.Bot; +using Telegram.Bot.Polling; + +namespace Telegram.Net.Interfaces; + +public interface ITelegramBotConfig +{ + /// + /// Token of telegram bot. You can take it from @BotFather + /// + public string Token { internal get; init; } + /// + /// Custom error handler for bot. You can add custom logger or anything. + /// + public Func? errorHandler { get; init; } + /// + /// Custom receiver options + /// + public ReceiverOptions? ReceiverOptions { get; init; } +} \ No newline at end of file diff --git a/Telegram.Net/Interfaces/IUpdatePollingSerivce.cs b/Telegram.Net/Interfaces/IUpdatePollingSerivce.cs new file mode 100644 index 0000000..929a654 --- /dev/null +++ b/Telegram.Net/Interfaces/IUpdatePollingSerivce.cs @@ -0,0 +1,9 @@ +namespace Telegram.Net.Interfaces; + +/// +/// You should implement this interface in all your classes with update polling logic +/// +public interface IUpdatePollingSerivce +{ + +} \ No newline at end of file diff --git a/Telegram.Net/Models/TelegramBotConfig.cs b/Telegram.Net/Models/TelegramBotConfig.cs new file mode 100644 index 0000000..84fd5b7 --- /dev/null +++ b/Telegram.Net/Models/TelegramBotConfig.cs @@ -0,0 +1,17 @@ +using Telegram.Bot; +using Telegram.Bot.Polling; +using Telegram.Net.Interfaces; + +namespace Telegram.Net.Models; + +public class TelegramBotConfig : ITelegramBotConfig +{ + public TelegramBotConfig(string token) + { + Token = token; + } + + public string Token { get; init; } + public Func? errorHandler { get; init; } + public ReceiverOptions? ReceiverOptions { get; init; } +} \ No newline at end of file diff --git a/Telegram.Net/ServiceBindings.cs b/Telegram.Net/ServiceBindings.cs new file mode 100644 index 0000000..684733b --- /dev/null +++ b/Telegram.Net/ServiceBindings.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.DependencyInjection; +using Telegram.Net.Models; +using Telegram.Net.Services; + +namespace Telegram.Net; + +public static class ServiceBindings +{ + public static IServiceCollection ConnectTelegram(this IServiceCollection isc, TelegramBotConfig config) + { + isc.AddHostedService(k => new(config)); + return isc; + } +} \ No newline at end of file diff --git a/Telegram.Net/Services/TelegramHostedService.cs b/Telegram.Net/Services/TelegramHostedService.cs new file mode 100644 index 0000000..d1afc91 --- /dev/null +++ b/Telegram.Net/Services/TelegramHostedService.cs @@ -0,0 +1,68 @@ +using System.Diagnostics.CodeAnalysis; +using Microsoft.Extensions.Hosting; +using Telegram.Bot; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Payments; +using Telegram.Net.Interfaces; +#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously + +namespace Telegram.Net.Services; + +public class TelegramHostedService : IHostedService +{ + private TelegramBotClient Client { get; } + private ITelegramBotConfig Config { get; } + internal static Dictionary> CommandHandler { get; } = new(); + internal static List> EditedMessageHandler { get; } = new(); + internal static Dictionary> CallbackQueryHandler { get; } = new(); + internal static Dictionary> InlineHandler { get; } = new(); + internal static Func? PreCheckoutHandler { get; set; } + internal static List> DefaultUpdateHandler { get; } = new(); + + public TelegramHostedService(ITelegramBotConfig config) + { + Client = new TelegramBotClient(config.Token); + Config = config; + + } + + [SuppressMessage("ReSharper", "AsyncVoidLambda")] + public async Task StartAsync(CancellationToken cancellationToken) + { + Client.StartReceiving( + async (client, update, ctx) => + { + switch (update) + { + case { Message: { } message }: + await CommandHandler.FirstOrDefault(k => message.Text!.StartsWith(k.Key)).Value(client, message, cancellationToken); + break; + case { EditedMessage: { } message }: + EditedMessageHandler.ForEach(async k => await k(client, message, cancellationToken)); + break; + case { CallbackQuery: { } callbackQuery }: + await CallbackQueryHandler.FirstOrDefault(k => callbackQuery.Data!.StartsWith(k.Key)).Value(client, callbackQuery, cancellationToken); + break; + case { InlineQuery: { } inlineQuery }: + await InlineHandler.FirstOrDefault(k => inlineQuery.Id.StartsWith(k.Key)).Value(client, inlineQuery, cancellationToken); + break; + case {PreCheckoutQuery: { } preCheckoutQuery}: + if (PreCheckoutHandler != null) + await PreCheckoutHandler(client, preCheckoutQuery, cancellationToken); + break; + default: + DefaultUpdateHandler.ForEach(async k => await k(client, update, ctx)); + break; + } + + }, + Config.errorHandler ?? ((_, _, _) => Task.CompletedTask), + Config.ReceiverOptions, + cancellationToken); + } + + public async Task StopAsync(CancellationToken cancellationToken) + { + await Client.DropPendingUpdates(cancellationToken); + } +} \ No newline at end of file diff --git a/Telegram.Net/Telegram.Net.csproj b/Telegram.Net/Telegram.Net.csproj new file mode 100644 index 0000000..dd6a97e --- /dev/null +++ b/Telegram.Net/Telegram.Net.csproj @@ -0,0 +1,14 @@ + + + + net7.0 + enable + enable + + + + + + + +