Files
Telegrator/Telegrator.Hosting.Web/Polling/HostedUpdateWebhooker.cs
T

97 lines
3.6 KiB
C#
Raw Normal View History

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
2026-03-06 20:49:32 +04:00
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Hosting;
2025-07-24 23:19:59 +04:00
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using System.Text.Json;
2025-07-24 23:19:59 +04:00
using Telegram.Bot;
using Telegram.Bot.Types;
2025-07-24 23:19:59 +04:00
using Telegrator.MadiatorCore;
namespace Telegrator.Hosting.Web.Polling
{
/// <summary>
/// Service for receiving updates for Hosted telegram bots via Webhooks
/// </summary>
2025-07-24 23:19:59 +04:00
public class HostedUpdateWebhooker : IHostedService
{
private const string SecretTokenHeader = "X-Telegram-Bot-Api-Secret-Token";
2026-03-06 20:49:32 +04:00
private readonly IEndpointRouteBuilder _botHost;
2025-07-24 23:19:59 +04:00
private readonly ITelegramBotClient _botClient;
private readonly IUpdateRouter _updateRouter;
private readonly TelegratorWebOptions _options;
2025-07-24 23:19:59 +04:00
/// <summary>
/// Initiallizes new instance of <see cref="HostedUpdateWebhooker"/>
/// </summary>
/// <param name="botHost"></param>
/// <param name="botClient"></param>
/// <param name="updateRouter"></param>
/// <param name="options"></param>
/// <exception cref="ArgumentNullException"></exception>
2026-03-06 20:49:32 +04:00
public HostedUpdateWebhooker(IEndpointRouteBuilder botHost, ITelegramBotClient botClient, IUpdateRouter updateRouter, IOptions<TelegratorWebOptions> options)
2025-07-24 23:19:59 +04:00
{
if (string.IsNullOrEmpty(options.Value.WebhookUri))
throw new ArgumentNullException(nameof(options), "Option \"WebhookUrl\" must be set to subscribe for update recieving");
_botHost = botHost;
_botClient = botClient;
_updateRouter = updateRouter;
_options = options.Value;
}
/// <inheritdoc/>
2025-07-24 23:19:59 +04:00
public Task StartAsync(CancellationToken cancellationToken)
2025-08-04 04:27:04 +04:00
{
StartInternal(cancellationToken);
return Task.CompletedTask;
}
private async void StartInternal(CancellationToken cancellationToken)
2025-07-24 23:19:59 +04:00
{
string pattern = new UriBuilder(_options.WebhookUri).Path;
_botHost.MapPost(pattern, (Delegate)ReceiveUpdate);
2025-08-04 04:27:04 +04:00
await _botClient.SetWebhook(
2025-07-24 23:19:59 +04:00
url: _options.WebhookUri,
maxConnections: _options.MaxConnections,
2026-03-06 20:49:32 +04:00
allowedUpdates: _updateRouter.HandlersProvider.AllowedTypes,
2025-07-24 23:19:59 +04:00
dropPendingUpdates: _options.DropPendingUpdates,
2026-03-06 20:49:32 +04:00
secretToken: _options.SecretToken,
2025-08-04 04:27:04 +04:00
cancellationToken: cancellationToken);
2025-07-24 23:19:59 +04:00
}
/// <inheritdoc/>
2025-07-24 23:19:59 +04:00
public Task StopAsync(CancellationToken cancellationToken)
{
_botClient.DeleteWebhook(_options.DropPendingUpdates, cancellationToken);
return Task.CompletedTask;
}
private async Task<IResult> ReceiveUpdate(HttpContext ctx)
{
if (_options.SecretToken != null)
{
if (!ctx.Request.Headers.TryGetValue(SecretTokenHeader, out StringValues strings))
return Results.BadRequest();
string? secret = strings.SingleOrDefault();
if (secret == null)
return Results.BadRequest();
if (_options.SecretToken != secret)
return Results.StatusCode(401);
}
Update? update = await JsonSerializer.DeserializeAsync<Update>(ctx.Request.Body, JsonBotAPI.Options, ctx.RequestAborted);
if (update is not { Id: > 0 })
return Results.BadRequest();
await _updateRouter.HandleUpdateAsync(_botClient, update, ctx.RequestAborted);
return Results.Ok();
}
2025-07-24 23:19:59 +04:00
}
}