using Telegram.Bot;
using Telegram.Bot.Polling;
using Telegram.Bot.Requests;
using Telegram.Bot.Types;
namespace Telegrator.Polling
{
///
/// Reactive implementation of for polling updates from Telegram.
/// Provides custom update receiving logic with error handling and configuration options.
///
/// The Telegram bot client for making API requests.
/// Optional receiver options for configuring update polling behavior.
public class ReactiveUpdateReceiver(ITelegramBotClient client, ReceiverOptions? options) : IUpdateReceiver
{
///
/// Gets the receiver options for configuring update polling behavior.
///
public readonly ReceiverOptions? Options = options;
///
/// Gets the Telegram bot client for making API requests.
///
public readonly ITelegramBotClient Client = client;
///
/// Receives updates from Telegram using long polling.
/// Handles update processing, error handling, and cancellation.
///
/// The update handler to process received updates.
/// The cancellation token to stop receiving updates.
/// A task representing the asynchronous update receiving operation.
public async Task ReceiveAsync(IUpdateHandler updateHandler, CancellationToken cancellationToken)
{
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken).Token;
GetUpdatesRequest request = new GetUpdatesRequest()
{
AllowedUpdates = Options?.AllowedUpdates ?? [],
Limit = Options?.Limit.GetValueOrDefault(100),
Offset = Options?.Offset
};
if (Options?.DropPendingUpdates ?? false)
{
try
{
Update[] array = await Client.GetUpdates(-1, 1, 0, [], cancellationToken).ConfigureAwait(false);
request.Offset = array.Length != 0 ? array[^1].Id + 1 : 0;
}
catch (OperationCanceledException)
{
return;
}
}
while (!cancellationToken.IsCancellationRequested)
{
try
{
request.Timeout = (int)Client.Timeout.TotalSeconds;
foreach (Update update in await Client.SendRequest(request, cancellationToken).ConfigureAwait(false))
{
try
{
request.Offset = update.Id + 1;
await updateHandler.HandleUpdateAsync(Client, update, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
}
catch (Exception exception2)
{
await updateHandler.HandleErrorAsync(Client, exception2, HandleErrorSource.HandleUpdateError, cancellationToken).ConfigureAwait(false);
}
}
}
catch (OperationCanceledException)
{
return;
}
catch (Exception exception)
{
await updateHandler.HandleErrorAsync(Client, exception, HandleErrorSource.PollingError, cancellationToken).ConfigureAwait(false);
}
}
}
}
}