/// <summary> /// Informs a user that some of the Telegram Passport elements they provided contains errors. The user will /// not be able to re-submit their Passport to you until the errors are fixed (the contents of the field for /// which you returned the error must change). Returns True on success. /// Use this if the data submitted by the user doesn't satisfy the standards your service requires for /// any reason. For example, if a birthday date seems invalid, a submitted document is blurry, a scan shows /// evidence of tampering, etc. Supply some details in the error message to make sure the user knows how to /// correct the issues. /// </summary> /// <param name="botClient">Instance of bot client</param> /// <param name="userId">User identifier</param> /// <param name="errors">Descriptions of the errors</param> /// <param name="cancellationToken">The cancellation token to cancel operation.</param> /// <see href="https://core.telegram.org/bots/api#setpassportdataerrors"/> public static Task SetPassportDataErrorsAsync( this ITelegramBotClient botClient, int userId, IEnumerable <PassportElementError> errors, CancellationToken cancellationToken = default ) => botClient.MakeRequestAsync(new SetPassportDataErrorsRequest(userId, errors), cancellationToken);
private async Task <Update[]> GetUpdatesAsync(IEnumerable <UpdateType> allowedUpdates, int offset, CancellationToken cancellation = default) { var timeout = (int)_client.Timeout.TotalSeconds; return(await _client.MakeRequestAsync(new GetUpdatesRequest { Offset = offset, Timeout = timeout, AllowedUpdates = allowedUpdates, }, cancellation)); }
/// <summary> /// Starts receiving <see cref="Update"/>s on the ThreadPool, invoking <see cref="IUpdateHandler.HandleUpdate(ITelegramBotClient, Update, CancellationToken)"/> for each. /// <para>This method will block if awaited. GetUpdates will be called AFTER the <see cref="IUpdateHandler.HandleUpdate(ITelegramBotClient, Update, CancellationToken)"/> returns</para> /// </summary> /// <param name="botClient">The <see cref="ITelegramBotClient"/> used for making GetUpdates calls</param> /// <param name="updateHandler">The <see cref="IUpdateHandler"/> used for processing <see cref="Update"/>s</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> with which you can stop receiving</param> /// <returns></returns> public static async Task ReceiveAsync( this ITelegramBotClient botClient, IUpdateHandler updateHandler, CancellationToken cancellationToken = default) { if (botClient == null) { throw new ArgumentNullException(nameof(botClient)); } if (updateHandler == null) { throw new ArgumentNullException(nameof(updateHandler)); } UpdateType[]? allowedUpdates = updateHandler.AllowedUpdates; int messageOffset = 0; var emptyUpdates = new Update[] { }; while (!cancellationToken.IsCancellationRequested) { int timeout = (int)botClient.Timeout.TotalSeconds; var updates = emptyUpdates; try { updates = await botClient.MakeRequestAsync(new GetUpdatesRequest() { Offset = messageOffset, Timeout = timeout, AllowedUpdates = allowedUpdates, }, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { // Ignore } catch (Exception ex) { await updateHandler.HandleError(botClient, ex, cancellationToken) .ConfigureAwait(false); } foreach (var update in updates) { await updateHandler.HandleUpdate(botClient, update, cancellationToken) .ConfigureAwait(false); messageOffset = update.Id + 1; } } }
/// <summary>Send a request to the Bot API with retry policy in case if the request being timed out</summary> /// <typeparam name="TResponse">Type of expected result in the response object</typeparam> /// <param name="client">Bot client instance</param> /// <param name="request">API request object</param> /// <param name="cancellationToken"></param> /// <returns>Result of the API request</returns> public static Task <TResponse> MakeRequestWithRetryAsync <TResponse>( this ITelegramBotClient client, IRequest <TResponse> request, CancellationToken cancellationToken = default ) => Policy .Handle <ApiRequestException>(exception => exception.Message == "Request timed out") .WaitAndRetryAsync( new[] { TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(25), TimeSpan.FromSeconds(30), } ) .ExecuteAsync(_ => client.MakeRequestAsync(request, cancellationToken), cancellationToken);
/// <summary> /// /// </summary> /// <param name="client"></param> /// <param name="inlineMessageId"></param> /// <param name="text"></param> /// <param name="parseMode"></param> /// <param name="disableWebPagePreview"></param> /// <param name="replyMarkup"></param> /// <param name="entities"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public static Task EditMessageTextV2Async( this ITelegramBotClient client, string inlineMessageId, string text, ParseMode parseMode = default, bool disableWebPagePreview = default, InlineKeyboardMarkup replyMarkup = default, MessageEntity[] entities = default, CancellationToken cancellationToken = default ) => client.MakeRequestAsync(new SbEditInlineMessageTextRequest(inlineMessageId, text) { DisableWebPagePreview = disableWebPagePreview, ReplyMarkup = replyMarkup, ParseMode = parseMode, Entities = entities }, cancellationToken);
/// <summary> /// Will attempt to throw the last update using offset set to -1. /// </summary> /// <param name="botClient"></param> /// <param name="cancellationToken"></param> /// <returns> /// Update ID of the last <see cref="Update"/> increased by 1 if there were any /// </returns> internal static async Task <int> ThrowOutPendingUpdatesAsync( this ITelegramBotClient botClient, CancellationToken cancellationToken = default) { var request = new GetUpdatesRequest { Limit = 1, Offset = -1, Timeout = 0, AllowedUpdates = Array.Empty <UpdateType>(), }; var updates = await botClient.MakeRequestAsync(request : request, cancellationToken : cancellationToken) .ConfigureAwait(false); #if NETCOREAPP3_1_OR_GREATER if (updates.Length > 0) { return(updates[^ 1].Id + 1);
/// <summary> /// Yields <see cref="Update"/>s as they are received (or inside <see cref="PendingUpdates"/>). /// <para>GetUpdates will be called AFTER all the <see cref="Update"/>s are processed</para> /// </summary> /// <returns>An <see cref="IAsyncEnumerable{T}"/> of <see cref="Update"/></returns> public async IAsyncEnumerable <Update> YieldUpdatesAsync() { // Access to YieldUpdatesAsync is not thread-safe! while (!_cancellationToken.IsCancellationRequested) { while (_updateIndex < _updateArray.Length) { // It is vital that we increment before yielding _updateIndex++; yield return(_updateArray[_updateIndex - 1]); } _updateArray = EmptyUpdates; _updateIndex = 0; while (!_cancellationToken.IsCancellationRequested && _updateArray.Length == 0) { int timeout = (int)BotClient.Timeout.TotalSeconds; try { _updateArray = await BotClient.MakeRequestAsync(new GetUpdatesRequest() { Offset = _messageOffset, Timeout = timeout, AllowedUpdates = _allowedUpdates, }, _cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { // Ignore } catch (Exception ex) { if (errorHandler != null) { await errorHandler(ex, _cancellationToken).ConfigureAwait(false); } } } if (_updateArray.Length > 0) { _messageOffset = _updateArray[^ 1].Id + 1;
/// <summary> /// Use this method to send text messages. On success, the sent Description is returned. /// </summary> /// <param name="chatId"><see cref="ChatId"/> for the target chat</param> /// <param name="text">Text of the message to be sent</param> /// <param name="parseMode">Change, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot's message.</param> /// <param name="disableWebPagePreview">Disables link previews for links in this message</param> /// <param name="disableNotification">Sends the message silently. iOS users will not receive a notification, Android users will receive a notification with no sound.</param> /// <param name="replyToMessageId">If the message is a reply, ID of the original message</param> /// <param name="replyMarkup">Additional interface options. A JSON-serialized object for a custom reply keyboard, instructions to hide keyboard or to force a reply from the user.</param> /// <param name="entities">Optional. For text messages, special entities like usernames, URLs, bot commands, etc. that appear in the text.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param> /// <returns>On success, the sent Description is returned.</returns> /// <see href="https://core.telegram.org/bots/api#sendmessage"/> public static Task <Message> SendTextMessageV2Async( this ITelegramBotClient client, ChatId chatId, string text, ParseMode parseMode = default, bool disableWebPagePreview = default, bool disableNotification = default, int replyToMessageId = default, IReplyMarkup replyMarkup = default, MessageEntity[] entities = default, CancellationToken cancellationToken = default ) => client.MakeRequestAsync(new SbSendMessageRequest(chatId, text) { ParseMode = parseMode, DisableWebPagePreview = disableWebPagePreview, DisableNotification = disableNotification, ReplyToMessageId = replyToMessageId, ReplyMarkup = replyMarkup, Entities = entities }, cancellationToken);
private void StartReceivingInternal( UpdateType[]?allowedUpdates = default, Func <Exception, CancellationToken, Task>?errorHandler = default, CancellationToken cancellationToken = default) { Debug.Assert(IsReceiving); Task.Run(async() => { try { while (!cancellationToken.IsCancellationRequested) { int timeout = (int)BotClient.Timeout.TotalSeconds; var updates = EmptyUpdates; try { updates = await BotClient.MakeRequestAsync(new GetUpdatesRequest() { Offset = _messageOffset, Timeout = timeout, AllowedUpdates = allowedUpdates, }, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { // Ignore } catch (Exception ex) { if (errorHandler != null) { await errorHandler(ex, cancellationToken).ConfigureAwait(false); } } if (updates.Length > 0) { Interlocked.Add(ref _pendingUpdates, updates.Length); _messageOffset = updates[^ 1].Id + 1;
/// <inheritdoc /> public async Task ReceiveAsync( IUpdateHandler updateHandler, CancellationToken cancellationToken = default) { if (updateHandler is null) { throw new ArgumentNullException(nameof(updateHandler)); } var allowedUpdates = _receiverOptions?.AllowedUpdates; var limit = _receiverOptions?.Limit ?? default; var messageOffset = _receiverOptions?.Offset ?? 0; var emptyUpdates = EmptyUpdates; if (_receiverOptions?.ThrowPendingUpdates is true) { try { messageOffset = await _botClient.ThrowOutPendingUpdatesAsync( cancellationToken : cancellationToken ); } catch (OperationCanceledException) { // ignored } } while (!cancellationToken.IsCancellationRequested) { var timeout = (int)_botClient.Timeout.TotalSeconds; var updates = emptyUpdates; try { var request = new GetUpdatesRequest { Limit = limit, Offset = messageOffset, Timeout = timeout, AllowedUpdates = allowedUpdates, }; updates = await _botClient.MakeRequestAsync( request : request, cancellationToken : cancellationToken ).ConfigureAwait(false); } catch (OperationCanceledException) { // Ignore } catch (Exception exception) { try { await updateHandler.HandleErrorAsync( botClient : _botClient, exception : exception, cancellationToken : cancellationToken ).ConfigureAwait(false); } catch (OperationCanceledException) { // ignored } } foreach (var update in updates) { try { await updateHandler.HandleUpdateAsync( botClient : _botClient, update : update, cancellationToken : cancellationToken ).ConfigureAwait(false); messageOffset = update.Id + 1; } catch (OperationCanceledException) { // ignored } } } }
public Task <TResponse> MakeRequest <TResponse>(IRequest <TResponse> request, CancellationToken cancellationToken = default) { return(_botClient.MakeRequestAsync(request, cancellationToken)); }