* Added StartReceiving method as ITelegratoBot interface member

* Added missing summaries
* Fixed compiler warning and infos
* Code cleanup and bugfixes
This commit is contained in:
gutii
2026-04-27 22:13:47 +04:00
parent 5433a2de0d
commit 96b3241716
21 changed files with 379 additions and 68 deletions
@@ -13,7 +13,7 @@ using Telegrator.Hosting.Web;
namespace Telegrator.Mediation;
/// <summary>
/// Service for receiving updates for Hosted telegram bots via Webhooks
/// Service for receiving updates for Hosted telegram bots via Webhooks and queuing them to router
/// </summary>
public class HostedUpdateWebhooker : IHostedService
{
@@ -99,8 +99,15 @@ public static class WebHostBuilderExtensions
/// </summary>
public static class WebServicesCollectionExtensions
{
/// <summary>
/// Adds WebhookerOptions to services
/// </summary>
/// <param name="services"></param>
/// <param name="options"></param>
/// <returns></returns>
public static IServiceCollection ConfigureWebhooker(this IServiceCollection services, WebhookerOptions options)
{
services.RemoveAll<IOptions<WebhookerOptions>>();
services.AddSingleton(Options.Create(options));
return services;
}
@@ -176,6 +183,9 @@ public static class WebTelegramBotHostExtensions
/// <returns></returns>
public static IServiceCollection AddTelegramWebhook(this IServiceCollection services)
{
services.RemoveAll<IOptions<HostedUpdateWebhooker>>();
services.RemoveAll<ITelegramBotClient>();
services.AddHttpClient<ITelegramBotClient>("tgwebhook").RemoveAllLoggers().AddTypedClient(TypedTelegramBotClientFactory);
services.AddHostedService<HostedUpdateWebhooker>();
return services;
@@ -6,3 +6,5 @@
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Roslynator", "RCS1037")]
[assembly: SuppressMessage("Style", "IDE0090")]
[assembly: SuppressMessage("Style", "IDE0270")]
@@ -1,18 +1,22 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Threading;
using System.Threading.Tasks;
using Telegram.Bot;
using Telegram.Bot.Polling;
using Telegrator.Core;
namespace Telegrator.Mediation;
//Hosting.WideBot
/// <summary>
/// Service for receiving updates for Hosted wide telegram bots and queuing them to router
/// </summary>
/// <param name="logger"></param>
/// <param name="botClient"></param>
/// <param name="updateRouter"></param>
/// <param name="options"></param>
public class HostedWideBotUpdateReceiver(ILogger<HostedWideBotUpdateReceiver> logger, ITelegramBotClient botClient, IUpdateRouter updateRouter, IOptions<ReceiverOptions>? options) : BackgroundService
{
/// <inheritdoc/>
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
if (botClient is not WTelegramBotClient wideBotClient)
@@ -8,12 +8,19 @@ using WUpdate = WTelegram.Types.Update;
namespace Telegrator.Mediation;
/// <summary>
/// Reactive implementation of <see cref="IUpdateReceiver"/> for polling updates from Telegram.
/// Provides custom update receiving logic with error handling and configuration options.
/// </summary>
/// <param name="client">The Telegram bot client for making API requests.</param>
// <param name="options">Optional receiver options for configuring update polling behavior.</param>
public class WideUpdateReceiver(WTelegramBotClient client) : IUpdateReceiver
{
private readonly WTelegramBotClient _client = client;
private IUpdateHandler? _updateHandler = null;
private CancellationToken _cancellation = default;
/// <inheritdoc/>
public async Task ReceiveAsync(IUpdateHandler updateHandler, CancellationToken cancellationToken = default)
{
_updateHandler = updateHandler;
@@ -13,18 +13,33 @@ using Telegrator.States;
namespace Telegrator;
/// <summary>
/// Client class for the Telegrator library with Wider functionality, provided by WTelegramBotClient.
/// Extends TelegramBotClient with reactive capabilities for handling updates.
/// </summary>
public class TelegratorWClient : WTelegramBotClient, ITelegratorBot, ICollectingProvider
{
private IUpdateRouter? _updateRouter = null;
/// <inheritdoc/>
public TelegratorOptions Options { get; }
/// <inheritdoc/>
public IHandlersCollection Handlers { get; }
/// <inheritdoc/>
public ITelegramBotInfo BotInfo { get; }
/// <inheritdoc/>
public IUpdateRouter UpdateRouter => _updateRouter ?? throw new InvalidOperationException("Router's not created yet. Invoke `StartReceiving` to initialize this property.");
/// <summary>
/// Initializes new instance of <see cref="TelegratorWClient"/>
/// </summary>
/// <param name="wOptions"></param>
/// <param name="telegratorOptions"></param>
/// <param name="httpClient"></param>
/// <param name="cancellationToken"></param>
public TelegratorWClient(WTelegramBotClientOptions wOptions, TelegratorOptions? telegratorOptions = null, HttpClient? httpClient = null, CancellationToken cancellationToken = default)
: base(wOptions, httpClient, cancellationToken)
{
@@ -33,7 +48,8 @@ public class TelegratorWClient : WTelegramBotClient, ITelegratorBot, ICollecting
BotInfo = new TelegramBotInfo(GetMe(cancellationToken).Result);
}
public void StartReceiving(CancellationToken cancellationToken = default)
/// <inheritdoc/>
public void StartReceiving(ReceiverOptions? _, CancellationToken cancellationToken = default)
{
if (Options.GlobalCancellationToken == CancellationToken.None)
Options.GlobalCancellationToken = cancellationToken;
@@ -45,10 +61,27 @@ public class TelegratorWClient : WTelegramBotClient, ITelegratorBot, ICollecting
_updateRouter = new UpdateRouter(handlerProvider, awaitingProvider, stateStorage, Options, BotInfo);
TelegratorLogging.LogInformation($"TelegratorW bot starting up - BotId: {BotInfo.User.Id}, Username: {BotInfo.User.Username}");
StartReceivingInternal(Options.GlobalCancellationToken);
StartReceivingInternal(Options.GlobalCancellationToken)
.ConfigureAwait(false).GetAwaiter().GetResult();
}
private async void StartReceivingInternal(CancellationToken cancellationToken)
/// <inheritdoc/>
public async Task StartReceivingAsync(ReceiverOptions? receiverOptions = null,CancellationToken cancellationToken = default)
{
if (Options.GlobalCancellationToken == CancellationToken.None)
Options.GlobalCancellationToken = cancellationToken;
HandlersProvider handlerProvider = new HandlersProvider(Handlers, Options);
AwaitingProvider awaitingProvider = new AwaitingProvider(Options);
DefaultStateStorage stateStorage = new DefaultStateStorage();
_updateRouter = new UpdateRouter(handlerProvider, awaitingProvider, stateStorage, Options, BotInfo);
TelegratorLogging.LogInformation($"TelegratorW bot starting up - BotId: {BotInfo.User.Id}, Username: {BotInfo.User.Username}");
await StartReceivingInternal(Options.GlobalCancellationToken);
}
private async Task StartReceivingInternal(CancellationToken cancellationToken)
{
try
{
@@ -13,15 +13,21 @@ using Telegrator.Hosting;
using Telegrator.Mediation;
using Telegrator.Providers;
using TLUpdate = TL.Update;
using WUpdate = WTelegram.Types.Update;
using TLUpdate = TL.Update;
namespace Telegrator;
/// <summary>
/// Provides extensions memebrs for <see cref="UpdateHandlerBase"/> for easy access to Wider bot functions and update
/// </summary>
public static class HandlersExtensions
{
extension<TUpdate>(AbstractUpdateHandler<TUpdate> handler) where TUpdate : class
{
/// <summary>
/// Casts Update to <see cref="WTelegramBotClient"/>
/// </summary>
public WTelegramBotClient WClient
{
get
@@ -35,6 +41,9 @@ public static class HandlersExtensions
}
/// <summary>
/// Casts Update to <see cref="WUpdate"/>
/// </summary>
public WUpdate WideUpdate
{
get
@@ -47,18 +56,27 @@ public static class HandlersExtensions
}
}
/// <summary>
/// Casts Update to <see cref="TLUpdate"/>
/// </summary>
public TLUpdate? TLUpdate
{
get => handler.WideUpdate.TLUpdate;
}
}
/// <summary>
/// Casts Update to <see cref="WTelegramBotClient"/>
/// </summary>
public static WTelegramBotClient AsWClient(this ITelegramBotClient client)
{
return client as WTelegramBotClient
?? throw new InvalidCastException("Client is not assignable to `WTelegram.Bot.WTelegramBotClient`");
}
/// <summary>
/// Casts Update to <see cref="WUpdate"/>
/// </summary>
public static WUpdate AsWUpdate(this Update update)
{
return update as WUpdate
@@ -149,20 +167,45 @@ public static class WideHostBuilderExtensions
/// </summary>
public static class WideBotServiceCollectionExtensions
{
/// <summary>
/// Adds WTelegramBotClientOptions to services
/// </summary>
/// <param name="services"></param>
/// <param name="options"></param>
/// <returns></returns>
public static IServiceCollection ConfigureWideTelegram(this IServiceCollection services, WTelegramBotClientOptions options)
{
services.RemoveAll<IOptions<WTelegramBotClientOptions>>();
services.AddSingleton(Options.Create(options));
return services;
}
public static IServiceCollection AddMTProtoUpdateReceiver(this IServiceCollection services)
/// <summary>
/// Adds WTelegramBotClient
/// </summary>
/// <param name="services"></param>
/// <param name="useHttp"></param>
/// <returns></returns>
public static IServiceCollection AddMTProtoUpdateReceiver(this IServiceCollection services, bool useHttp = false)
{
services.AddHttpClient<WTelegramBotClient>("tgmtproto").RemoveAllLoggers().AddTypedClient(TypedTelegramBotClientFactory);
services.RemoveAll<ITelegramBotClient>();
services.RemoveAll<HostedWideBotUpdateReceiver>();
if (useHttp)
{
services.AddHttpClient<WTelegramBotClient>("tgmtproto").RemoveAllLoggers().AddTypedClient(TypedTelegramBotClientFactory);
}
else
{
services.AddSingleton(TypedTelegramBotClientFactory);
}
services.AddSingleton<ITelegramBotClient>(sp => sp.GetRequiredService<WTelegramBotClient>());
services.AddHostedService<HostedWideBotUpdateReceiver>();
return services;
}
#pragma warning disable CA2254
private static WTelegramBotClient TypedTelegramBotClientFactory(HttpClient httpClient, IServiceProvider provider)
{
ILogger<WTelegramBotClient> logger = provider.GetRequiredService<ILogger<WTelegramBotClient>>();
@@ -171,6 +214,16 @@ public static class WideBotServiceCollectionExtensions
WTelegram.Helpers.Log = (lvl, str) => logger.Log((LogLevel)lvl, str);
return client;
}
private static WTelegramBotClient TypedTelegramBotClientFactory(IServiceProvider provider)
{
ILogger<WTelegramBotClient> logger = provider.GetRequiredService<ILogger<WTelegramBotClient>>();
WTelegramBotClient client = new WTelegramBotClient(provider.GetRequiredService<IOptions<WTelegramBotClientOptions>>().Value);
WTelegram.Helpers.Log = (lvl, str) => logger.Log((LogLevel)lvl, str);
return client;
}
#pragma warning restore CA2254
}
/// <summary>
@@ -1,9 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Telegrator;
public class WideReceiverOptions
{
}
@@ -8,7 +8,7 @@ using Telegrator.Core;
namespace Telegrator.Mediation;
/// <summary>
/// Service for receiving updates for Hosted telegram bots
/// Service for receiving updates for Hosted telegram botsand queuing them to router
/// </summary>
/// <param name="botClient"></param>
/// <param name="updateRouter"></param>
+17
View File
@@ -129,14 +129,28 @@ public static class HostBuilderExtensions
/// </summary>
public static class HostServicesCollectionExtensions
{
/// <summary>
/// Adds TelegramBotClientOptions to services
/// </summary>
/// <param name="services"></param>
/// <param name="options"></param>
/// <returns></returns>
public static IServiceCollection ConfigureTelegram(this IServiceCollection services, TelegramBotClientOptions options)
{
services.RemoveAll<IOptions<TelegramBotClientOptions>>();
services.AddSingleton(Options.Create(options));
return services;
}
/// <summary>
/// Adds ReceiverOptions to services
/// </summary>
/// <param name="services"></param>
/// <param name="options"></param>
/// <returns></returns>
public static IServiceCollection ConfigureReceiver(this IServiceCollection services, ReceiverOptions options)
{
services.RemoveAll<IOptions<ReceiverOptions>>();
services.AddSingleton(Options.Create(options));
return services;
}
@@ -176,6 +190,9 @@ public static class HostServicesCollectionExtensions
/// <returns></returns>
public static IServiceCollection AddTelegramReceiver(this IServiceCollection services)
{
services.RemoveAll<ITelegramBotClient>();
services.RemoveAll<HostedUpdateReceiver>();
services.AddHttpClient<ITelegramBotClient>("tgreceiver").RemoveAllLoggers().AddTypedClient(TypedTelegramBotClientFactory);
services.AddHostedService<HostedUpdateReceiver>();
return services;
+1
View File
@@ -10,3 +10,4 @@ using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Style", "IDE0057")]
[assembly: SuppressMessage("Style", "IDE0270")]
[assembly: SuppressMessage("Roslynator", "RCS1037")]
[assembly: SuppressMessage("Roslynator", "RCS1227")]
+10 -1
View File
@@ -1,4 +1,5 @@
using Telegrator.Core;
using Telegram.Bot.Polling;
using Telegrator.Core;
namespace Telegrator;
@@ -12,4 +13,12 @@ public interface ITelegratorBot
/// Gets the update router for handling incoming updates.
/// </summary>
public IUpdateRouter UpdateRouter { get; }
/// <summary>
/// Initializes the update router and begins polling for updates asynchronously.
/// </summary>
/// <param name="receiverOptions">Optional receiver options for configuring update polling.</param>
/// <param name="cancellationToken">The cancellation token to stop receiving updates.</param>
/// <returns></returns>
Task StartReceivingAsync(ReceiverOptions? receiverOptions = null, CancellationToken cancellationToken = default);
}
+9 -16
View File
@@ -20,13 +20,13 @@ public class TelegratorClient : TelegramBotClient, ITelegratorBot, ICollectingPr
private IUpdateRouter? updateRouter = null;
/// <inheritdoc/>
public TelegratorOptions Options { get; private set; }
public TelegratorOptions Options { get; }
/// <inheritdoc/>
public IHandlersCollection Handlers { get; private set; }
public IHandlersCollection Handlers { get; }
/// <inheritdoc/>
public ITelegramBotInfo BotInfo { get; private set; }
public ITelegramBotInfo BotInfo { get; }
/// <inheritdoc/>
public IUpdateRouter UpdateRouter => updateRouter ?? throw new InvalidOperationException("Router's not created yet. Invoke `StartReceiving` to initialize this property.");
@@ -63,26 +63,19 @@ public class TelegratorClient : TelegramBotClient, ITelegratorBot, ICollectingPr
BotInfo = new TelegramBotInfo(this.GetMe(cancellationToken).Result);
}
/// <summary>
/// Starts receiving updates from Telegram.
/// Initializes the update router and begins polling for updates.
/// </summary>
/// <param name="receiverOptions">Optional receiver options for configuring update polling.</param>
/// <param name="globalCancellationToken">The cancellation token to stop receiving updates.</param>
public void StartReceiving(ReceiverOptions? receiverOptions = null, CancellationToken globalCancellationToken = default)
/// <inheritdoc/>
public async Task StartReceivingAsync(ReceiverOptions? receiverOptions = null, CancellationToken cancellationToken = default)
{
if (Options.GlobalCancellationToken == CancellationToken.None)
Options.GlobalCancellationToken = globalCancellationToken;
Options.GlobalCancellationToken = cancellationToken;
HandlersProvider handlerProvider = new HandlersProvider(Handlers, Options);
AwaitingProvider awaitingProvider = new AwaitingProvider(Options);
DefaultStateStorage stateStorage = new DefaultStateStorage();
updateRouter = new UpdateRouter(handlerProvider, awaitingProvider, stateStorage, Options, BotInfo);
// Log startup
TelegratorLogging.LogInformation($"Telegrator bot starting up - BotId: {BotInfo.User.Id}, Username: {BotInfo.User.Username}, MaxParallelHandlers: {Options.MaximumParallelWorkingHandlers ?? -1}");
StartReceivingInternal(receiverOptions, globalCancellationToken);
updateRouter = new UpdateRouter(handlerProvider, awaitingProvider, stateStorage, Options, BotInfo);
await StartReceivingInternal(receiverOptions, Options.GlobalCancellationToken);
}
/// <summary>
@@ -91,7 +84,7 @@ public class TelegratorClient : TelegramBotClient, ITelegratorBot, ICollectingPr
/// </summary>
/// <param name="receiverOptions">Optional receiver options for configuring update polling.</param>
/// <param name="cancellationToken">The cancellation token to stop receiving updates.</param>
private async void StartReceivingInternal(ReceiverOptions? receiverOptions, CancellationToken cancellationToken)
private async Task StartReceivingInternal(ReceiverOptions? receiverOptions, CancellationToken cancellationToken)
{
try
{
+19
View File
@@ -1,4 +1,5 @@
using System.Reflection;
using Telegram.Bot.Polling;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using Telegram.Bot.Types.Payments;
@@ -13,6 +14,24 @@ using Telegrator.States;
namespace Telegrator;
/// <summary>
/// Provides usefull helper methods for TelegratorBot
/// </summary>
public static class TelegratorBotExtensions
{
/// <summary>
/// Initializes the update router and begins polling for updates synchronously (Blocking calling thread).
/// </summary>
/// <param name="bot"></param>
/// <param name="receiverOptions">Optional receiver options for configuring update polling.</param>
/// <param name="cancellationToken">The cancellation token to stop receiving updates.</param>
public static void StartReceiving(this ITelegratorBot bot, ReceiverOptions? receiverOptions = null, CancellationToken cancellationToken = default)
{
bot.StartReceivingAsync(receiverOptions, cancellationToken)
.ConfigureAwait(false).GetAwaiter().GetResult();
}
}
/// <summary>
/// Provides usefull helper methods for messages
/// </summary>