74 lines
2.3 KiB
C#
74 lines
2.3 KiB
C#
using Telegram.Bot;
|
|
using Telegram.Bot.Types;
|
|
using Telegram.Bot.Types.Enums;
|
|
|
|
namespace GmRelay.Bot.Infrastructure.Telegram;
|
|
|
|
/// <summary>
|
|
/// Long polling loop for Telegram Bot API.
|
|
/// Stateless — all state is in PostgreSQL. Safe to restart at any time.
|
|
/// </summary>
|
|
public sealed class TelegramBotService(
|
|
ITelegramBotClient bot,
|
|
UpdateRouter router,
|
|
ILogger<TelegramBotService> logger) : BackgroundService
|
|
{
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
{
|
|
logger.LogInformation("Telegram bot polling started");
|
|
|
|
// Skip any pending updates from before this startup
|
|
try
|
|
{
|
|
var pending = await bot.GetUpdates(offset: -1, limit: 1, cancellationToken: stoppingToken);
|
|
if (pending.Length > 0)
|
|
{
|
|
logger.LogInformation("Skipped {Count} pending update(s)", pending[^1].Id);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.LogWarning(ex, "Failed to clear pending updates, continuing anyway");
|
|
}
|
|
|
|
var offset = 0;
|
|
|
|
while (!stoppingToken.IsCancellationRequested)
|
|
{
|
|
try
|
|
{
|
|
var updates = await bot.GetUpdates(
|
|
offset: offset,
|
|
timeout: 30,
|
|
allowedUpdates: [UpdateType.Message, UpdateType.CallbackQuery],
|
|
cancellationToken: stoppingToken);
|
|
|
|
foreach (var update in updates)
|
|
{
|
|
try
|
|
{
|
|
await router.RouteAsync(update, stoppingToken);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.LogError(ex, "Error handling update {UpdateId}", update.Id);
|
|
}
|
|
|
|
offset = update.Id + 1;
|
|
}
|
|
}
|
|
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
|
|
{
|
|
break;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.LogError(ex, "Polling error, retrying in 5s");
|
|
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
|
|
}
|
|
}
|
|
|
|
logger.LogInformation("Telegram bot polling stopped");
|
|
}
|
|
}
|