From 1088037e5854ee37a082486ef8567e66e061e5e2 Mon Sep 17 00:00:00 2001 From: Sergey Gut Date: Sun, 28 Jan 2024 18:51:18 +0300 Subject: [PATCH] Initial webhook support --- Core/Controllers/Telegram.cs | 75 +++++++++++++++++++++++++++++++++++ Core/Core.csproj | 2 +- Core/Startup.cs | 10 ++++- Core/WebhookAspNetProvider.cs | 40 +++++++++++++++++++ 4 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 Core/Controllers/Telegram.cs create mode 100644 Core/WebhookAspNetProvider.cs diff --git a/Core/Controllers/Telegram.cs b/Core/Controllers/Telegram.cs new file mode 100644 index 0000000..21ac958 --- /dev/null +++ b/Core/Controllers/Telegram.cs @@ -0,0 +1,75 @@ +using BotFramework.Abstractions.UpdateProvider; +using BotFramework.Config; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using System.Threading.Tasks; +using Telegram.Bot; +using Telegram.Bot.Types; + +namespace Kruzya.TelegramBot.Core.Controllers +{ + [Route("/Telegram")] + public class Telegram : Controller + { + private const string SecretTokenHeader = "X-Telegram-Bot-Api-Secret-Token"; + + private readonly ILogger _logger; + private readonly ITelegramBotClient _client; + private readonly IUpdateTarget _updateTarget; + private readonly string _secretToken; + + public Telegram(ILogger logger, ITelegramBotClient client, IUpdateTarget updateTarget, IOptions config) + { + _logger = logger; + _client = client; + _updateTarget = updateTarget; + + _secretToken = config.Value.Webhook.SecretToken; + if (string.IsNullOrEmpty(_secretToken)) + { + _secretToken = null; + } + } + + [Route("/WebHook")] + [HttpPost] + public IActionResult Index() + { + if (_secretToken != null && !Request.Headers.ContainsKey(SecretTokenHeader)) + { + _logger.LogWarning("Someone tried push update without secret key in headers"); + return BadRequest(); + } + + var ok = (_secretToken == null || Request.Headers[SecretTokenHeader] == _secretToken); + if (!ok) + { + _logger.LogWarning("Someone tried push update with wrong secret key in headers"); + return BadRequest(); + } + + LaunchHandle(); + return Ok(); + } + + private void LaunchHandle() + { + try + { + var update = JsonConvert.DeserializeObject(Request.Body.ToString()); + if (update == null) + { + throw new System.Exception("Invalid request body"); + } + + _updateTarget.Push(update); + } + catch (System.Exception e) + { + _logger.LogError($"Error occured when handling a new update: {e}"); + } + } + } +} diff --git a/Core/Core.csproj b/Core/Core.csproj index 6413eea..1931408 100644 --- a/Core/Core.csproj +++ b/Core/Core.csproj @@ -8,7 +8,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Core/Startup.cs b/Core/Startup.cs index 672e552..3073ed4 100644 --- a/Core/Startup.cs +++ b/Core/Startup.cs @@ -13,6 +13,7 @@ using Microsoft.Extensions.Logging; using System.Collections.Concurrent; using Kruzya.TelegramBot.Core.Options; using Telegram.Bot.Types; +using BotFramework.Abstractions.UpdateProvider; namespace Kruzya.TelegramBot.Core; @@ -49,7 +50,8 @@ public class Startup services.AddSingleton(); services.AddSingleton(); - + services.AddSingleton(); + services.AddControllersWithViews(); services.AddSingleton>(); services.AddHostedService(); @@ -64,6 +66,12 @@ public class Startup // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { + app.UseRouting(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + _core.Modules.Configure(app, env); } } \ No newline at end of file diff --git a/Core/WebhookAspNetProvider.cs b/Core/WebhookAspNetProvider.cs new file mode 100644 index 0000000..fe13169 --- /dev/null +++ b/Core/WebhookAspNetProvider.cs @@ -0,0 +1,40 @@ +#nullable enable + +using BotFramework.Abstractions.UpdateProvider; +using BotFramework.Config; +using Microsoft.Extensions.Options; +using System.Threading; +using System.Threading.Tasks; +using Telegram.Bot; + +namespace Kruzya.TelegramBot.Core +{ + public class WebhookAspNetProvider : IWebhookProvider + { + private readonly ITelegramBotClient _client; + private readonly BotConfig _config; + private readonly string? _secretToken; + + public WebhookAspNetProvider(ITelegramBotClient client, IOptions config) + { + _client = client; + _config = config.Value; + + _secretToken = _config.Webhook.SecretToken; + if (string.IsNullOrWhiteSpace(_secretToken)) + { + _secretToken = null; + } + } + + public async Task StartAsync(CancellationToken token) + { + await _client.SetWebhookAsync(_config.Webhook.Url, secretToken: _secretToken, cancellationToken: token); + } + + public async Task StopAsync(CancellationToken token) + { + await _client.DeleteWebhookAsync(cancellationToken: token); + } + } +}