< Summary

Information
Class: TeleFlow.Telegram.Internal.TelegramLongPollingUpdateSource
Assembly: TeleFlow.Framework.LongPolling
File(s): /_/src/TeleFlow.Framework.LongPolling/Internal/TelegramLongPollingUpdateSource.cs
Line coverage
87%
Covered lines: 81
Uncovered lines: 12
Coverable lines: 93
Total lines: 253
Line coverage: 87%
Branch coverage
88%
Covered branches: 23
Total branches: 26
Branch coverage: 88.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
StartAsync()86.36%262280.32%
GetUpdateType()100%22100%
CreateRawOptions(...)100%11100%
GetElapsedMilliseconds(...)100%11100%
IsUpdateCancellation(...)100%22100%

File(s)

/_/src/TeleFlow.Framework.LongPolling/Internal/TelegramLongPollingUpdateSource.cs

#LineLine coverage
 1using System.Diagnostics.CodeAnalysis;
 2using Microsoft.Extensions.Logging;
 3using TeleFlow.Framework.Updates;
 4using TeleFlow.Telegram.Internal.Handlers;
 5
 6namespace TeleFlow.Telegram.Internal;
 7
 8[SuppressMessage(
 9    "Performance",
 10    "CA1812:Avoid uninstantiated internal classes",
 11    Justification = "The type is instantiated by dependency injection through AddLongPolling.")]
 12internal sealed partial class TelegramLongPollingUpdateSource : IUpdateSource
 13{
 14    private readonly ITelegramLongPollingClient _pollingClient;
 15    private readonly ITelegramClient _bot;
 16    private readonly TelegramBotIdentity _botIdentity;
 17    private readonly TelegramLongPollingOptions _options;
 18    private readonly TimeProvider _timeProvider;
 19    private readonly ILogger<TelegramLongPollingUpdateSource> _logger;
 20    private readonly IReadOnlyList<TelegramHandlerDescriptor> _handlerDescriptors;
 21
 22    public TelegramLongPollingUpdateSource(
 23        ITelegramLongPollingClient pollingClient,
 24        ITelegramClient bot,
 25        TelegramBotIdentity botIdentity,
 26        TelegramLongPollingOptions options,
 27        TimeProvider timeProvider,
 28        ILoggerFactory loggerFactory,
 29        IEnumerable<TelegramHandlerDescriptor> handlerDescriptors)
 30    {
 1731        ArgumentNullException.ThrowIfNull(pollingClient);
 1732        ArgumentNullException.ThrowIfNull(bot);
 1733        ArgumentNullException.ThrowIfNull(botIdentity);
 1734        ArgumentNullException.ThrowIfNull(options);
 1735        ArgumentNullException.ThrowIfNull(timeProvider);
 1736        ArgumentNullException.ThrowIfNull(loggerFactory);
 1737        ArgumentNullException.ThrowIfNull(handlerDescriptors);
 38
 1739        _pollingClient = pollingClient;
 1740        _bot = bot;
 1741        _botIdentity = botIdentity;
 1742        _options = options;
 1743        _timeProvider = timeProvider;
 1744        _logger = loggerFactory.CreateLogger<TelegramLongPollingUpdateSource>();
 1745        _handlerDescriptors = handlerDescriptors.ToArray();
 1746    }
 47
 48    public async Task StartAsync(
 49        Func<IUpdatePayload, CancellationToken, Task> updateHandler,
 50        CancellationToken cancellationToken = default)
 51    {
 1652        ArgumentNullException.ThrowIfNull(updateHandler);
 53
 1654        await _botIdentity.EnsureResolvedAsync(_bot, cancellationToken).ConfigureAwait(false);
 55
 1656        var allowedUpdates = TelegramAllowedUpdatesResolver.Resolve(_options.AllowedUpdates, _handlerDescriptors, _logge
 1657        var rawOptions = CreateRawOptions(allowedUpdates);
 1658        var connected = false;
 59
 1660        LogStarting(
 1661            _logger,
 1662            TelegramUpdateLogFormatter.FormatAllowedUpdates(allowedUpdates),
 1663            _options.TimeoutSeconds,
 1664            _options.Limit);
 65
 66        try
 67        {
 6868            await foreach (var item in _pollingClient.GetUpdatesAsync(rawOptions, cancellationToken).ConfigureAwait(fals
 69            {
 1970                if (!connected)
 71                {
 1672                    LogConnected(_logger);
 1673                    connected = true;
 74                }
 75
 1976                var update = item.Update;
 1977                var informationEnabled = _logger.IsEnabled(LogLevel.Information);
 1978                var errorEnabled = _logger.IsEnabled(LogLevel.Error);
 1979                var debugEnabled = _logger.IsEnabled(LogLevel.Debug);
 1980                string? updateType = null;
 481                string GetUpdateType() => updateType ??= TelegramUpdateLogFormatter.GetUpdateType(update);
 1982                var processingStarted = debugEnabled ? _timeProvider.GetTimestamp() : 0;
 83
 1984                if (informationEnabled)
 85                {
 286                    LogUpdateReceived(
 287                        _logger,
 288                        update.UpdateId,
 289                        GetUpdateType(),
 290                        item.BatchIndex,
 291                        item.BatchCount);
 92                }
 93
 94                try
 95                {
 1996                    await updateHandler(new TelegramUpdatePayload(update), cancellationToken).ConfigureAwait(false);
 1797                }
 298                catch (Exception exception) when (!IsUpdateCancellation(exception, cancellationToken))
 99                {
 1100                    if (errorEnabled)
 101                    {
 0102                        if (debugEnabled)
 103                        {
 0104                            LogUpdateProcessingFailedWithTiming(
 0105                                _logger,
 0106                                exception,
 0107                                update.UpdateId,
 0108                                GetUpdateType(),
 0109                                GetElapsedMilliseconds(processingStarted));
 110                        }
 111                        else
 112                        {
 0113                            LogUpdateProcessingFailed(
 0114                                _logger,
 0115                                exception,
 0116                                update.UpdateId,
 0117                                GetUpdateType());
 118                        }
 119                    }
 120
 1121                    throw;
 122                }
 123
 17124                await item.AcknowledgeAsync(CancellationToken.None).ConfigureAwait(false);
 125
 17126                if (informationEnabled)
 127                {
 1128                    LogUpdateProcessed(
 1129                        _logger,
 1130                        update.UpdateId,
 1131                        GetUpdateType());
 132                }
 133
 17134                if (debugEnabled)
 135                {
 1136                    LogUpdateProcessedWithTiming(
 1137                        _logger,
 1138                        update.UpdateId,
 1139                        GetUpdateType(),
 1140                        GetElapsedMilliseconds(processingStarted));
 141                }
 17142            }
 14143        }
 144        finally
 145        {
 16146            if (cancellationToken.IsCancellationRequested)
 147            {
 15148                LogStopped(_logger);
 149            }
 150        }
 14151    }
 152
 153    private TelegramRawLongPollingOptions CreateRawOptions(IReadOnlyList<string>? allowedUpdates)
 154    {
 16155        return new TelegramRawLongPollingOptions
 16156        {
 16157            TimeoutSeconds = _options.TimeoutSeconds,
 16158            Limit = _options.Limit,
 16159            AllowedUpdates = allowedUpdates,
 16160            Backoff = new TelegramRawLongPollingBackoffOptions
 16161            {
 16162                Enabled = _options.Backoff.Enabled,
 16163                MinDelay = _options.Backoff.MinDelay,
 16164                MaxDelay = _options.Backoff.MaxDelay,
 16165                Factor = _options.Backoff.Factor,
 16166                Jitter = _options.Backoff.Jitter
 16167            }
 16168        };
 169    }
 170
 171    private double GetElapsedMilliseconds(long startingTimestamp)
 172    {
 1173        return _timeProvider.GetElapsedTime(startingTimestamp).TotalMilliseconds;
 174    }
 175
 176    private static bool IsUpdateCancellation(Exception exception, CancellationToken cancellationToken)
 177    {
 2178        return exception is OperationCanceledException && cancellationToken.IsCancellationRequested;
 179    }
 180
 181    [LoggerMessage(
 182        EventId = 1,
 183        Level = LogLevel.Information,
 184        Message = "Starting Telegram long polling. allowed_updates={AllowedUpdates}, timeout={TimeoutSeconds}s, limit={L
 185    private static partial void LogStarting(
 186        ILogger logger,
 187        string allowedUpdates,
 188        int timeoutSeconds,
 189        int limit);
 190
 191    [LoggerMessage(
 192        EventId = 2,
 193        Level = LogLevel.Information,
 194        Message = "Telegram long polling connected.")]
 195    private static partial void LogConnected(ILogger logger);
 196
 197    [LoggerMessage(
 198        EventId = 3,
 199        Level = LogLevel.Information,
 200        Message = "Telegram update received. update_id={UpdateId}, type={UpdateType}, batch_index={BatchIndex}/{BatchCou
 201    private static partial void LogUpdateReceived(
 202        ILogger logger,
 203        long updateId,
 204        string updateType,
 205        int batchIndex,
 206        int batchCount);
 207
 208    [LoggerMessage(
 209        EventId = 4,
 210        Level = LogLevel.Error,
 211        Message = "Telegram update processing failed. update_id={UpdateId}, type={UpdateType}.")]
 212    private static partial void LogUpdateProcessingFailed(
 213        ILogger logger,
 214        Exception exception,
 215        long updateId,
 216        string updateType);
 217
 218    [LoggerMessage(
 219        EventId = 4,
 220        Level = LogLevel.Error,
 221        Message = "Telegram update processing failed. update_id={UpdateId}, type={UpdateType}, total_ms={TotalElapsedMil
 222    private static partial void LogUpdateProcessingFailedWithTiming(
 223        ILogger logger,
 224        Exception exception,
 225        long updateId,
 226        string updateType,
 227        double totalElapsedMilliseconds);
 228
 229    [LoggerMessage(
 230        EventId = 5,
 231        Level = LogLevel.Information,
 232        Message = "Telegram update processed. update_id={UpdateId}, type={UpdateType}.")]
 233    private static partial void LogUpdateProcessed(
 234        ILogger logger,
 235        long updateId,
 236        string updateType);
 237
 238    [LoggerMessage(
 239        EventId = 5,
 240        Level = LogLevel.Debug,
 241        Message = "Telegram update processed. update_id={UpdateId}, type={UpdateType}, total_ms={TotalElapsedMillisecond
 242    private static partial void LogUpdateProcessedWithTiming(
 243        ILogger logger,
 244        long updateId,
 245        string updateType,
 246        double totalElapsedMilliseconds);
 247
 248    [LoggerMessage(
 249        EventId = 6,
 250        Level = LogLevel.Information,
 251        Message = "Telegram long polling stopped.")]
 252    private static partial void LogStopped(ILogger logger);
 253}