5 Commits

Author SHA1 Message Date
gutii 9901077213 * Added webhooking detection 2026-04-27 22:15:39 +04:00
gutii 96b3241716 * Added StartReceiving method as ITelegratoBot interface member
* Added missing summaries
* Fixed compiler warning and infos
* Code cleanup and bugfixes
2026-04-27 22:13:47 +04:00
gutii 5433a2de0d * Fixed Result behaviour
* Added AsWClient
* Updated examples
2026-04-27 21:07:02 +04:00
gutii 0e0a280308 * Added WideBot csproj data
* Added TelegratorWideClient
* Added WClient extension property for handlers
* Code cleanup
2026-04-27 16:28:20 +04:00
gutii aba9cf4037 * Added integration addon wit WTelegramBot (WIP)
* Added some extensions methods
* Refactored Result behaviour
* Added missing exception messages
* Removed telegrator-specific host builder (obsolete)
* Code cleanup and bug fixes
2026-04-27 09:56:44 +04:00
50 changed files with 1437 additions and 1106 deletions
+1
View File
@@ -4,6 +4,7 @@
<Project Path="src/Telegrator.Analyzers/Telegrator.Analyzers.csproj" />
<Project Path="src/Telegrator.Hosting.Web/Telegrator.Hosting.Web.csproj" />
<Project Path="src/Telegrator.Hosting/Telegrator.Hosting.csproj" />
<Project Path="src/Telegrator.Hosting.WideBot/Telegrator.Hosting.WideBot.csproj" />
<Project Path="src/Telegrator.Localized/Telegrator.Localized.csproj" />
<Project Path="src/Telegrator/Telegrator.csproj" />
<Project Path="tests/Telegrator.Tests/Telegrator.Tests.csproj" />
@@ -6,3 +6,4 @@
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Style", "IDE0090")]
[assembly: SuppressMessage("Roslynator", "RCS1037")]
@@ -112,7 +112,7 @@ public class ImplicitHandlerBuilderExtensionsGenerator : IIncrementalGenerator
{
try
{
PrimaryConstructorBaseTypeSyntax primaryConstructor = (PrimaryConstructorBaseTypeSyntax)classDeclaration.BaseList.Types.ElementAt(0);
PrimaryConstructorBaseTypeSyntax primaryConstructor = (PrimaryConstructorBaseTypeSyntax)classDeclaration.BaseList.Types[0];
MethodDeclarationSyntax genExtension = GeneratedExtensionsMethod(classDeclaration, classDeclaration.ParameterList, primaryConstructor.ArgumentList, targeter);
extensions.Add(genExtension);
}
@@ -239,7 +239,7 @@ public class ImplicitHandlerBuilderExtensionsGenerator : IIncrementalGenerator
if (targeters.TryGetValue(classDeclaration.Identifier.ValueText, out MethodDeclarationSyntax targeter))
return targeter;
if (classDeclaration.BaseList != null && targeters.TryGetValue(classDeclaration.BaseList.Types.ElementAt(0).Type.ToString(), out targeter))
if (classDeclaration.BaseList != null && targeters.TryGetValue(classDeclaration.BaseList.Types[0].Type.ToString(), out targeter))
return targeter;
return null;
@@ -1,7 +1,7 @@
namespace Telegrator.RoslynGenerators.RoslynExtensions
namespace Telegrator.RoslynGenerators.RoslynExtensions;
public static class CollectionsExtensions
{
public static class CollectionsExtensions
{
public static IEnumerable<TSource> Combine<TSource>(params IEnumerable<TSource>[] collections)
=> collections.SelectMany(x => x);
@@ -60,5 +60,4 @@
public static IEnumerable<T> Repeat<T>(this T item, int times)
=> Enumerable.Range(0, times).Select(_ => item);
}
}
+36 -156
View File
@@ -4,131 +4,6 @@
<name>Telegrator.Hosting.Web</name>
</assembly>
<members>
<member name="T:Telegrator.Hosting.Web.TelegramBotWebHost">
<summary>
Represents a web hosted telegram bot
</summary>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHost.Services">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHost.UpdateRouter">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHost.DataSources">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHost.Lifetime">
<summary>
Allows consumers to be notified of application lifetime events.
</summary>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHost.Logger">
<summary>
This application's logger
</summary>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHost.Properties">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.#ctor(Microsoft.AspNetCore.Builder.WebApplicationBuilder)">
<summary>
Initializes a new instance of the <see cref="T:Microsoft.AspNetCore.Builder.WebApplicationBuilder"/> class.
</summary>
<param name="webApplicationBuilder">The proxied instance of host builder.</param>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.CreateBuilder(Microsoft.AspNetCore.Builder.WebApplicationOptions)">
<summary>
Creates new <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> with default services and webhook update receiving scheme
</summary>
<returns></returns>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.CreateSlimBuilder(Microsoft.AspNetCore.Builder.WebApplicationOptions)">
<summary>
Creates new SLIM <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> with default services and webhook update receiving scheme
</summary>
<returns></returns>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.CreateEmptyBuilder(Microsoft.AspNetCore.Builder.WebApplicationOptions)">
<summary>
Creates new EMPTY <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes
</summary>
<returns></returns>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.StartAsync(System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.StopAsync(System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.CreateApplicationBuilder">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.Use(System.Func{Microsoft.AspNetCore.Http.RequestDelegate,Microsoft.AspNetCore.Http.RequestDelegate})">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.New">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.Build">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.DisposeAsync">
<summary>
Disposes the host.
</summary>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.Dispose">
<summary>
Disposes the host.
</summary>
</member>
<member name="T:Telegrator.Hosting.Web.TelegramBotWebHostBuilder">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.Handlers">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.Configuration">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.Logging">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.Services">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.Environment">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.Properties">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.Metrics">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.#ctor(Microsoft.AspNetCore.Builder.WebApplicationBuilder)">
<summary>
Initializes a new instance of the <see cref="T:Telegrator.Hosting.Web.TelegramBotWebHostBuilder"/> class.
</summary>
<param name="webApplicationBuilder"></param>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.#ctor(Microsoft.AspNetCore.Builder.WebApplicationBuilder,Telegrator.Core.IHandlersCollection)">
<summary>
Initializes a new instance of the <see cref="T:Telegrator.Hosting.Web.TelegramBotWebHostBuilder"/> class.
</summary>
<param name="webApplicationBuilder"></param>
<param name="handlers"></param>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.Build">
<summary>
Builds the host.
</summary>
<returns></returns>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.ConfigureContainer``1(Microsoft.Extensions.DependencyInjection.IServiceProviderFactory{``0},System.Action{``0})">
<inheritdoc/>
</member>
<member name="T:Telegrator.Hosting.Web.WebhookerOptions">
<summary>
Configuration options for Telegram bot behavior and execution settings.
@@ -160,7 +35,7 @@
</member>
<member name="T:Telegrator.Mediation.HostedUpdateWebhooker">
<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>
</member>
<member name="M:Telegrator.Mediation.HostedUpdateWebhooker.#ctor(Telegram.Bot.ITelegramBotClient,Telegrator.Core.IUpdateRouter,Microsoft.Extensions.Options.IOptions{Telegrator.Hosting.Web.WebhookerOptions})">
@@ -194,36 +69,41 @@
</summary>
<param name="routeBuilder"></param>
</member>
<member name="T:Telegrator.ServicesCollectionExtensions">
<member name="T:Telegrator.WebHostBuilderExtensions">
<summary>
Provides extension methods for <see cref="T:Microsoft.Extensions.Hosting.IHostApplicationBuilder"/> to configure Telegrator.
</summary>
</member>
<member name="M:Telegrator.WebHostBuilderExtensions.AddTelegratorWeb(Microsoft.Extensions.Hosting.IHostApplicationBuilder,Telegrator.TelegratorOptions,Telegrator.Core.IHandlersCollection)">
<summary>
Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
</summary>
</member>
<member name="M:Telegrator.WebHostBuilderExtensions.AddTelegratorWeb(Microsoft.Extensions.Hosting.IHostApplicationBuilder,Telegrator.TelegratorOptions,Telegrator.Core.IHandlersCollection,System.Action{Telegrator.Hosting.ITelegramBotHostBuilder})">
<summary>
Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
</summary>
</member>
<member name="M:Telegrator.WebHostBuilderExtensions.AddTelegratorWebInternal(Microsoft.Extensions.DependencyInjection.IServiceCollection,Microsoft.Extensions.Configuration.IConfiguration,System.Collections.Generic.IDictionary{System.Object,System.Object},Telegrator.Core.IHandlersCollection@,Telegrator.TelegratorOptions)">
<summary>
Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
</summary>
</member>
<member name="T:Telegrator.WebServicesCollectionExtensions">
<summary>
Contains extensions for <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection"/>
Provides method to configure Telegram Bot WebHost
</summary>
</member>
<member name="F:Telegrator.ServicesCollectionExtensions.HandlersCollectionPropertyKey">
<member name="M:Telegrator.WebServicesCollectionExtensions.ConfigureWebhooker(Microsoft.Extensions.DependencyInjection.IServiceCollection,Telegrator.Hosting.Web.WebhookerOptions)">
<summary>
The key used to store the <see cref="T:Telegrator.Core.IHandlersCollection"/> in the builder properties.
Adds WebhookerOptions to services
</summary>
<param name="services"></param>
<param name="options"></param>
<returns></returns>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.get_Handlers(Microsoft.AspNetCore.Builder.WebApplicationBuilder)">
<inheritdoc cref="P:Telegrator.ServicesCollectionExtensions.&lt;G&gt;$41F16C2D39AF52899E745C9C9F42FF83.Handlers"/>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.AddTelegratorWeb(Telegrator.Hosting.ITelegramBotHostBuilder,Telegrator.TelegratorOptions,Telegrator.Core.IHandlersCollection,System.Action{Telegrator.Hosting.ITelegramBotHostBuilder})">
<summary>
Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
</summary>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.AddTelegratorWeb(Microsoft.AspNetCore.Builder.WebApplicationBuilder,Telegrator.TelegratorOptions,Telegrator.Core.IHandlersCollection,System.Action{Telegrator.Hosting.ITelegramBotHostBuilder})">
<summary>
Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
</summary>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.AddTelegratorWebInternal(Microsoft.Extensions.DependencyInjection.IServiceCollection,Microsoft.Extensions.Configuration.IConfiguration,System.Collections.Generic.IDictionary{System.Object,System.Object},Telegrator.Core.IHandlersCollection@,Telegrator.TelegratorOptions)">
<summary>
Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
</summary>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.TryFindWebhooker(System.IServiceProvider,Telegrator.Mediation.HostedUpdateWebhooker@)">
<member name="M:Telegrator.WebServicesCollectionExtensions.TryFindWebhooker(System.IServiceProvider,Telegrator.Mediation.HostedUpdateWebhooker@)">
<summary>
Searchs for <see cref="T:Telegrator.Mediation.HostedUpdateWebhooker"/> hosted service inside hosts services
</summary>
@@ -231,13 +111,18 @@
<param name="webhooker"></param>
<returns></returns>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.UseTelegratorWeb``1(``0,System.Boolean)">
<member name="T:Telegrator.WebTelegramBotHostExtensions">
<summary>
Provides useful methods to adjust Telegram bot Host
</summary>
</member>
<member name="M:Telegrator.WebTelegramBotHostExtensions.UseTelegratorWeb``1(``0,System.Boolean)">
<summary>
Replaces the initialization logic from TelegramBotWebHost constructor.
Initializes the bot and logs handlers on application startup.
</summary>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.RemapWebhook``1(``0,System.String)">
<member name="M:Telegrator.WebTelegramBotHostExtensions.RemapWebhook``1(``0,System.String)">
<summary>
Allows to remap receiving webhook endpoint and map new route to webhost.
</summary>
@@ -246,17 +131,12 @@
<returns></returns>
<exception cref="T:System.ArgumentException"></exception>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.AddTelegramWebhook(Microsoft.Extensions.DependencyInjection.IServiceCollection)">
<member name="M:Telegrator.WebTelegramBotHostExtensions.AddTelegramWebhook(Microsoft.Extensions.DependencyInjection.IServiceCollection)">
<summary>
Registers <see cref="T:Telegram.Bot.ITelegramBotClient"/> service with <see cref="T:Telegrator.Mediation.HostedUpdateWebhooker"/> to receive updates using webhook
</summary>
<param name="services"></param>
<returns></returns>
</member>
<member name="P:Telegrator.ServicesCollectionExtensions.&lt;G&gt;$41F16C2D39AF52899E745C9C9F42FF83.Handlers">
<summary>
Gets the <see cref="T:Telegrator.Core.IHandlersCollection"/> from the builder properties.
</summary>
</member>
</members>
</doc>
+171
View File
@@ -0,0 +1,171 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>Telegrator.Hosting.WideBot</name>
</assembly>
<members>
<member name="T:Telegrator.Mediation.HostedWideBotUpdateReceiver">
<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>
</member>
<member name="M:Telegrator.Mediation.HostedWideBotUpdateReceiver.#ctor(Microsoft.Extensions.Logging.ILogger{Telegrator.Mediation.HostedWideBotUpdateReceiver},Telegram.Bot.ITelegramBotClient,Telegrator.Core.IUpdateRouter,Microsoft.Extensions.Options.IOptions{Telegram.Bot.Polling.ReceiverOptions})">
<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>
</member>
<member name="M:Telegrator.Mediation.HostedWideBotUpdateReceiver.ExecuteAsync(System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="T:Telegrator.Mediation.WideUpdateReceiver">
<summary>
Reactive implementation of <see cref="T:Telegrator.Core.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>
</member>
<member name="M:Telegrator.Mediation.WideUpdateReceiver.#ctor(Telegram.Bot.WTelegramBotClient)">
<summary>
Reactive implementation of <see cref="T:Telegrator.Core.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>
</member>
<member name="M:Telegrator.Mediation.WideUpdateReceiver.ReceiveAsync(Telegram.Bot.Polling.IUpdateHandler,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="T:Telegrator.TelegratorWClient">
<summary>
Client class for the Telegrator library with Wider functionality, provided by WTelegramBotClient.
Extends TelegramBotClient with reactive capabilities for handling updates.
</summary>
</member>
<member name="P:Telegrator.TelegratorWClient.Options">
<inheritdoc/>
</member>
<member name="P:Telegrator.TelegratorWClient.Handlers">
<inheritdoc/>
</member>
<member name="P:Telegrator.TelegratorWClient.BotInfo">
<inheritdoc/>
</member>
<member name="P:Telegrator.TelegratorWClient.UpdateRouter">
<inheritdoc/>
</member>
<member name="M:Telegrator.TelegratorWClient.#ctor(Telegram.Bot.WTelegramBotClientOptions,Telegrator.TelegratorOptions,System.Net.Http.HttpClient,System.Threading.CancellationToken)">
<summary>
Initializes new instance of <see cref="T:Telegrator.TelegratorWClient"/>
</summary>
<param name="wOptions"></param>
<param name="telegratorOptions"></param>
<param name="httpClient"></param>
<param name="cancellationToken"></param>
</member>
<member name="M:Telegrator.TelegratorWClient.StartReceiving(Telegram.Bot.Polling.ReceiverOptions,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:Telegrator.TelegratorWClient.StartReceivingAsync(Telegram.Bot.Polling.ReceiverOptions,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="T:Telegrator.HandlersExtensions">
<summary>
Provides extensions memebrs for <see cref="T:Telegrator.Core.Handlers.UpdateHandlerBase"/> for easy access to Wider bot functions and update
</summary>
</member>
<member name="M:Telegrator.HandlersExtensions.get_WClient``1(Telegrator.Core.Handlers.AbstractUpdateHandler{``0})">
<inheritdoc cref="P:Telegrator.HandlersExtensions.&lt;G&gt;$F89AF16C011F73161937A1614DCDDD7A`1.WClient"/>
</member>
<member name="M:Telegrator.HandlersExtensions.get_WideUpdate``1(Telegrator.Core.Handlers.AbstractUpdateHandler{``0})">
<inheritdoc cref="P:Telegrator.HandlersExtensions.&lt;G&gt;$F89AF16C011F73161937A1614DCDDD7A`1.WideUpdate"/>
</member>
<member name="M:Telegrator.HandlersExtensions.get_TLUpdate``1(Telegrator.Core.Handlers.AbstractUpdateHandler{``0})">
<inheritdoc cref="P:Telegrator.HandlersExtensions.&lt;G&gt;$F89AF16C011F73161937A1614DCDDD7A`1.TLUpdate"/>
</member>
<member name="M:Telegrator.HandlersExtensions.AsWClient(Telegram.Bot.ITelegramBotClient)">
<summary>
Casts Update to <see cref="T:Telegram.Bot.WTelegramBotClient"/>
</summary>
</member>
<member name="M:Telegrator.HandlersExtensions.AsWUpdate(Telegram.Bot.Types.Update)">
<summary>
Casts Update to <see cref="T:WTelegram.Types.Update"/>
</summary>
</member>
<member name="P:Telegrator.HandlersExtensions.&lt;G&gt;$F89AF16C011F73161937A1614DCDDD7A`1.WClient">
<summary>
Casts Update to <see cref="T:Telegram.Bot.WTelegramBotClient"/>
</summary>
</member>
<member name="P:Telegrator.HandlersExtensions.&lt;G&gt;$F89AF16C011F73161937A1614DCDDD7A`1.WideUpdate">
<summary>
Casts Update to <see cref="T:WTelegram.Types.Update"/>
</summary>
</member>
<member name="P:Telegrator.HandlersExtensions.&lt;G&gt;$F89AF16C011F73161937A1614DCDDD7A`1.TLUpdate">
<summary>
Casts Update to <see cref="T:TL.Update"/>
</summary>
</member>
<member name="T:Telegrator.WideHostBuilderExtensions">
<summary>
Provides extension methods for <see cref="T:Microsoft.Extensions.Hosting.IHostApplicationBuilder"/> to configure Telegrator.
</summary>
</member>
<member name="M:Telegrator.WideHostBuilderExtensions.AddWideTelegrator(Microsoft.Extensions.Hosting.IHostApplicationBuilder,Telegrator.TelegratorOptions,Telegrator.Core.IHandlersCollection,System.Action{Telegrator.Hosting.ITelegramBotHostBuilder})">
<summary>
Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
</summary>
</member>
<member name="M:Telegrator.WideHostBuilderExtensions.AddWideTelegrator(Microsoft.Extensions.Hosting.IHostApplicationBuilder,Telegrator.TelegratorOptions,Telegrator.Core.IHandlersCollection)">
<summary>
Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
</summary>
</member>
<member name="M:Telegrator.WideHostBuilderExtensions.AddWideTelegratorInternal(Microsoft.Extensions.DependencyInjection.IServiceCollection,Microsoft.Extensions.Configuration.IConfiguration,System.Collections.Generic.IDictionary{System.Object,System.Object},Telegrator.Core.IHandlersCollection@,Telegrator.TelegratorOptions)">
<summary>
Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
</summary>
</member>
<member name="T:Telegrator.WideBotServiceCollectionExtensions">
<summary>
Contains extensions for <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection"/>
Provides method to configure Telegram Bot WebHost
</summary>
</member>
<member name="M:Telegrator.WideBotServiceCollectionExtensions.ConfigureWideTelegram(Microsoft.Extensions.DependencyInjection.IServiceCollection,Telegram.Bot.WTelegramBotClientOptions)">
<summary>
Adds WTelegramBotClientOptions to services
</summary>
<param name="services"></param>
<param name="options"></param>
<returns></returns>
</member>
<member name="M:Telegrator.WideBotServiceCollectionExtensions.AddMTProtoUpdateReceiver(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Boolean)">
<summary>
Adds WTelegramBotClient
</summary>
<param name="services"></param>
<param name="useHttp"></param>
<returns></returns>
</member>
<member name="T:Telegrator.WideTelegramBotHostExtensions">
<summary>
Provides useful methods to adjust Telegram bot Host
</summary>
</member>
<member name="M:Telegrator.WideTelegramBotHostExtensions.UseWideTelegrator(Microsoft.Extensions.Hosting.IHost)">
<summary>
Replaces the initialization logic from TelegramBotWebHost constructor.
Initializes the bot and logs handlers on application startup.
</summary>
</member>
</members>
</doc>
+41 -88
View File
@@ -40,63 +40,6 @@
Represents a hosted telegram bots and services builder that helps manage configuration, logging, lifetime, and more.
</summary>
</member>
<member name="T:Telegrator.Hosting.TelegramBotHost">
<summary>
Represents a hosted telegram bot
</summary>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHost.Services">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHost.UpdateRouter">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHost.Logger">
<summary>
This application's logger
</summary>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHost.#ctor(Microsoft.Extensions.Hosting.HostApplicationBuilder)">
<summary>
Initializes a new instance of the <see cref="T:Telegrator.Hosting.TelegramBotHost"/> class.
</summary>
<param name="hostApplicationBuilder">The proxied instance of host builder.</param>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHost.CreateBuilder">
<summary>
Creates new <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> with default configuration, services and long-polling update receiving scheme
</summary>
<returns></returns>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHost.CreateBuilder(Microsoft.Extensions.Hosting.HostApplicationBuilderSettings)">
<summary>
Creates new <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> with default services and long-polling update receiving scheme
</summary>
<returns></returns>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHost.CreateEmptyBuilder">
<summary>
Creates new EMPTY <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes
</summary>
<returns></returns>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHost.CreateEmptyBuilder(Microsoft.Extensions.Hosting.HostApplicationBuilderSettings)">
<summary>
Creates new EMPTY <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes
</summary>
<returns></returns>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHost.StartAsync(System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHost.StopAsync(System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHost.Dispose">
<summary>
Disposes the host.
</summary>
</member>
<member name="T:Telegrator.Hosting.TelegramBotHostBuilder">
<inheritdoc/>
</member>
@@ -121,25 +64,19 @@
<member name="P:Telegrator.Hosting.TelegramBotHostBuilder.Metrics">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHostBuilder.#ctor(Microsoft.Extensions.Hosting.HostApplicationBuilder)">
<member name="M:Telegrator.Hosting.TelegramBotHostBuilder.#ctor(Microsoft.Extensions.Hosting.IHostApplicationBuilder)">
<summary>
Initializes a new instance of the <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> class.
</summary>
<param name="hostApplicationBuilder"></param>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHostBuilder.#ctor(Microsoft.Extensions.Hosting.HostApplicationBuilder,Telegrator.Core.IHandlersCollection)">
<member name="M:Telegrator.Hosting.TelegramBotHostBuilder.#ctor(Microsoft.Extensions.Hosting.IHostApplicationBuilder,Telegrator.Core.IHandlersCollection)">
<summary>
Initializes a new instance of the <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> class.
</summary>
<param name="hostApplicationBuilder"></param>
<param name="handlers"></param>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHostBuilder.Build">
<summary>
Builds the host.
</summary>
<returns></returns>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHostBuilder.ConfigureContainer``1(Microsoft.Extensions.DependencyInjection.IServiceProviderFactory{``0},System.Action{``0})">
<inheritdoc/>
</member>
@@ -158,42 +95,42 @@
<member name="M:Telegrator.Logging.MicrosoftLoggingAdapter.Log(Telegrator.Logging.LogLevel,System.String,System.Exception)">
<inheritdoc/>
</member>
<member name="T:Telegrator.Polling.HostedUpdateReceiver">
<member name="T:Telegrator.Mediation.HostedUpdateReceiver">
<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>
<param name="options"></param>
<param name="logger"></param>
</member>
<member name="M:Telegrator.Polling.HostedUpdateReceiver.#ctor(Telegram.Bot.ITelegramBotClient,Telegrator.Core.IUpdateRouter,Microsoft.Extensions.Options.IOptions{Telegram.Bot.Polling.ReceiverOptions},Microsoft.Extensions.Logging.ILogger{Telegrator.Polling.HostedUpdateReceiver})">
<member name="M:Telegrator.Mediation.HostedUpdateReceiver.#ctor(Telegram.Bot.ITelegramBotClient,Telegrator.Core.IUpdateRouter,Microsoft.Extensions.Options.IOptions{Telegram.Bot.Polling.ReceiverOptions},Microsoft.Extensions.Logging.ILogger{Telegrator.Mediation.HostedUpdateReceiver})">
<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>
<param name="options"></param>
<param name="logger"></param>
</member>
<member name="M:Telegrator.Polling.HostedUpdateReceiver.ExecuteAsync(System.Threading.CancellationToken)">
<member name="M:Telegrator.Mediation.HostedUpdateReceiver.ExecuteAsync(System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="T:Telegrator.Polling.HostUpdateRouter">
<member name="T:Telegrator.Mediation.HostUpdateRouter">
<inheritdoc/>
</member>
<member name="F:Telegrator.Polling.HostUpdateRouter.Logger">
<member name="F:Telegrator.Mediation.HostUpdateRouter.Logger">
<summary>
<see cref="T:Microsoft.Extensions.Logging.ILogger"/> of this router
</summary>
</member>
<member name="M:Telegrator.Polling.HostUpdateRouter.#ctor(Telegrator.Core.IHandlersProvider,Telegrator.Core.IAwaitingProvider,Telegrator.Core.States.IStateStorage,Microsoft.Extensions.Options.IOptions{Telegrator.TelegratorOptions},Telegrator.Core.ITelegramBotInfo,Microsoft.Extensions.Logging.ILogger{Telegrator.Polling.HostUpdateRouter})">
<member name="M:Telegrator.Mediation.HostUpdateRouter.#ctor(Telegrator.Core.IHandlersProvider,Telegrator.Core.IAwaitingProvider,Telegrator.Core.States.IStateStorage,Microsoft.Extensions.Options.IOptions{Telegrator.TelegratorOptions},Telegrator.Core.ITelegramBotInfo,Microsoft.Extensions.Logging.ILogger{Telegrator.Mediation.HostUpdateRouter})">
<inheritdoc/>
</member>
<member name="M:Telegrator.Polling.HostUpdateRouter.HandleUpdateAsync(Telegram.Bot.ITelegramBotClient,Telegram.Bot.Types.Update,System.Threading.CancellationToken)">
<member name="M:Telegrator.Mediation.HostUpdateRouter.HandleUpdateAsync(Telegram.Bot.ITelegramBotClient,Telegram.Bot.Types.Update,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:Telegrator.Polling.HostUpdateRouter.HandleException(Telegram.Bot.ITelegramBotClient,System.Exception,Telegram.Bot.Polling.HandleErrorSource,System.Threading.CancellationToken)">
<member name="M:Telegrator.Mediation.HostUpdateRouter.HandleException(Telegram.Bot.ITelegramBotClient,System.Exception,Telegram.Bot.Polling.HandleErrorSource,System.Threading.CancellationToken)">
<summary>
Default exception handler of this router
</summary>
@@ -239,12 +176,7 @@
The key used to store the <see cref="T:Telegrator.Core.IHandlersCollection"/> in the builder properties.
</summary>
</member>
<member name="M:Telegrator.HostBuilderExtensions.AddTelegrator(Telegrator.Hosting.ITelegramBotHostBuilder,Telegrator.TelegratorOptions,Telegrator.Core.IHandlersCollection,System.Action{Telegrator.Hosting.ITelegramBotHostBuilder})">
<summary>
Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
</summary>
</member>
<member name="M:Telegrator.HostBuilderExtensions.AddTelegrator(Microsoft.Extensions.Hosting.HostApplicationBuilder,Telegrator.TelegratorOptions,Telegrator.Core.IHandlersCollection,System.Action{Telegrator.Hosting.ITelegramBotHostBuilder})">
<member name="M:Telegrator.HostBuilderExtensions.AddTelegrator(Microsoft.Extensions.Hosting.IHostApplicationBuilder,Telegrator.TelegratorOptions,Telegrator.Core.IHandlersCollection,System.Action{Telegrator.Hosting.ITelegramBotHostBuilder})">
<summary>
Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
</summary>
@@ -259,18 +191,39 @@
Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
</summary>
</member>
<member name="M:Telegrator.HostBuilderExtensions.AddTelegrator(Microsoft.Extensions.Hosting.IHostBuilder,Telegrator.TelegratorOptions,Telegrator.Core.IHandlersCollection,System.Action{Telegrator.Core.IHandlersCollection})">
<summary>
Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
</summary>
</member>
<member name="M:Telegrator.HostBuilderExtensions.AddTelegratorInternal(Microsoft.Extensions.DependencyInjection.IServiceCollection,Microsoft.Extensions.Configuration.IConfiguration,System.Collections.Generic.IDictionary{System.Object,System.Object},Telegrator.Core.IHandlersCollection@,Telegrator.TelegratorOptions)">
<summary>
Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
</summary>
</member>
<member name="T:Telegrator.ServicesCollectionExtensions">
<member name="T:Telegrator.HostServicesCollectionExtensions">
<summary>
Contains extensions for <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection"/>
Provides method to configure Telegram Bot Host
</summary>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.AddStateStorage``1(Microsoft.Extensions.DependencyInjection.IServiceCollection)">
<member name="M:Telegrator.HostServicesCollectionExtensions.ConfigureTelegram(Microsoft.Extensions.DependencyInjection.IServiceCollection,Telegram.Bot.TelegramBotClientOptions)">
<summary>
Adds TelegramBotClientOptions to services
</summary>
<param name="services"></param>
<param name="options"></param>
<returns></returns>
</member>
<member name="M:Telegrator.HostServicesCollectionExtensions.ConfigureReceiver(Microsoft.Extensions.DependencyInjection.IServiceCollection,Telegram.Bot.Polling.ReceiverOptions)">
<summary>
Adds ReceiverOptions to services
</summary>
<param name="services"></param>
<param name="options"></param>
<returns></returns>
</member>
<member name="M:Telegrator.HostServicesCollectionExtensions.AddStateStorage``1(Microsoft.Extensions.DependencyInjection.IServiceCollection)">
<summary>
Registers <see cref="T:Telegrator.Core.States.IStateStorage"/> service
</summary>
@@ -278,21 +231,21 @@
<param name="services"></param>
<returns></returns>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.AddTelegramBotHostDefaults(Microsoft.Extensions.DependencyInjection.IServiceCollection)">
<member name="M:Telegrator.HostServicesCollectionExtensions.AddTelegramBotHostDefaults(Microsoft.Extensions.DependencyInjection.IServiceCollection)">
<summary>
Registers <see cref="T:Telegrator.Hosting.TelegramBotHost"/> default services
Registers <see cref="N:Telegrator"/> default services
</summary>
<param name="services"></param>
<returns></returns>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.AddTelegramReceiver(Microsoft.Extensions.DependencyInjection.IServiceCollection)">
<member name="M:Telegrator.HostServicesCollectionExtensions.AddTelegramReceiver(Microsoft.Extensions.DependencyInjection.IServiceCollection)">
<summary>
Registers <see cref="T:Telegram.Bot.ITelegramBotClient"/> service with <see cref="T:Telegrator.Polling.HostedUpdateReceiver"/> to receive updates using long polling
Registers <see cref="T:Telegram.Bot.ITelegramBotClient"/> service with <see cref="T:Telegrator.Mediation.HostedUpdateReceiver"/> to receive updates using long polling
</summary>
<param name="services"></param>
<returns></returns>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.TypedTelegramBotClientFactory(System.Net.Http.HttpClient,System.IServiceProvider)">
<member name="M:Telegrator.HostServicesCollectionExtensions.TypedTelegramBotClientFactory(System.Net.Http.HttpClient,System.IServiceProvider)">
<summary>
<see cref="T:Telegram.Bot.ITelegramBotClient"/> factory method
</summary>
+46 -14
View File
@@ -5483,6 +5483,14 @@
Gets the update router for handling incoming updates.
</summary>
</member>
<member name="M:Telegrator.ITelegratorBot.StartReceivingAsync(Telegram.Bot.Polling.ReceiverOptions,System.Threading.CancellationToken)">
<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>
</member>
<member name="T:Telegrator.Logging.ConsoleLogger">
<summary>
Console logger implementation that writes to System.Console.
@@ -6027,6 +6035,9 @@
Manages the distribution of updates between regular handlers and awaiting handlers.
</summary>
</member>
<member name="P:Telegrator.Mediation.UpdateRouter.Options">
<inheritdoc/>
</member>
<member name="P:Telegrator.Mediation.UpdateRouter.HandlersProvider">
<inheritdoc/>
</member>
@@ -6036,9 +6047,6 @@
<member name="P:Telegrator.Mediation.UpdateRouter.StateStorage">
<inheritdoc/>
</member>
<member name="P:Telegrator.Mediation.UpdateRouter.Options">
<inheritdoc/>
</member>
<member name="P:Telegrator.Mediation.UpdateRouter.HandlersPool">
<inheritdoc/>
</member>
@@ -6377,14 +6385,14 @@
Represents handler results, allowing to communicate with router and control aspect execution
</summary>
</member>
<member name="P:Telegrator.Result.Positive">
<member name="P:Telegrator.Result.Success">
<summary>
Is result positive
Tell router to stop describing
</summary>
</member>
<member name="P:Telegrator.Result.RouteNext">
<summary>
Should router search for next matching handler
Tell router to continue describing
</summary>
</member>
<member name="P:Telegrator.Result.NextType">
@@ -6449,6 +6457,14 @@
<param name="keySelector"></param>
<returns></returns>
</member>
<member name="M:Telegrator.ColletionsExtensions.Squeeze``1(System.Collections.Generic.IEnumerable{``0})">
<summary>
Remove all <see langword="null"/> values and returns collection without nullable type.
</summary>
<typeparam name="T"></typeparam>
<param name="source"></param>
<returns></returns>
</member>
<member name="M:Telegrator.ColletionsExtensions.ForEach``1(System.Collections.Generic.IEnumerable{``0},System.Action{``0})">
<summary>
Enumerates objects in a <paramref name="source"/> and executes an <paramref name="action"/> on each one
@@ -6558,7 +6574,7 @@
<param name="type"></param>
<returns></returns>
</member>
<member name="M:Telegrator.ReflectionExtensions.IsHandlerRealization(System.Type)">
<member name="M:Telegrator.ReflectionExtensions.IsHandlerImplementation(System.Type)">
<summary>
Checks if <paramref name="type"/> is an implementation of <see cref="T:Telegrator.Core.Handlers.UpdateHandlerBase"/> class or its descendants
</summary>
@@ -6796,13 +6812,8 @@
<param name="httpClient">Optional HTTP client for making requests.</param>
<param name="cancellationToken">The cancellation token.</param>
</member>
<member name="M:Telegrator.TelegratorClient.StartReceiving(Telegram.Bot.Polling.ReceiverOptions,System.Threading.CancellationToken)">
<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="cancellationToken">The cancellation token to stop receiving updates.</param>
<member name="M:Telegrator.TelegratorClient.StartReceivingAsync(Telegram.Bot.Polling.ReceiverOptions,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:Telegrator.TelegratorClient.StartReceivingInternal(Telegram.Bot.Polling.ReceiverOptions,System.Threading.CancellationToken)">
<summary>
@@ -6863,6 +6874,19 @@
Gets or sets the global cancellation token for all bot operations.
</summary>
</member>
<member name="T:Telegrator.TelegratorBotExtensions">
<summary>
Provides usefull helper methods for TelegratorBot
</summary>
</member>
<member name="M:Telegrator.TelegratorBotExtensions.StartReceiving(Telegrator.ITelegratorBot,Telegram.Bot.Polling.ReceiverOptions,System.Threading.CancellationToken)">
<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>
</member>
<member name="T:Telegrator.MessageExtensions">
<summary>
Provides usefull helper methods for messages
@@ -7113,6 +7137,14 @@
Provides convenient methods for creating implicit handlers.
</summary>
</member>
<member name="M:Telegrator.HandlersCollectionExtensions.CollectHandlers(Telegrator.Core.IHandlersCollection)">
<summary>
Collects all handlers from current app domain.
Scans for handlers exported by analyzer into class `Telegrator.Analyzers.AnalyzerExport` in each assembly and registers them to the collection.
</summary>
<param name="handlers"></param>
<returns></returns>
</member>
<member name="M:Telegrator.HandlersCollectionExtensions.CollectHandlersDomainWide(Telegrator.Core.IHandlersCollection)">
<summary>
Collects all public handlers from the current app domain.
@@ -10,6 +10,8 @@ namespace Telegrator.Analyzers;
[Generator(LanguageNames.CSharp)]
public class DeveloperHelperAnalyzer : IIncrementalGenerator
{
internal record class HandlerDeclarationModel(string ClassName, string NamespaceName, string? AttributeName, string? BaseClassName, Location Location);
private static readonly DiagnosticDescriptor MissingBaseClassWarning = new(
id: "TLG101",
title: "Missing handlers base class",
@@ -131,9 +133,8 @@ public class DeveloperHelperAnalyzer : IIncrementalGenerator
private static FieldDeclarationSyntax GenerateTypeField(HandlerDeclarationModel handler)
{
string fullTypeName = handler.Namespace == "Global"
? handler.ClassName
: $"{handler.Namespace}.{handler.ClassName}";
string fullTypeName = handler.NamespaceName == "Global"
? handler.ClassName : $"{handler.NamespaceName}.{handler.ClassName}";
TypeOfExpressionSyntax typeofExpression = SyntaxFactory.TypeOfExpression(SyntaxFactory.ParseTypeName(fullTypeName));
VariableDeclaratorSyntax variableDeclarator = SyntaxFactory.VariableDeclarator(SyntaxFactory.Identifier($"{handler.ClassName}Type"))
@@ -149,15 +150,6 @@ public class DeveloperHelperAnalyzer : IIncrementalGenerator
}
}
internal class HandlerDeclarationModel(string className, string namespaceName, string? attributeName, string? baseClassName, Location location)
{
public readonly string ClassName = className;
public readonly string Namespace = namespaceName;
public readonly string? AttributeName = attributeName;
public readonly string? BaseClassName = baseClassName;
public readonly Location Location = location;
}
internal static class DeveloperHelperAnalyzerExtensions
{
private static readonly string[] HandlersNames =
@@ -8,8 +8,12 @@ using System.Text;
namespace Telegrator.Analyzers;
[Generator(LanguageNames.CSharp)]
public class GeneratedKeyboardMarkupGenerator : IIncrementalGenerator
public class KeyboardMarkupGenerator : IIncrementalGenerator
{
// Records
private record class GeneratedMarkupMethodModel(MethodDeclarationSyntax OriginalMethod, FieldDeclarationSyntax GeneratedField, MethodDeclarationSyntax GeneratedMethod);
private record class GeneratedMarkupPropertyModel(PropertyDeclarationSyntax OriginalProperty, PropertyDeclarationSyntax GeneratedProperty);
// Return types
private const string InlineReturnType = "InlineKeyboardMarkup";
private const string ReplyReturnType = "ReplyKeyboardMarkup";
@@ -459,30 +463,4 @@ public class GeneratedKeyboardMarkupGenerator : IIncrementalGenerator
SyntaxFactory.IdentifierName(className),
SyntaxFactory.IdentifierName(methodName));
}
private class GeneratedMarkupMethodModel
{
public MethodDeclarationSyntax OriginalMethod { get; }
public FieldDeclarationSyntax GeneratedField { get; }
public MethodDeclarationSyntax GeneratedMethod { get; }
public GeneratedMarkupMethodModel(MethodDeclarationSyntax originalMethod, FieldDeclarationSyntax generatedField, MethodDeclarationSyntax generatedMethod)
{
OriginalMethod = originalMethod;
GeneratedField = generatedField;
GeneratedMethod = generatedMethod;
}
}
private class GeneratedMarkupPropertyModel
{
public PropertyDeclarationSyntax OriginalProperty { get; }
public PropertyDeclarationSyntax GeneratedProperty { get; }
public GeneratedMarkupPropertyModel(PropertyDeclarationSyntax originalProperty, PropertyDeclarationSyntax generatedProperty)
{
OriginalProperty = originalProperty;
GeneratedProperty = generatedProperty;
}
}
}
@@ -1,7 +1,7 @@
namespace Telegrator.Analyzers.RoslynExtensions;
public class TargteterNotFoundException() : Exception() { }
public class BaseClassTypeNotFoundException() : Exception() { }
public class AncestorNotFoundException : Exception { }
#pragma warning disable RCS1194 // Implement exception constructors
public class TargteterNotFoundException() : Exception();
public class BaseClassTypeNotFoundException() : Exception();
public class AncestorNotFoundException() : Exception();
#pragma warning restore RCS1194 // Implement exception constructors
@@ -10,3 +10,5 @@ using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Usage", "CA2254")]
[assembly: SuppressMessage("Maintainability", "CA1510")]
[assembly: SuppressMessage("Style", "IDE0270")]
[assembly: SuppressMessage("Roslynator", "RCS1037")]
[assembly: SuppressMessage("Roslynator", "RCS1224")]
@@ -1,159 +0,0 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Telegrator.Core;
namespace Telegrator.Hosting.Web;
/// <summary>
/// Represents a web hosted telegram bot
/// </summary>
public class TelegramBotWebHost : IHost, IApplicationBuilder, IEndpointRouteBuilder, IAsyncDisposable
{
private readonly WebApplication _innerApp;
private readonly IUpdateRouter _updateRouter;
private readonly ILogger<TelegramBotWebHost> _logger;
private bool _disposed;
/// <inheritdoc/>
public IServiceProvider Services => _innerApp.Services;
/// <inheritdoc/>
public IUpdateRouter UpdateRouter => _updateRouter;
/// <inheritdoc/>
public ICollection<EndpointDataSource> DataSources => ((IEndpointRouteBuilder)_innerApp).DataSources;
/// <summary>
/// Allows consumers to be notified of application lifetime events.
/// </summary>
public IHostApplicationLifetime Lifetime => _innerApp.Lifetime;
/// <summary>
/// This application's logger
/// </summary>
public ILogger<TelegramBotWebHost> Logger => _logger;
/// <inheritdoc/>
public IDictionary<string, object?> Properties => ((IApplicationBuilder)_innerApp).Properties;
// Private interface fields
IServiceProvider IEndpointRouteBuilder.ServiceProvider => Services;
IServiceProvider IApplicationBuilder.ApplicationServices { get => Services; set => throw new NotImplementedException(); }
IFeatureCollection IApplicationBuilder.ServerFeatures => ((IApplicationBuilder)_innerApp).ServerFeatures;
/// <summary>
/// Initializes a new instance of the <see cref="WebApplicationBuilder"/> class.
/// </summary>
/// <param name="webApplicationBuilder">The proxied instance of host builder.</param>
public TelegramBotWebHost(WebApplicationBuilder webApplicationBuilder)
{
// Building proxy application
_innerApp = webApplicationBuilder.Build();
// Reruesting services for this host
_updateRouter = Services.GetRequiredService<IUpdateRouter>();
_logger = Services.GetRequiredService<ILogger<TelegramBotWebHost>>();
}
/// <summary>
/// Creates new <see cref="TelegramBotHostBuilder"/> with default services and webhook update receiving scheme
/// </summary>
/// <returns></returns>
public static TelegramBotWebHostBuilder CreateBuilder(WebApplicationOptions? settings)
{
ArgumentNullException.ThrowIfNull(settings, nameof(settings));
WebApplicationBuilder innerApp = WebApplication.CreateBuilder(settings);
TelegramBotWebHostBuilder builder = new TelegramBotWebHostBuilder(innerApp);
builder.AddTelegratorWeb();
return builder;
}
/// <summary>
/// Creates new SLIM <see cref="TelegramBotHostBuilder"/> with default services and webhook update receiving scheme
/// </summary>
/// <returns></returns>
public static TelegramBotWebHostBuilder CreateSlimBuilder(WebApplicationOptions? settings)
{
ArgumentNullException.ThrowIfNull(settings, nameof(settings));
WebApplicationBuilder innerApp = WebApplication.CreateSlimBuilder(settings);
TelegramBotWebHostBuilder builder = new TelegramBotWebHostBuilder(innerApp);
builder.AddTelegratorWeb();
return builder;
}
/// <summary>
/// Creates new EMPTY <see cref="TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes
/// </summary>
/// <returns></returns>
public static TelegramBotWebHostBuilder CreateEmptyBuilder(WebApplicationOptions? settings)
{
ArgumentNullException.ThrowIfNull(settings, nameof(settings));
WebApplicationBuilder innerApp = WebApplication.CreateEmptyBuilder(settings);
TelegramBotWebHostBuilder builder = new TelegramBotWebHostBuilder(innerApp);
builder.AddTelegratorWeb();
return builder;
}
/// <inheritdoc/>
public async Task StartAsync(CancellationToken cancellationToken = default)
{
await _innerApp.StartAsync(cancellationToken);
}
/// <inheritdoc/>
public async Task StopAsync(CancellationToken cancellationToken = default)
{
await _innerApp.StopAsync(cancellationToken);
}
/// <inheritdoc/>
public IApplicationBuilder CreateApplicationBuilder()
=> ((IEndpointRouteBuilder)_innerApp).CreateApplicationBuilder();
/// <inheritdoc/>
public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
=> _innerApp.Use(middleware);
/// <inheritdoc/>
public IApplicationBuilder New()
=> ((IApplicationBuilder)_innerApp).New();
/// <inheritdoc/>
public RequestDelegate Build()
=> ((IApplicationBuilder)_innerApp).Build();
/// <summary>
/// Disposes the host.
/// </summary>
public async ValueTask DisposeAsync()
{
if (_disposed)
return;
await _innerApp.DisposeAsync();
GC.SuppressFinalize(this);
_disposed = true;
}
/// <summary>
/// Disposes the host.
/// </summary>
public void Dispose()
{
if (_disposed)
return;
ValueTask disposeTask = _innerApp.DisposeAsync();
disposeTask.AsTask().Wait();
GC.SuppressFinalize(this);
_disposed = true;
}
}
@@ -1,75 +0,0 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.Metrics;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Telegrator.Core;
#pragma warning disable IDE0001
namespace Telegrator.Hosting.Web;
/// <inheritdoc/>
public class TelegramBotWebHostBuilder : ITelegramBotHostBuilder
{
private readonly WebApplicationBuilder _innerBuilder;
internal IHandlersCollection _handlers = null!;
/// <inheritdoc/>
public IHandlersCollection Handlers => _handlers;
/// <inheritdoc/>
public IConfigurationManager Configuration => _innerBuilder.Configuration;
/// <inheritdoc/>
public ILoggingBuilder Logging => _innerBuilder.Logging;
/// <inheritdoc/>
public IServiceCollection Services => _innerBuilder.Services;
/// <inheritdoc/>
public IHostEnvironment Environment => _innerBuilder.Environment;
/// <inheritdoc/>
public IDictionary<object, object> Properties => ((IHostApplicationBuilder)_innerBuilder).Properties;
/// <inheritdoc/>
public IMetricsBuilder Metrics => _innerBuilder.Metrics;
/// <summary>
/// Initializes a new instance of the <see cref="TelegramBotWebHostBuilder"/> class.
/// </summary>
/// <param name="webApplicationBuilder"></param>
public TelegramBotWebHostBuilder(WebApplicationBuilder webApplicationBuilder)
{
_innerBuilder = webApplicationBuilder ?? throw new ArgumentNullException(nameof(webApplicationBuilder));
}
/// <summary>
/// Initializes a new instance of the <see cref="TelegramBotWebHostBuilder"/> class.
/// </summary>
/// <param name="webApplicationBuilder"></param>
/// <param name="handlers"></param>
public TelegramBotWebHostBuilder(WebApplicationBuilder webApplicationBuilder, IHandlersCollection handlers)
{
_innerBuilder = webApplicationBuilder ?? throw new ArgumentNullException(nameof(webApplicationBuilder));
_handlers = handlers ?? throw new ArgumentNullException(nameof(handlers));
}
/// <summary>
/// Builds the host.
/// </summary>
/// <returns></returns>
public TelegramBotWebHost Build()
{
TelegramBotWebHost host = new TelegramBotWebHost(_innerBuilder);
host.UseTelegratorWeb();
return host;
}
/// <inheritdoc/>
public void ConfigureContainer<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory, Action<TContainerBuilder>? configure = null) where TContainerBuilder : notnull
{
((IHostApplicationBuilder)_innerBuilder).ConfigureContainer(factory, configure);
}
}
@@ -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
{
-85
View File
@@ -1,85 +0,0 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Telegrator.Hosting;
using Telegrator.Hosting.Web;
namespace Telegrator;
internal class Program
{
public static void TelegramBotWebHostBuilder_Example(string[] args)
{
TelegramBotWebHostBuilder builder = TelegramBotWebHost.CreateBuilder(new WebApplicationOptions()
{
Args = args,
ApplicationName = "TelegramBotWebHost example",
});
builder.Handlers
.CollectHandlersAssemblyWide();
builder.Build()
.AddLoggingAdapter()
.SetBotCommands()
.Run();
}
public static void WebApplicationBuilder_Example(string[] args)
{
WebApplicationBuilder builder = WebApplication.CreateBuilder(new WebApplicationOptions()
{
Args = args,
ApplicationName = "WebApplication example",
});
builder.AddTelegratorWeb(action: builder => builder.Handlers
.CollectHandlersAssemblyWide());
builder.Build()
.UseTelegratorWeb(dontMap: true)
.RemapWebhook("https://awesome-butt-sex.cloudpub.ru/")
.AddLoggingAdapter()
.SetBotCommands()
.Run();
}
public static void TelegramBotHostBuilder_Example(string[] args)
{
ConfigurationManager configuration = new ConfigurationManager();
configuration.AddJsonFile("appsettings.json");
TelegramBotHostBuilder builder = TelegramBotHost.CreateBuilder(new HostApplicationBuilderSettings()
{
Args = args,
ApplicationName = "TelegramBotHost example",
Configuration = configuration
});
builder.Handlers
.CollectHandlersAssemblyWide();
builder.Build()
.AddLoggingAdapter()
.SetBotCommands()
.Run();
}
public static void HostApplicationBuilder_Example(string[] args)
{
HostApplicationBuilder builder = Host.CreateApplicationBuilder(new HostApplicationBuilderSettings()
{
Args = args,
ApplicationName = "Host example",
});
builder.AddTelegrator(action: builder => builder.Handlers
.CollectHandlersAssemblyWide());
builder.Build()
.UseTelegrator()
.AddLoggingAdapter()
.SetBotCommands()
.Run();
}
}
@@ -15,7 +15,7 @@
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
<Title>Telegrator.Hosting.Web</Title>
<Version>1.16.9</Version>
<Version>1.17.0</Version>
<Authors>Rikitav Tim4ik</Authors>
<Company>Rikitav Tim4ik</Company>
<RepositoryUrl>https://github.com/Rikitav/Telegrator</RepositoryUrl>
@@ -40,4 +40,5 @@
<None Include="..\..\LICENSE" Pack="True" PackagePath="\" />
<None Include="..\..\resources\telegrator_nuget.png" Pack="True" PackagePath="\" />
</ItemGroup>
</Project>
+61 -41
View File
@@ -1,5 +1,4 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
@@ -14,39 +13,29 @@ using Telegrator.Hosting.Web;
using Telegrator.Mediation;
using Telegrator.Providers;
namespace Telegrator
{
/// <summary>
/// Contains extensions for <see cref="IServiceCollection"/>
/// Provides method to configure Telegram Bot WebHost
/// </summary>
public static class ServicesCollectionExtensions
{
/// <summary>
/// The key used to store the <see cref="IHandlersCollection"/> in the builder properties.
/// </summary>
public const string HandlersCollectionPropertyKey = nameof(IHandlersCollection);
namespace Telegrator;
/// <summary>
/// Provides extension methods for <see cref="IHostApplicationBuilder"/> to configure Telegrator.
/// </summary>
public static class WebHostBuilderExtensions
{
/// <summary>
/// Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
/// </summary>
public static ITelegramBotHostBuilder AddTelegratorWeb(this ITelegramBotHostBuilder builder, TelegratorOptions? options = null, IHandlersCollection? handlers = null, Action<ITelegramBotHostBuilder>? action = null)
public static IHostApplicationBuilder AddTelegratorWeb(this IHostApplicationBuilder builder, TelegratorOptions? options = null, IHandlersCollection? handlers = null)
{
AddTelegratorWebInternal(builder.Services, builder.Configuration, builder.Properties, ref handlers, options);
if (builder is TelegramBotWebHostBuilder telegramBotHostBuilder)
telegramBotHostBuilder._handlers = handlers;
action?.Invoke(builder);
return builder;
}
/// <summary>
/// Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
/// </summary>
public static IHostApplicationBuilder AddTelegratorWeb(this WebApplicationBuilder builder, TelegratorOptions? options = null, IHandlersCollection? handlers = null, Action<ITelegramBotHostBuilder>? action = null)
public static IHostApplicationBuilder AddTelegratorWeb(this IHostApplicationBuilder builder, TelegratorOptions? options = null, IHandlersCollection? handlers = null, Action<ITelegramBotHostBuilder>? action = null)
{
AddTelegratorWebInternal(builder.Services, builder.Configuration, ((IHostApplicationBuilder)builder).Properties, ref handlers, options);
action?.Invoke(new TelegramBotWebHostBuilder(builder, handlers));
AddTelegratorWebInternal(builder.Services, builder.Configuration, builder.Properties, ref handlers, options);
action?.Invoke(new TelegramBotHostBuilder(builder, handlers));
return builder;
}
@@ -55,11 +44,14 @@ namespace Telegrator
/// </summary>
internal static void AddTelegratorWebInternal(IServiceCollection services, IConfiguration configuration, IDictionary<object, object> properties, [NotNull] ref IHandlersCollection? handlers, TelegratorOptions? options = null)
{
if (options == null)
if (services.Any(srvc => srvc.ServiceType == typeof(HostedUpdateReceiver)))
throw new InvalidOperationException("`HostedUpdateReceiver` found in services. WebHost extension is not compatible with long-polling receiving. Please, remove `AddTelegrator` invocation from your WebApp configuration.");
if (options is null)
{
options = configuration.GetSection(nameof(TelegratorOptions)).Get<TelegratorOptions>();
if (options == null)
throw new MissingMemberException("Auto configuration disabled, yet no options of type 'TelegratorOptions' wasn't registered. This configuration is runtime required!");
if (options is null)
throw new MissingMemberException("Auto configuration disabled, yet no options of type 'TelegratorOptions' was registered. This configuration is runtime required!");
}
CancellationTokenSource globallCancell = new CancellationTokenSource();
@@ -67,25 +59,22 @@ namespace Telegrator
services.AddSingleton(Options.Create(options));
services.AddKeyedSingleton("cancell", globallCancell);
if (handlers != null)
{
if (handlers is IHandlersManager manager)
if (handlers is not null && handlers is IHandlersManager manager)
{
ServiceDescriptor descriptor = new ServiceDescriptor(typeof(IHandlersProvider), manager);
services.Replace(descriptor);
services.AddSingleton(manager);
}
}
handlers ??= new HostHandlersCollection(services, options);
services.AddSingleton(handlers);
properties.Add(HandlersCollectionPropertyKey, handlers);
properties.Add(HostBuilderExtensions.HandlersCollectionPropertyKey, handlers);
if (!services.Any(srvc => srvc.ImplementationType == typeof(IOptions<WebhookerOptions>)))
if (!services.Any(srvc => srvc.ServiceType == typeof(IOptions<WebhookerOptions>)))
{
WebhookerOptions? webhookerOptions = configuration.GetSection(nameof(WebhookerOptions)).Get<WebhookerOptions>();
if (webhookerOptions == null)
throw new MissingMemberException("Auto configuration disabled, yet no options of type 'WebhookerOptions' wasn't registered. This configuration is runtime required!");
throw new MissingMemberException("Auto configuration disabled, yet no options of type 'WebhookerOptions' was registered. This configuration is runtime required!");
services.AddSingleton(Options.Create(webhookerOptions));
}
@@ -102,6 +91,26 @@ namespace Telegrator
services.AddTelegramBotHostDefaults();
services.AddTelegramWebhook();
}
}
/// <summary>
/// Contains extensions for <see cref="IServiceCollection"/>
/// Provides method to configure Telegram Bot WebHost
/// </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;
}
/// <summary>
/// Searchs for <see cref="HostedUpdateWebhooker"/> hosted service inside hosts services
@@ -114,32 +123,41 @@ namespace Telegrator
webhooker = services.GetServices<IHostedService>().FirstOrDefault(s => s is HostedUpdateWebhooker) as HostedUpdateWebhooker;
return webhooker != null;
}
}
/// <summary>
/// Provides useful methods to adjust Telegram bot Host
/// </summary>
public static class WebTelegramBotHostExtensions
{
/// <summary>
/// Replaces the initialization logic from TelegramBotWebHost constructor.
/// Initializes the bot and logs handlers on application startup.
/// </summary>
public static T UseTelegratorWeb<T>(this T app, bool dontMap = false) where T : IEndpointRouteBuilder, IHost
public static T UseTelegratorWeb<T>(this T botHost, bool dontMap = false) where T : IEndpointRouteBuilder, IHost
{
if (!app.ServiceProvider.TryFindWebhooker(out HostedUpdateWebhooker? webhooker))
if (!botHost.ServiceProvider.TryFindWebhooker(out HostedUpdateWebhooker? webhooker))
throw new InvalidOperationException("No service for type 'Telegrator.Mediation.HostedUpdateWebhooker' has been registered.");
ITelegramBotInfo info = app.ServiceProvider.GetRequiredService<ITelegramBotInfo>();
IHandlersCollection handlers = app.ServiceProvider.GetRequiredService<IHandlersCollection>();
ILoggerFactory loggerFactory = app.ServiceProvider.GetRequiredService<ILoggerFactory>();
ITelegramBotInfo info = botHost.ServiceProvider.GetRequiredService<ITelegramBotInfo>();
IHandlersCollection handlers = botHost.ServiceProvider.GetRequiredService<IHandlersCollection>();
ILoggerFactory loggerFactory = botHost.ServiceProvider.GetRequiredService<ILoggerFactory>();
ILogger logger = loggerFactory.CreateLogger("Telegrator.Hosting.Web.TelegratorHost");
if (logger.IsEnabled(LogLevel.Information))
{
logger.LogInformation("Telegrator Bot ASP.NET WebHost started");
logger.LogInformation("Telegrator Bot Host started (ASP.NET WebHost)");
logger.LogInformation("Receiving mode : WEB-HOOKING");
logger.LogInformation("Telegram Bot : {firstname}, @{usrname}, id:{id},", info.User.FirstName ?? "[NULL]", info.User.Username ?? "[NULL]", info.User.Id);
logger.LogHandlers(handlers);
}
if (!dontMap)
webhooker.MapWebhook(app);
webhooker.MapWebhook(botHost);
return app;
botHost.AddLoggingAdapter();
botHost.SetBotCommands();
return botHost;
}
/// <summary>
@@ -165,6 +183,9 @@ namespace Telegrator
/// <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;
@@ -172,5 +193,4 @@ namespace Telegrator
private static ITelegramBotClient TypedTelegramBotClientFactory(HttpClient httpClient, IServiceProvider provider)
=> new TelegramBotClient(provider.GetRequiredService<IOptions<TelegramBotClientOptions>>().Value, httpClient);
}
}
@@ -0,0 +1,10 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Roslynator", "RCS1037")]
[assembly: SuppressMessage("Style", "IDE0090")]
[assembly: SuppressMessage("Style", "IDE0270")]
@@ -0,0 +1,39 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Telegram.Bot;
using Telegram.Bot.Polling;
using Telegrator.Core;
namespace Telegrator.Mediation;
/// <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)
throw new Exception("Registered ITelegramBotClient was not a wide client (WTelegramBotClient)! Please, use `AddWideTelegrator` instead.");
if (options?.Value.DropPendingUpdates is true)
await wideBotClient.DropPendingUpdates();
logger.LogInformation("Starting receiving updates via MTProto");
// UIP (understanding in progress)
//_receiverOptions.AllowedUpdates = updateRouter.HandlersProvider.AllowedTypes.ToArray();
botClient.DeleteWebhook(options?.Value.DropPendingUpdates ?? false, cancellationToken: stoppingToken)
.ConfigureAwait(false).GetAwaiter().GetResult();
WideUpdateReceiver updateReceiver = new WideUpdateReceiver(wideBotClient);
await updateReceiver.ReceiveAsync(updateRouter, stoppingToken).ConfigureAwait(false);
}
}
@@ -0,0 +1,57 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Telegram.Bot;
using Telegram.Bot.Polling;
using Telegrator.Core;
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;
_cancellation = cancellationToken;
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
await using CancellationTokenRegistration registration = cancellationToken.Register(() => tcs.TrySetResult(null!));
try
{
_client.OnUpdate += OnUpdate;
await tcs.Task.ConfigureAwait(false);
}
finally
{
_client.OnUpdate -= OnUpdate;
}
}
private async Task OnUpdate(WUpdate update)
{
if (_updateHandler == null)
throw new Exception("Router not initialized (got null)");
try
{
await _updateHandler.HandleUpdateAsync(_client, update, _cancellation).ConfigureAwait(false);
}
catch (Exception ex)
{
await _updateHandler.HandleErrorAsync(_client, ex, HandleErrorSource.HandleUpdateError, _cancellation).ConfigureAwait(false);
}
}
}
+1
View File
@@ -0,0 +1 @@

@@ -0,0 +1,43 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<RootNamespace>Telegrator</RootNamespace>
<BaseOutputPath>..\..\bin</BaseOutputPath>
<DocumentationFile>..\..\docs\$(AssemblyName).xml</DocumentationFile>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<EnableNETAnalyzers>True</EnableNETAnalyzers>
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
<Title>Telegrator.Hosting.WideBot</Title>
<Version>1.17.0</Version>
<Authors>Rikitav Tim4ik</Authors>
<Company>Rikitav Tim4ik</Company>
<RepositoryUrl>https://github.com/Rikitav/Telegrator</RepositoryUrl>
<PackageTags>telegram;bot;mediator;attributes;aspect;hosting;host;framework;easy;simple;handlers;wtelegrambot;userbot</PackageTags>
<PackageIcon>telegrator_nuget.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="WTelegramBot" Version="9.5.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Telegrator.Hosting\Telegrator.Hosting.csproj" />
</ItemGroup>
<ItemGroup>
<None Include=".\README.md" Pack="True" PackagePath="\" />
<None Include="..\..\LICENSE" Pack="True" PackagePath="\" />
<None Include="..\..\resources\telegrator_nuget.png" Pack="True" PackagePath="\" />
</ItemGroup>
</Project>
@@ -0,0 +1,107 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Net.Http;
using System.Threading;
using Telegram.Bot;
using Telegram.Bot.Polling;
using Telegrator.Core;
using Telegrator.Logging;
using Telegrator.Mediation;
using Telegrator.Providers;
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)
{
Options = telegratorOptions ?? new TelegratorOptions();
Handlers = new HandlersCollection(default);
BotInfo = new TelegramBotInfo(GetMe(cancellationToken).Result);
}
/// <inheritdoc/>
public void StartReceiving(ReceiverOptions? _, 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}");
StartReceivingInternal(Options.GlobalCancellationToken)
.ConfigureAwait(false).GetAwaiter().GetResult();
}
/// <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
{
try
{
await new HostedWideBotUpdateReceiver(NullLoggerFactory.Instance.CreateLogger<HostedWideBotUpdateReceiver>(), this, UpdateRouter, null)
.StartAsync(cancellationToken)
.ConfigureAwait(false);
}
catch (Exception exception)
{
await UpdateRouter
.HandleErrorAsync(this, exception, HandleErrorSource.FatalError, cancellationToken)
.ConfigureAwait(false);
}
}
catch (OperationCanceledException)
{
// Cancelled
TelegratorLogging.LogInformation("Telegrator bot stopped (cancelled)");
}
}
}
@@ -0,0 +1,268 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Diagnostics.CodeAnalysis;
using Telegram.Bot;
using Telegram.Bot.Types;
using Telegrator.Core;
using Telegrator.Core.Handlers;
using Telegrator.Hosting;
using Telegrator.Mediation;
using Telegrator.Providers;
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
{
object? client = handler.GetType().GetField("Client")?.GetValue(handler);
if (client is not WTelegramBotClient wideClient)
throw new InvalidCastException("Client is not assignable to `WTelegram.Bot.WTelegramBotClient`");
return wideClient;
}
}
/// <summary>
/// Casts Update to <see cref="WUpdate"/>
/// </summary>
public WUpdate WideUpdate
{
get
{
object? update = handler.GetType().GetField("HandlingUpdate")?.GetValue(handler);
if (update is not WUpdate wUpdate)
throw new InvalidCastException("Update is not assignable to `WTelegram.Types.Update`");
return wUpdate;
}
}
/// <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
?? throw new InvalidCastException("Update is not assignable to `WTelegram.Types.Update`");
}
}
/// <summary>
/// Provides extension methods for <see cref="IHostApplicationBuilder"/> to configure Telegrator.
/// </summary>
public static class WideHostBuilderExtensions
{
/// <summary>
/// Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
/// </summary>
public static IHostApplicationBuilder AddWideTelegrator(this IHostApplicationBuilder builder, TelegratorOptions? options = null, IHandlersCollection? handlers = null, Action<ITelegramBotHostBuilder>? action = null)
{
AddWideTelegratorInternal(builder.Services, builder.Configuration, builder.Properties, ref handlers, options);
action?.Invoke(new TelegramBotHostBuilder(builder, handlers));
return builder;
}
/// <summary>
/// Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
/// </summary>
public static IHostApplicationBuilder AddWideTelegrator(this IHostApplicationBuilder builder, TelegratorOptions? options = null, IHandlersCollection? handlers = null)
{
AddWideTelegratorInternal(builder.Services, builder.Configuration, builder.Properties, ref handlers, options);
return builder;
}
/// <summary>
/// Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
/// </summary>
internal static void AddWideTelegratorInternal(IServiceCollection services, IConfiguration configuration, IDictionary<object, object> properties, [NotNull] ref IHandlersCollection? handlers, TelegratorOptions? options = null)
{
if (services.Any(srvc => srvc.ServiceType == typeof(HostedUpdateReceiver)))
throw new InvalidOperationException("`HostedUpdateReceiver` found in services. WideHost extension is not compatible with default long-polling receiver. Please, remove `AddTelegrator` invocation from your Host configuration.");
if (services.Any(srvc => srvc.ServiceType.Name == "HostedUpdateWebhooker"))
throw new InvalidOperationException("`HostedUpdateWebhooker` found in services. WideHost extension is not compatible with webhooking yet. Please, remove `AddWebTelegrator` invocation from your Host configuration.");
if (options == null)
{
options = configuration.GetSection(nameof(TelegratorOptions)).Get<TelegratorOptions>();
if (options == null)
throw new MissingMemberException("Auto configuration disabled, yet no options of type 'TelegratorOptions' was registered. This configuration is runtime required!");
}
CancellationTokenSource globallCancell = new CancellationTokenSource();
options.GlobalCancellationToken = globallCancell.Token;
services.AddSingleton(Options.Create(options));
services.AddKeyedSingleton("cancell", globallCancell);
if (handlers != null)
{
if (handlers is IHandlersManager manager)
{
ServiceDescriptor descriptor = new ServiceDescriptor(typeof(IHandlersProvider), manager);
services.Replace(descriptor);
services.AddSingleton(manager);
}
}
handlers ??= new HostHandlersCollection(services, options);
services.AddSingleton(handlers);
properties.Add(HostBuilderExtensions.HandlersCollectionPropertyKey, handlers);
if (!services.Any(srvc => srvc.ServiceType == typeof(IOptions<WTelegramBotClientOptions>)))
{
// For now, there's no way to configure this from IConfiguration, use `ConfigureWideTelegram` instead
throw new MissingMemberException("No options of type 'WTelegramBotClientOptions' was registered. This configuration is runtime required! Use `ConfigureWideTelegram` to register options.");
/*
services.AddSingleton(Options.Create(new WTelegramBotClientOptions(options.Token, options.BaseUrl, options.UseTestEnvironment)
{
RetryCount = options.RetryCount,
RetryThreshold = options.RetryThreshold
}));
*/
}
services.AddTelegramBotHostDefaults();
services.AddMTProtoUpdateReceiver();
}
}
/// <summary>
/// Contains extensions for <see cref="IServiceCollection"/>
/// Provides method to configure Telegram Bot WebHost
/// </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;
}
/// <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.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>>();
WTelegramBotClient client = new WTelegramBotClient(provider.GetRequiredService<IOptions<WTelegramBotClientOptions>>().Value, httpClient);
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>
/// Provides useful methods to adjust Telegram bot Host
/// </summary>
public static class WideTelegramBotHostExtensions
{
/// <summary>
/// Replaces the initialization logic from TelegramBotWebHost constructor.
/// Initializes the bot and logs handlers on application startup.
/// </summary>
public static IHost UseWideTelegrator(this IHost botHost)
{
if (!botHost.Services.TryFindWTelegramBotClient())
throw new InvalidOperationException("No service for type 'Telegram.Bot.WTelegramBotClient' has been registered. Invoke `AddWideTelegrator`");
ITelegramBotInfo info = botHost.Services.GetRequiredService<ITelegramBotInfo>();
IHandlersCollection handlers = botHost.Services.GetRequiredService<IHandlersCollection>();
ILoggerFactory loggerFactory = botHost.Services.GetRequiredService<ILoggerFactory>();
ILogger logger = loggerFactory.CreateLogger("Telegrator.Hosting.Web.TelegratorHost");
if (logger.IsEnabled(LogLevel.Information))
{
logger.LogInformation("Telegrator WIDE Bot Host started (Generic Host)");
logger.LogInformation("Receiving mode : MTProto");
logger.LogInformation("Telegram Bot : {firstname}, @{usrname}, id:{id},", info.User.FirstName ?? "[NULL]", info.User.Username ?? "[NULL]", info.User.Id);
logger.LogHandlers(handlers);
}
botHost.AddLoggingAdapter();
botHost.SetBotCommands();
return botHost;
}
private static bool TryFindWTelegramBotClient(this IServiceProvider services)
{
return services.GetServices<IHostedService>().Any(s => s is HostedWideBotUpdateReceiver);
}
}
@@ -10,3 +10,4 @@ using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Usage", "CA2254")]
[assembly: SuppressMessage("Maintainability", "CA1510")]
[assembly: SuppressMessage("Style", "IDE0270")]
[assembly: SuppressMessage("Roslynator", "RCS1037")]
@@ -6,7 +6,4 @@ namespace Telegrator.Hosting;
/// <summary>
/// Represents a hosted telegram bots and services builder that helps manage configuration, logging, lifetime, and more.
/// </summary>
public interface ITelegramBotHostBuilder : IHostApplicationBuilder, ICollectingProvider
{
}
public interface ITelegramBotHostBuilder : IHostApplicationBuilder, ICollectingProvider;
@@ -1,114 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Telegrator.Core;
namespace Telegrator.Hosting;
/// <summary>
/// Represents a hosted telegram bot
/// </summary>
public class TelegramBotHost : IHost, ITelegratorBot
{
private readonly IHost _innerHost;
private readonly IUpdateRouter _updateRouter;
private readonly ILogger<TelegramBotHost> _logger;
private bool _disposed;
/// <inheritdoc/>
public IServiceProvider Services => _innerHost.Services;
/// <inheritdoc/>
public IUpdateRouter UpdateRouter => _updateRouter;
/// <summary>
/// This application's logger
/// </summary>
public ILogger<TelegramBotHost> Logger => _logger;
/// <summary>
/// Initializes a new instance of the <see cref="TelegramBotHost"/> class.
/// </summary>
/// <param name="hostApplicationBuilder">The proxied instance of host builder.</param>
public TelegramBotHost(HostApplicationBuilder hostApplicationBuilder)
{
// Registering this host in services for easy access
hostApplicationBuilder.Services.AddSingleton<ITelegratorBot>(this);
// Building proxy hoster
_innerHost = hostApplicationBuilder.Build();
// Reruesting services for this host
_updateRouter = Services.GetRequiredService<IUpdateRouter>();
_logger = Services.GetRequiredService<ILogger<TelegramBotHost>>();
}
/// <summary>
/// Creates new <see cref="TelegramBotHostBuilder"/> with default configuration, services and long-polling update receiving scheme
/// </summary>
/// <returns></returns>
public static TelegramBotHostBuilder CreateBuilder()
{
HostApplicationBuilder innerBuilder = new HostApplicationBuilder(settings: null);
TelegramBotHostBuilder builder = new TelegramBotHostBuilder(innerBuilder);
return builder;
}
/// <summary>
/// Creates new <see cref="TelegramBotHostBuilder"/> with default services and long-polling update receiving scheme
/// </summary>
/// <returns></returns>
public static TelegramBotHostBuilder CreateBuilder(HostApplicationBuilderSettings? settings)
{
HostApplicationBuilder innerBuilder = new HostApplicationBuilder(settings);
TelegramBotHostBuilder builder = new TelegramBotHostBuilder(innerBuilder);
return builder;
}
/// <summary>
/// Creates new EMPTY <see cref="TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes
/// </summary>
/// <returns></returns>
public static TelegramBotHostBuilder CreateEmptyBuilder()
{
HostApplicationBuilder innerBuilder = Host.CreateEmptyApplicationBuilder(null);
return new TelegramBotHostBuilder(innerBuilder);
}
/// <summary>
/// Creates new EMPTY <see cref="TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes
/// </summary>
/// <returns></returns>
public static TelegramBotHostBuilder CreateEmptyBuilder(HostApplicationBuilderSettings? settings)
{
HostApplicationBuilder innerBuilder = Host.CreateEmptyApplicationBuilder(settings);
return new TelegramBotHostBuilder(innerBuilder);
}
/// <inheritdoc/>
public async Task StartAsync(CancellationToken cancellationToken = default)
{
await _innerHost.StartAsync(cancellationToken);
}
/// <inheritdoc/>
public async Task StopAsync(CancellationToken cancellationToken = default)
{
await _innerHost.StopAsync(cancellationToken);
}
/// <summary>
/// Disposes the host.
/// </summary>
public void Dispose()
{
if (_disposed)
return;
_innerHost.Dispose();
GC.SuppressFinalize(this);
_disposed = true;
}
}
@@ -11,7 +11,7 @@ namespace Telegrator.Hosting;
/// <inheritdoc/>
public class TelegramBotHostBuilder : ITelegramBotHostBuilder
{
private readonly HostApplicationBuilder _innerBuilder;
private readonly IHostApplicationBuilder _innerBuilder;
internal IHandlersCollection _handlers = null!;
/// <inheritdoc/>
@@ -30,7 +30,7 @@ public class TelegramBotHostBuilder : ITelegramBotHostBuilder
public IHostEnvironment Environment => _innerBuilder.Environment;
/// <inheritdoc/>
public IDictionary<object, object> Properties => ((IHostApplicationBuilder)_innerBuilder).Properties;
public IDictionary<object, object> Properties => _innerBuilder.Properties;
/// <inheritdoc/>
public IMetricsBuilder Metrics => _innerBuilder.Metrics;
@@ -39,7 +39,7 @@ public class TelegramBotHostBuilder : ITelegramBotHostBuilder
/// Initializes a new instance of the <see cref="TelegramBotHostBuilder"/> class.
/// </summary>
/// <param name="hostApplicationBuilder"></param>
public TelegramBotHostBuilder(HostApplicationBuilder hostApplicationBuilder)
public TelegramBotHostBuilder(IHostApplicationBuilder hostApplicationBuilder)
{
_innerBuilder = hostApplicationBuilder ?? throw new ArgumentNullException(nameof(hostApplicationBuilder));
}
@@ -49,23 +49,12 @@ public class TelegramBotHostBuilder : ITelegramBotHostBuilder
/// </summary>
/// <param name="hostApplicationBuilder"></param>
/// <param name="handlers"></param>
public TelegramBotHostBuilder(HostApplicationBuilder hostApplicationBuilder, IHandlersCollection handlers)
public TelegramBotHostBuilder(IHostApplicationBuilder hostApplicationBuilder, IHandlersCollection handlers)
{
_innerBuilder = hostApplicationBuilder ?? throw new ArgumentNullException(nameof(hostApplicationBuilder));
_handlers = handlers ?? throw new ArgumentNullException(nameof(handlers));
}
/// <summary>
/// Builds the host.
/// </summary>
/// <returns></returns>
public TelegramBotHost Build()
{
TelegramBotHost host = new TelegramBotHost(_innerBuilder);
host.UseTelegrator();
return host;
}
/// <inheritdoc/>
public void ConfigureContainer<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory, Action<TContainerBuilder>? configure = null) where TContainerBuilder : notnull
{
@@ -32,11 +32,13 @@ public class MicrosoftLoggingAdapter : ITelegratorLogger
if (exception != null)
{
_logger.Log(msLogLevel, default, message, exception, (str, exc) => string.Format("{0} : {1}", str, exc));
_logger.Log(msLogLevel, default, message, exception,
(str, exc) => string.Format("{0} : {1}", str, exc));
}
else
{
_logger.Log(msLogLevel, default, message, null, (str, _) => str);
_logger.Log(msLogLevel, default, message, null,
(str, _) => str);
}
}
}
@@ -5,9 +5,8 @@ using Telegram.Bot.Polling;
using Telegram.Bot.Types;
using Telegrator.Core;
using Telegrator.Core.States;
using Telegrator.Mediation;
namespace Telegrator.Polling;
namespace Telegrator.Mediation;
/// <inheritdoc/>
public class HostUpdateRouter : UpdateRouter
@@ -4,12 +4,11 @@ using Microsoft.Extensions.Options;
using Telegram.Bot;
using Telegram.Bot.Polling;
using Telegrator.Core;
using Telegrator.Mediation;
namespace Telegrator.Polling;
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>
@@ -26,7 +25,8 @@ public class HostedUpdateReceiver(ITelegramBotClient botClient, IUpdateRouter up
logger.LogInformation("Starting receiving updates via long-polling");
_receiverOptions.AllowedUpdates = _updateRouter.HandlersProvider.AllowedTypes.ToArray();
botClient.DeleteWebhook(options.Value.DropPendingUpdates).Wait();
botClient.DeleteWebhook(options.Value.DropPendingUpdates, cancellationToken: stoppingToken)
.ConfigureAwait(false).GetAwaiter().GetResult();
DefaultUpdateReceiver updateReceiver = new DefaultUpdateReceiver(botClient, _receiverOptions);
await updateReceiver.ReceiveAsync(_updateRouter, stoppingToken).ConfigureAwait(false);
@@ -17,41 +17,60 @@ public class HostHandlersCollection(IServiceCollection hostServiceColletion, Tel
{
switch (descriptor.Type)
{
default:
throw new Exception("Unknown descriptor type");
case DescriptorType.General:
{
if (descriptor.InstanceFactory != null)
{
Services.AddScoped(descriptor.HandlerType, _ => descriptor.InstanceFactory.Invoke());
else
Services.AddScoped(descriptor.HandlerType);
break;
}
Services.AddScoped(descriptor.HandlerType);
break;
}
case DescriptorType.Keyed:
{
if (descriptor.InstanceFactory != null)
{
Services.AddKeyedScoped(descriptor.HandlerType, descriptor.ServiceKey, (_, _) => descriptor.InstanceFactory.Invoke());
else
Services.AddKeyedScoped(descriptor.HandlerType, descriptor.ServiceKey);
break;
}
Services.AddKeyedScoped(descriptor.HandlerType, descriptor.ServiceKey);
break;
}
case DescriptorType.Singleton:
{
Services.AddSingleton(descriptor.HandlerType, descriptor.SingletonInstance ?? (descriptor.InstanceFactory != null
? descriptor.InstanceFactory.Invoke()
: throw new Exception()));
if (descriptor.SingletonInstance != null)
{
Services.AddSingleton(descriptor.HandlerType, descriptor.SingletonInstance);
break;
}
if (descriptor.InstanceFactory == null)
throw new InvalidOperationException("Singleton handler descriptor without singleton instance should implement `InstanceFactory`");
Services.AddSingleton(descriptor.HandlerType, descriptor.InstanceFactory.Invoke());
break;
}
case DescriptorType.Implicit:
{
Services.AddKeyedSingleton(descriptor.HandlerType, descriptor.ServiceKey, descriptor.SingletonInstance ?? (descriptor.InstanceFactory != null
? descriptor.InstanceFactory.Invoke()
: throw new Exception()));
if (descriptor.SingletonInstance != null)
{
Services.AddKeyedSingleton(descriptor.HandlerType, descriptor.ServiceKey, descriptor.SingletonInstance);
break;
}
if (descriptor.InstanceFactory == null)
throw new InvalidOperationException("Implicit handler descriptor without singleton instance should implement `InstanceFactory`");
Services.AddKeyedSingleton(descriptor.HandlerType, descriptor.ServiceKey, descriptor.InstanceFactory.Invoke());
break;
}
}
@@ -15,7 +15,7 @@
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
<Title>Telegrator.Hosting</Title>
<Version>1.16.9</Version>
<Version>1.17.0</Version>
<Authors>Rikitav Tim4ik</Authors>
<Company>Rikitav Tim4ik</Company>
<RepositoryUrl>https://github.com/Rikitav/Telegrator</RepositoryUrl>
+57 -23
View File
@@ -15,7 +15,7 @@ using Telegrator.Core.Descriptors;
using Telegrator.Core.States;
using Telegrator.Hosting;
using Telegrator.Logging;
using Telegrator.Polling;
using Telegrator.Mediation;
using Telegrator.Providers;
using Telegrator.States;
@@ -34,20 +34,7 @@ public static class HostBuilderExtensions
/// <summary>
/// Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
/// </summary>
public static ITelegramBotHostBuilder AddTelegrator(this ITelegramBotHostBuilder builder, TelegratorOptions? options = null, IHandlersCollection? handlers = null, Action<ITelegramBotHostBuilder>? action = null)
{
AddTelegratorInternal(builder.Services, builder.Configuration, builder.Properties, ref handlers, options);
if (builder is TelegramBotHostBuilder telegramBotHostBuilder)
telegramBotHostBuilder._handlers = handlers;
action?.Invoke(builder);
return builder;
}
/// <summary>
/// Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
/// </summary>
public static IHostApplicationBuilder AddTelegrator(this HostApplicationBuilder builder, TelegratorOptions? options = null, IHandlersCollection? handlers = null, Action<ITelegramBotHostBuilder>? action = null)
public static IHostApplicationBuilder AddTelegrator(this IHostApplicationBuilder builder, TelegratorOptions? options = null, IHandlersCollection? handlers = null, Action<ITelegramBotHostBuilder>? action = null)
{
AddTelegratorInternal(builder.Services, builder.Configuration, ((IHostApplicationBuilder)builder).Properties, ref handlers, options);
action?.Invoke(new TelegramBotHostBuilder(builder, handlers));
@@ -72,6 +59,16 @@ public static class HostBuilderExtensions
return builder;
}
/// <summary>
/// Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
/// </summary>
public static IHostBuilder AddTelegrator(this IHostBuilder builder, TelegratorOptions? options = null, IHandlersCollection? handlers = null, Action<IHandlersCollection>? action = null)
{
builder.ConfigureServices((ctx, sp) => AddTelegratorInternal(sp, ctx.Configuration, builder.Properties, ref handlers, options));
action?.Invoke(handlers!); // AddTelegratorInternal initializes `handlers`
return builder;
}
/// <summary>
/// Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
/// </summary>
@@ -81,7 +78,7 @@ public static class HostBuilderExtensions
{
options = configuration.GetSection(nameof(TelegratorOptions)).Get<TelegratorOptions>();
if (options == null)
throw new MissingMemberException("Auto configuration disabled, yet no options of type 'TelegratorOptions' wasn't registered. This configuration is runtime required!");
throw new MissingMemberException("Auto configuration disabled, yet no options of type 'TelegratorOptions' was registered. This configuration is runtime required!");
}
CancellationTokenSource globallCancell = new CancellationTokenSource();
@@ -103,11 +100,11 @@ public static class HostBuilderExtensions
services.AddSingleton(handlers);
properties.Add(HandlersCollectionPropertyKey, handlers);
if (!services.Any(srvc => srvc.ImplementationType == typeof(IOptions<ReceiverOptions>)))
if (!services.Any(srvc => srvc.ServiceType == typeof(IOptions<ReceiverOptions>)))
{
ReceiverOptions? receiverOptions = configuration.GetSection(nameof(ReceiverOptions)).Get<ReceiverOptions>();
if (receiverOptions == null)
throw new MissingMemberException("Auto configuration disabled, yet no options of type 'ReceiverOptions' wasn't registered. This configuration is runtime required!");
throw new MissingMemberException("Auto configuration disabled, yet no options of type 'ReceiverOptions' was registered. This configuration is runtime required!");
services.AddSingleton(Options.Create(receiverOptions));
}
@@ -130,8 +127,34 @@ public static class HostBuilderExtensions
/// Contains extensions for <see cref="IServiceCollection"/>
/// Provides method to configure Telegram Bot Host
/// </summary>
public static class ServicesCollectionExtensions
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;
}
/// <summary>
/// Registers <see cref="IStateStorage"/> service
/// </summary>
@@ -145,7 +168,7 @@ public static class ServicesCollectionExtensions
}
/// <summary>
/// Registers <see cref="TelegramBotHost"/> default services
/// Registers <see cref="Telegrator"/> default services
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
@@ -167,6 +190,9 @@ public static class ServicesCollectionExtensions
/// <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;
@@ -200,11 +226,14 @@ public static class TelegramBotHostExtensions
if (logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Information))
{
logger.LogInformation("Telegrator Bot .NET Host started");
logger.LogInformation("Telegrator Bot Host started (Generic Host)");
logger.LogInformation("Receiving mode : LONG-POLLING");
logger.LogInformation("Telegram Bot : {firstname}, @{usrname}, id:{id},", info.User.FirstName ?? "[NULL]", info.User.Username ?? "[NULL]", info.User.Id);
logger.LogHandlers(handlers);
}
botHost.AddLoggingAdapter();
botHost.SetBotCommands();
return botHost;
}
@@ -219,7 +248,12 @@ public static class TelegramBotHostExtensions
IUpdateRouter router = botHost.Services.GetRequiredService<IUpdateRouter>();
IEnumerable<BotCommand> aliases = router.HandlersProvider.GetBotCommands();
client.SetMyCommands(aliases).Wait();
if (aliases.Any())
{
client.SetMyCommands(aliases)
.ConfigureAwait(false).GetAwaiter().GetResult();
}
return botHost;
}
@@ -255,7 +289,7 @@ public static class LoggerExtensions
StringBuilder logBuilder = new StringBuilder("Registered handlers : ");
if (!handlers.Keys.Any())
throw new Exception();
throw new Exception("No update types were registered");
foreach (UpdateType updateType in handlers.Keys)
{
@@ -125,7 +125,8 @@ public sealed class DescriptorFiltersSet
if (!anyErrors)
return Result.Ok();
return formReport ? Result.Next() : Result.Fault();
return formReport
? Result.Next() : Result.Fault();
}
private static bool ExecuteFilter<T>(IFilter<T> filter, FilterExecutionContext<T> context, out Exception? exception) where T : class
@@ -1,4 +1,7 @@
using System.ComponentModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
@@ -21,6 +24,11 @@ public static class HandlerInspector
/// <returns></returns>
public static string? GetDisplayName(MemberInfo handlerType)
{
if (handlerType == null)
{
throw new ArgumentNullException(nameof(handlerType));
}
return handlerType.GetCustomAttribute<DisplayNameAttribute>()?.DisplayName;
}
@@ -31,11 +39,26 @@ public static class HandlerInspector
/// <returns>The handler attribute.</returns>
public static UpdateHandlerAttributeBase GetHandlerAttribute(MemberInfo handlerType)
{
// Getting polling handler attribute
IEnumerable<UpdateHandlerAttributeBase> handlerAttrs = handlerType.GetCustomAttributes<UpdateHandlerAttributeBase>();
if (handlerType == null)
{
throw new ArgumentNullException(nameof(handlerType));
}
//
return handlerAttrs.Single();
List<UpdateHandlerAttributeBase> handlerAttrs = handlerType.GetCustomAttributes<UpdateHandlerAttributeBase>().ToList();
if (handlerAttrs.Count == 0)
{
throw new InvalidOperationException(
$"Failed to register handler '{handlerType.Name}': Missing required attribute derived from '{nameof(UpdateHandlerAttributeBase)}'.");
}
if (handlerAttrs.Count > 1)
{
throw new InvalidOperationException(
$"Failed to register handler '{handlerType.Name}': Multiple handler attributes found. A handler must have exactly one attribute derived from '{nameof(UpdateHandlerAttributeBase)}'.");
}
return handlerAttrs[0];
}
/// <summary>
@@ -45,10 +68,16 @@ public static class HandlerInspector
/// <returns>The state keeper attribute, or null if not present.</returns>
public static IFilter<Update>? GetStateKeeperAttribute(MemberInfo handlerType)
{
// Getting polling handler attribute
Attribute stateAttr = handlerType.GetCustomAttribute(typeof(StateAttribute<,>));
if (handlerType == null)
throw new ArgumentNullException(nameof(handlerType));
Attribute? stateAttr = handlerType.GetCustomAttributes()
.FirstOrDefault(attr =>
{
Type type = attr.GetType();
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(StateAttribute<,>);
});
//
return stateAttr as IFilter<Update>;
}
@@ -60,12 +89,19 @@ public static class HandlerInspector
/// <returns>An enumerable of filter attributes.</returns>
public static IEnumerable<IFilter<Update>> GetFilterAttributes(MemberInfo handlerType, UpdateType validUpdType)
{
//
IEnumerable<UpdateFilterAttributeBase> filters = handlerType.GetCustomAttributes<UpdateFilterAttributeBase>();
if (handlerType == null)
throw new ArgumentNullException(nameof(handlerType));
//
if (filters.Any(filterAttr => !filterAttr.AllowedTypes.Contains(validUpdType)))
throw new InvalidOperationException();
List<UpdateFilterAttributeBase> filters = handlerType.GetCustomAttributes<UpdateFilterAttributeBase>().ToList();
UpdateFilterAttributeBase? invalidFilter = filters.FirstOrDefault(f => !f.AllowedTypes.Contains(validUpdType));
if (invalidFilter != null)
{
string allowedTypesStr = string.Join(", ", invalidFilter.AllowedTypes);
throw new InvalidOperationException(
$"Filter conflict on handler '{handlerType.Name}': The filter '{invalidFilter.GetType().Name}' " +
$"does not support update type '{validUpdType}'. Allowed types: [{allowedTypesStr}].");
}
UpdateFilterAttributeBase? lastFilterAttribute = null;
foreach (UpdateFilterAttributeBase filterAttribute in filters)
@@ -78,7 +114,6 @@ public static class HandlerInspector
else
{
lastFilterAttribute = filterAttribute;
continue;
}
}
}
@@ -91,8 +126,24 @@ public static class HandlerInspector
/// <returns>A <see cref="DescriptorAspectsSet"/> containing the aspects configuration.</returns>
public static DescriptorAspectsSet GetAspects(Type handlerType)
{
Type? typedPre = handlerType.GetCustomAttribute(typeof(BeforeExecutionAttribute<>))?.GetType().GetGenericArguments()[0];
Type? typedPost = handlerType.GetCustomAttribute(typeof(AfterExecutionAttribute<>))?.GetType().GetGenericArguments()[0];
if (handlerType == null)
throw new ArgumentNullException(nameof(handlerType));
Type? typedPre = GetGenericArgumentFromOpenGenericAttribute(handlerType, typeof(BeforeExecutionAttribute<>));
Type? typedPost = GetGenericArgumentFromOpenGenericAttribute(handlerType, typeof(AfterExecutionAttribute<>));
return new DescriptorAspectsSet(typedPre, typedPost);
}
private static Type? GetGenericArgumentFromOpenGenericAttribute(Type handlerType, Type openGenericAttributeType)
{
Attribute? attribute = handlerType.GetCustomAttributes()
.FirstOrDefault(attr =>
{
Type type = attr.GetType();
return type.IsGenericType && type.GetGenericTypeDefinition() == openGenericAttributeType;
});
return attribute?.GetType().GetGenericArguments().FirstOrDefault();
}
}
@@ -56,7 +56,7 @@ public abstract class UpdateHandlerBase(UpdateType handlingUpdateType) : IUpdate
.ExecutePre(this, container, cancellationToken)
.ConfigureAwait(false);
if (!preResult.Positive)
if (!preResult.Success)
return preResult;
}
catch (NotImplementedException)
@@ -69,7 +69,7 @@ public abstract class UpdateHandlerBase(UpdateType handlingUpdateType) : IUpdate
{
// Executing handler
Result execResult = await ExecuteInternal(container, cancellationToken).ConfigureAwait(false);
if (!execResult.Positive)
if (!execResult.Success)
return execResult;
}
catch (NotImplementedException)
@@ -86,7 +86,7 @@ public abstract class UpdateHandlerBase(UpdateType handlingUpdateType) : IUpdate
.ExecutePost(this, container, cancellationToken)
.ConfigureAwait(false);
if (!postResult.Positive)
if (!postResult.Success)
return postResult;
}
}
@@ -166,7 +166,7 @@ public abstract class UpdateHandlerBase(UpdateType handlingUpdateType) : IUpdate
/// <returns></returns>
public virtual Task<Result> FiltersFallback(FiltersFallbackReport report, ITelegramBotClient client, CancellationToken cancellationToken = default)
{
return Task.FromResult(Result.Ok());
return Task.FromResult(Result.Next());
}
/// <inheritdoc/>
+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);
}
+15 -28
View File
@@ -19,27 +19,22 @@ namespace Telegrator.Mediation;
/// </summary>
public class UpdateRouter : IUpdateRouter
{
private readonly TelegratorOptions _options;
private readonly IHandlersProvider _handlersProvider;
private readonly IAwaitingProvider _awaitingProvider;
private readonly IStateStorage _stateStorage;
private readonly IUpdateHandlersPool _HandlersPool;
private readonly ITelegramBotInfo _botInfo;
/// <inheritdoc/>
public IHandlersProvider HandlersProvider => _handlersProvider;
public TelegratorOptions Options { get; }
/// <inheritdoc/>
public IAwaitingProvider AwaitingProvider => _awaitingProvider;
public IHandlersProvider HandlersProvider { get; }
/// <inheritdoc/>
public IStateStorage StateStorage => _stateStorage;
public IAwaitingProvider AwaitingProvider { get; }
/// <inheritdoc/>
public TelegratorOptions Options => _options;
public IStateStorage StateStorage { get; }
/// <inheritdoc/>
public IUpdateHandlersPool HandlersPool => _HandlersPool;
public IUpdateHandlersPool HandlersPool { get; }
/// <inheritdoc/>
public IRouterExceptionHandler? ExceptionHandler { get; set; }
@@ -57,11 +52,11 @@ public class UpdateRouter : IUpdateRouter
/// <param name="botInfo"></param>
public UpdateRouter(IHandlersProvider handlersProvider, IAwaitingProvider awaitingProvider, IStateStorage stateStorage, TelegratorOptions options, ITelegramBotInfo botInfo)
{
_options = options;
_handlersProvider = handlersProvider;
_awaitingProvider = awaitingProvider;
_stateStorage = stateStorage;
_HandlersPool = new UpdateHandlersPool(this, _options, _options.GlobalCancellationToken);
Options = options;
HandlersProvider = handlersProvider;
AwaitingProvider = awaitingProvider;
StateStorage = stateStorage;
HandlersPool = new UpdateHandlersPool(this, Options, Options.GlobalCancellationToken);
_botInfo = botInfo;
}
@@ -102,11 +97,8 @@ public class UpdateRouter : IUpdateRouter
Result? lastResult = null;
foreach (DescribedHandlerDescriptor handlerInfo in GetHandlers(AwaitingProvider, botClient, update, cancellationToken))
{
if (lastResult?.NextType != null)
{
if (lastResult.NextType != handlerInfo.From.HandlerType)
if (lastResult?.NextType is not null && lastResult?.NextType != handlerInfo.From.HandlerType)
continue;
}
// Enqueuing found awiting handlers
await HandlersPool.Enqueue(handlerInfo);
@@ -116,7 +108,7 @@ public class UpdateRouter : IUpdateRouter
if (lastResult == null)
break; // Smth went horribly wrong, better to stop routing
if (lastResult != null && !lastResult.RouteNext)
if (!lastResult.RouteNext)
break;
TelegratorLogging.LogTrace("Handler '{0}' requested route continuation (Update {1})", handlerInfo.DisplayString, handlerInfo.HandlingUpdate.Id);
@@ -132,11 +124,8 @@ public class UpdateRouter : IUpdateRouter
// Queuing reagular handlers for execution
foreach (DescribedHandlerDescriptor handlerInfo in GetHandlers(HandlersProvider, botClient, update, cancellationToken))
{
if (lastResult?.NextType != null)
{
if (lastResult.NextType != handlerInfo.From.HandlerType)
if (lastResult?.NextType is not null && lastResult?.NextType != handlerInfo.From.HandlerType)
continue;
}
// Enqueuing found handlers
await HandlersPool.Enqueue(handlerInfo);
@@ -146,7 +135,7 @@ public class UpdateRouter : IUpdateRouter
if (lastResult == null)
break; // Smth went horribly wrong, better to stop routing
if (lastResult != null && !lastResult.RouteNext)
if (!lastResult.RouteNext)
break;
TelegratorLogging.LogTrace("Handler '{0}' requested route continuation (Update {1})", handlerInfo.DisplayString, handlerInfo.HandlingUpdate.Id);
@@ -255,7 +244,7 @@ public class UpdateRouter : IUpdateRouter
breakRouting = !fallbackResult.RouteNext;
return null;
}
else if (!filtersResult.Positive)
else if (!filtersResult.Success)
{
return null;
}
@@ -307,6 +296,4 @@ public class UpdateRouter : IUpdateRouter
TelegratorLogging.LogTrace(sb.ToString());
}
private class BreakDescribingException : Exception { }
}
+5 -5
View File
@@ -15,12 +15,12 @@ public sealed class Result
private static readonly Result next = new Result(true, true, null);
/// <summary>
/// Is result positive
/// Tell router to stop describing
/// </summary>
public bool Positive { get; }
public bool Success { get; }
/// <summary>
/// Should router search for next matching handler
/// Tell router to continue describing
/// </summary>
public bool RouteNext { get; }
@@ -29,9 +29,9 @@ public sealed class Result
/// </summary>
public Type? NextType { get; }
internal Result(bool positive, bool routeNext, Type? nextType)
internal Result(bool success, bool routeNext, Type? nextType)
{
Positive = positive;
Success = success;
RouteNext = routeNext;
NextType = nextType;
}
+18 -1
View File
@@ -26,6 +26,21 @@ public static partial class ColletionsExtensions
return new ReadOnlyDictionary<TKey, TValue>(dictionary);
}
/// <summary>
/// Remove all <see langword="null"/> values and returns collection without nullable type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <returns></returns>
public static IEnumerable<T> Squeeze<T>(this IEnumerable<T?> source)
{
foreach (T? item in source)
{
if (item is not null)
yield return item;
}
}
/// <summary>
/// Enumerates objects in a <paramref name="source"/> and executes an <paramref name="action"/> on each one
/// </summary>
@@ -188,7 +203,7 @@ public static partial class ReflectionExtensions
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static bool IsHandlerRealization(this Type type)
public static bool IsHandlerImplementation(this Type type)
=> !type.IsAbstract && type != typeof(UpdateHandlerBase) && typeof(UpdateHandlerBase).IsAssignableFrom(type);
/// <summary>
@@ -260,6 +275,7 @@ public static partial class StringExtensions
{
char[] chars = target.ToCharArray();
int index = chars.IndexOf(char.IsLetter);
chars[index] = char.ToUpper(chars[index]);
return new string(chars);
}
@@ -273,6 +289,7 @@ public static partial class StringExtensions
{
char[] chars = target.ToCharArray();
int index = chars.IndexOf(char.IsLetter);
chars[index] = char.ToLower(chars[index]);
return new string(chars);
}
+2 -3
View File
@@ -14,7 +14,7 @@
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
<Title>Telegrator : Telegram.Bot mediator framework</Title>
<Version>1.16.9</Version>
<Version>1.17.0</Version>
<Authors>Rikitav Tim4ik</Authors>
<Company>Rikitav Tim4ik</Company>
<RepositoryUrl>https://github.com/Rikitav/Telegrator</RepositoryUrl>
@@ -23,7 +23,6 @@
<PackageIcon>telegrator_nuget.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<UserSecretsId>b78bc62d-e49f-4ef0-b2de-ff4ceb3971af</UserSecretsId>
</PropertyGroup>
<ItemGroup>
@@ -33,7 +32,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Telegram.Bot" Version="22.9.6.1" />
<PackageReference Include="Telegram.Bot" Version="22.9.5.3" />
<PackageReference Include="System.Threading.Channels" Version="10.0.7" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.7" />
</ItemGroup>
+9 -19
View File
@@ -20,16 +20,16 @@ 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 { get => updateRouter ?? throw new Exception(); }
public IUpdateRouter UpdateRouter => updateRouter ?? throw new InvalidOperationException("Router's not created yet. Invoke `StartReceiving` to initialize this property.");
/// <summary>
/// Initializes a new instance of the <see cref="TelegratorClient"/> class with a bot token.
@@ -63,13 +63,8 @@ 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="cancellationToken">The cancellation token to stop receiving updates.</param>
public void StartReceiving(ReceiverOptions? receiverOptions = null, CancellationToken cancellationToken = default)
/// <inheritdoc/>
public async Task StartReceivingAsync(ReceiverOptions? receiverOptions = null, CancellationToken cancellationToken = default)
{
if (Options.GlobalCancellationToken == CancellationToken.None)
Options.GlobalCancellationToken = cancellationToken;
@@ -78,12 +73,9 @@ public class TelegratorClient : TelegramBotClient, ITelegratorBot, ICollectingPr
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, cancellationToken);
updateRouter = new UpdateRouter(handlerProvider, awaitingProvider, stateStorage, Options, BotInfo);
await StartReceivingInternal(receiverOptions, Options.GlobalCancellationToken);
}
/// <summary>
@@ -92,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
{
@@ -115,6 +107,4 @@ public class TelegratorClient : TelegramBotClient, ITelegratorBot, ICollectingPr
TelegratorLogging.LogInformation("Telegrator bot stopped (cancelled)");
}
}
}
+41 -2
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>
@@ -412,6 +431,26 @@ public static partial class HandlersCollectionExtensions
"Ocelot", "BouncyCastle", "IdentityModel", "Telegrator"
];
/// <summary>
/// Collects all handlers from current app domain.
/// Scans for handlers exported by analyzer into class `Telegrator.Analyzers.AnalyzerExport` in each assembly and registers them to the collection.
/// </summary>
/// <param name="handlers"></param>
/// <returns></returns>
public static IHandlersCollection CollectHandlers(this IHandlersCollection handlers)
{
const string exportClassName = "Telegrator.Analyzers.AnalyzerExport";
AppDomain.CurrentDomain.GetAssemblies()
.Select(ass => ass.GetType(exportClassName))
.Squeeze()
.SelectMany(t => t.GetFields())
.Select(f => f.GetValue(null) as Type)
.Squeeze()
.ForEach(v => handlers.AddHandler(v));
return handlers;
}
/// <summary>
/// Collects all public handlers from the current app domain.
/// Scans for types that implement handlers and adds them to the collection.
@@ -438,7 +477,7 @@ public static partial class HandlersCollectionExtensions
{
(collectingTarget ?? Assembly.GetCallingAssembly())
.GetExportedTypes()
.Where(type => type.GetCustomAttribute<DontCollectAttribute>() == null && type.IsHandlerRealization())
.Where(type => type.GetCustomAttribute<DontCollectAttribute>() == null && type.IsHandlerImplementation())
.ForEach(type => handlers.AddHandler(type));
return handlers;
@@ -496,7 +535,7 @@ public static partial class HandlersCollectionExtensions
/// <exception cref="Exception">Thrown when the type is not a valid handler implementation.</exception>
public static IHandlersCollection AddHandler(this IHandlersCollection handlers, Type handlerType)
{
if (!handlerType.IsHandlerRealization())
if (!handlerType.IsHandlerImplementation())
throw new Exception();
if (handlerType.IsCustomDescriptorsProvider())
@@ -0,0 +1,8 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Roslynator", "RCS1037")]
+63
View File
@@ -0,0 +1,63 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Data.Sqlite;
using Microsoft.Extensions.Hosting;
using System.Data.Common;
using Telegram.Bot;
namespace Telegrator.Tests;
internal static class Program
{
public static void HostApplicationBuilder_Example(string[] args)
{
HostApplicationBuilder builder = Host.CreateApplicationBuilder(new HostApplicationBuilderSettings()
{
Args = args,
ApplicationName = "Host example",
});
builder.AddTelegrator(action: builder => builder.Handlers
.CollectHandlersAssemblyWide());
builder.Build()
.UseTelegrator()
.Run();
}
public static void WideBotApplicationBuilder_Example(string[] args)
{
HostApplicationBuilder builder = Host.CreateApplicationBuilder(new HostApplicationBuilderSettings()
{
Args = args,
ApplicationName = "WBot example",
});
using DbConnection connection = new SqliteConnection("Data Source=wtgb.db");
builder.Services.ConfigureWideTelegram(
new WTelegramBotClientOptions(token: "BOT_TOKEN", apiId: 123, apiHash: "API_HASH", dbConnection: connection));
builder.AddWideTelegrator(action: builder => builder.Handlers
.CollectHandlersAssemblyWide());
builder.Build()
.UseWideTelegrator()
.Run();
}
public static void WebApplicationBuilder_Example(string[] args)
{
WebApplicationBuilder builder = WebApplication.CreateBuilder(new WebApplicationOptions()
{
Args = args,
ApplicationName = "WebApplication example",
});
builder.AddTelegratorWeb(action: builder => builder.Handlers
.CollectHandlersAssemblyWide());
builder.Build()
.UseTelegratorWeb(dontMap: true)
.RemapWebhook("https://amazing-butt-sex.cloudpub.ru/")
.Run();
}
}
@@ -9,6 +9,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.7" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit" Version="2.6.6" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6" />
@@ -18,6 +19,10 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Telegartor.RedisStateStorage\Telegartor.RedisStateStorage.csproj" />
<ProjectReference Include="..\..\src\Telegrator.Hosting.Web\Telegrator.Hosting.Web.csproj" />
<ProjectReference Include="..\..\src\Telegrator.Hosting.WideBot\Telegrator.Hosting.WideBot.csproj" />
<ProjectReference Include="..\..\src\Telegrator.Localized\Telegrator.Localized.csproj" />
<ProjectReference Include="..\..\src\Telegrator\Telegrator.csproj" />
<ProjectReference Include="..\..\src\Telegrator.Hosting\Telegrator.Hosting.csproj" />
</ItemGroup>
+8 -10
View File
@@ -1,16 +1,15 @@
using Telegram.Bot.Types;
using Telegrator.Handlers;
namespace Telegrator.Tests
namespace Telegrator.Tests;
/// <summary>
/// Вспомогательный класс для тестирования абстрактного UpdateHandlerBase.
/// ПРИНЦИП: Создание тестовых двойников для абстрактных классов
/// </summary>
[MessageHandler]
internal class TestUpdateHandler : MessageHandler
{
/// <summary>
/// Вспомогательный класс для тестирования абстрактного UpdateHandlerBase.
///
/// ПРИНЦИП: Создание тестовых двойников для абстрактных классов
/// </summary>
[MessageHandler]
internal class TestUpdateHandler : MessageHandler
{
public bool WasExecuted { get; private set; }
public override Task<Result> Execute(IHandlerContainer<Message> container, CancellationToken cancellationToken)
@@ -19,5 +18,4 @@ namespace Telegrator.Tests
WasExecuted = true;
return Task.FromResult(Result.Ok());
}
}
}