Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3d2d21f6c0 | |||
| 0dedd3c0f4 | |||
| 79d5df8291 | |||
| 899243c62b |
@@ -148,6 +148,7 @@ public class ImplicitHandlerBuilderExtensionsGenerator : IIncrementalGenerator
|
|||||||
.AddMembers([.. targetters.Values, .. extensions]);
|
.AddMembers([.. targetters.Values, .. extensions]);
|
||||||
|
|
||||||
NamespaceDeclarationSyntax namespaceDeclaration = SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName("Telegrator"))
|
NamespaceDeclarationSyntax namespaceDeclaration = SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName("Telegrator"))
|
||||||
|
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia("#pragma warning disable CS1591"))
|
||||||
.WithMembers([extensionsClass]);
|
.WithMembers([extensionsClass]);
|
||||||
|
|
||||||
CompilationUnitSyntax compilationUnit = SyntaxFactory.CompilationUnit()
|
CompilationUnitSyntax compilationUnit = SyntaxFactory.CompilationUnit()
|
||||||
|
|||||||
@@ -28,6 +28,9 @@
|
|||||||
This application's logger
|
This application's logger
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHost.Properties">
|
||||||
|
<inheritdoc/>
|
||||||
|
</member>
|
||||||
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.#ctor(Microsoft.AspNetCore.Builder.WebApplicationBuilder)">
|
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.#ctor(Microsoft.AspNetCore.Builder.WebApplicationBuilder)">
|
||||||
<summary>
|
<summary>
|
||||||
Initializes a new instance of the <see cref="T:Microsoft.AspNetCore.Builder.WebApplicationBuilder"/> class.
|
Initializes a new instance of the <see cref="T:Microsoft.AspNetCore.Builder.WebApplicationBuilder"/> class.
|
||||||
@@ -181,7 +184,7 @@
|
|||||||
Service for receiving updates for Hosted telegram bots via Webhooks
|
Service for receiving updates for Hosted telegram bots via Webhooks
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:Telegrator.Mediation.HostedUpdateWebhooker.#ctor(Microsoft.AspNetCore.Routing.IEndpointRouteBuilder,Telegram.Bot.ITelegramBotClient,Telegrator.Core.IUpdateRouter,Microsoft.Extensions.Options.IOptions{Telegrator.Hosting.Web.WebhookerOptions})">
|
<member name="M:Telegrator.Mediation.HostedUpdateWebhooker.#ctor(Telegram.Bot.ITelegramBotClient,Telegrator.Core.IUpdateRouter,Microsoft.Extensions.Options.IOptions{Telegrator.Hosting.Web.WebhookerOptions})">
|
||||||
<summary>
|
<summary>
|
||||||
Initiallizes new instance of <see cref="T:Telegrator.Mediation.HostedUpdateWebhooker"/>
|
Initiallizes new instance of <see cref="T:Telegrator.Mediation.HostedUpdateWebhooker"/>
|
||||||
</summary>
|
</summary>
|
||||||
@@ -197,6 +200,12 @@
|
|||||||
<member name="M:Telegrator.Mediation.HostedUpdateWebhooker.StopAsync(System.Threading.CancellationToken)">
|
<member name="M:Telegrator.Mediation.HostedUpdateWebhooker.StopAsync(System.Threading.CancellationToken)">
|
||||||
<inheritdoc/>
|
<inheritdoc/>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:Telegrator.Mediation.HostedUpdateWebhooker.MapWebhook(Microsoft.AspNetCore.Routing.IEndpointRouteBuilder)">
|
||||||
|
<summary>
|
||||||
|
Maps bot webhook to application builder
|
||||||
|
</summary>
|
||||||
|
<param name="routeBuilder"></param>
|
||||||
|
</member>
|
||||||
<member name="T:Telegrator.ServicesCollectionExtensions">
|
<member name="T:Telegrator.ServicesCollectionExtensions">
|
||||||
<summary>
|
<summary>
|
||||||
Contains extensions for <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection"/>
|
Contains extensions for <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection"/>
|
||||||
@@ -211,12 +220,22 @@
|
|||||||
<member name="M:Telegrator.ServicesCollectionExtensions.get_Handlers(Microsoft.AspNetCore.Builder.WebApplicationBuilder)">
|
<member name="M:Telegrator.ServicesCollectionExtensions.get_Handlers(Microsoft.AspNetCore.Builder.WebApplicationBuilder)">
|
||||||
<inheritdoc cref="P:Telegrator.ServicesCollectionExtensions.<G>$41F16C2D39AF52899E745C9C9F42FF83.Handlers"/>
|
<inheritdoc cref="P:Telegrator.ServicesCollectionExtensions.<G>$41F16C2D39AF52899E745C9C9F42FF83.Handlers"/>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:Telegrator.ServicesCollectionExtensions.AddTelegratorWeb(Microsoft.Extensions.Hosting.IHostApplicationBuilder,Telegrator.TelegratorOptions,Telegrator.Core.IHandlersCollection)">
|
<member name="M:Telegrator.ServicesCollectionExtensions.AddTelegratorWeb(Telegrator.Hosting.ITelegramBotHostBuilder,Telegrator.TelegratorOptions,Telegrator.Core.IHandlersCollection,System.Action{Telegrator.Hosting.ITelegramBotHostBuilder})">
|
||||||
<summary>
|
<summary>
|
||||||
Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
|
Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:Telegrator.ServicesCollectionExtensions.UseTelegratorWeb(Microsoft.AspNetCore.Builder.WebApplication)">
|
<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.Hosting.IHostApplicationBuilder,Telegrator.TelegratorOptions,Telegrator.Core.IHandlersCollection)">
|
||||||
|
<summary>
|
||||||
|
Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Telegrator.ServicesCollectionExtensions.UseTelegratorWeb``1(``0)">
|
||||||
<summary>
|
<summary>
|
||||||
Replaces the initialization logic from TelegramBotWebHost constructor.
|
Replaces the initialization logic from TelegramBotWebHost constructor.
|
||||||
Initializes the bot and logs handlers on application startup.
|
Initializes the bot and logs handlers on application startup.
|
||||||
|
|||||||
@@ -221,7 +221,7 @@
|
|||||||
<member name="T:Telegrator.Providers.HostAwaitingProvider">
|
<member name="T:Telegrator.Providers.HostAwaitingProvider">
|
||||||
<inheritdoc/>
|
<inheritdoc/>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:Telegrator.Providers.HostAwaitingProvider.#ctor(Microsoft.Extensions.Options.IOptions{Telegrator.TelegratorOptions},Microsoft.Extensions.Logging.ILogger{Telegrator.Providers.HostAwaitingProvider})">
|
<member name="M:Telegrator.Providers.HostAwaitingProvider.#ctor(Microsoft.Extensions.Options.IOptions{Telegrator.TelegratorOptions})">
|
||||||
<inheritdoc/>
|
<inheritdoc/>
|
||||||
</member>
|
</member>
|
||||||
<member name="T:Telegrator.Providers.HostHandlersCollection">
|
<member name="T:Telegrator.Providers.HostHandlersCollection">
|
||||||
@@ -239,7 +239,7 @@
|
|||||||
<member name="T:Telegrator.Providers.HostHandlersProvider">
|
<member name="T:Telegrator.Providers.HostHandlersProvider">
|
||||||
<inheritdoc/>
|
<inheritdoc/>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:Telegrator.Providers.HostHandlersProvider.#ctor(Telegrator.Core.IHandlersCollection,Microsoft.Extensions.Options.IOptions{Telegrator.TelegratorOptions},System.IServiceProvider,Microsoft.Extensions.Logging.ILogger{Telegrator.Providers.HostHandlersProvider})">
|
<member name="M:Telegrator.Providers.HostHandlersProvider.#ctor(Telegrator.Core.IHandlersCollection,Microsoft.Extensions.Options.IOptions{Telegrator.TelegratorOptions},System.IServiceProvider)">
|
||||||
<inheritdoc/>
|
<inheritdoc/>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:Telegrator.Providers.HostHandlersProvider.GetHandlerInstance(Telegrator.Core.Descriptors.HandlerDescriptor,System.Threading.CancellationToken)">
|
<member name="M:Telegrator.Providers.HostHandlersProvider.GetHandlerInstance(Telegrator.Core.Descriptors.HandlerDescriptor,System.Threading.CancellationToken)">
|
||||||
@@ -255,15 +255,25 @@
|
|||||||
The key used to store the <see cref="T:Telegrator.Core.IHandlersCollection"/> in the builder properties.
|
The key used to store the <see cref="T:Telegrator.Core.IHandlersCollection"/> in the builder properties.
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:Telegrator.HostBuilderExtensions.get_Handlers(Microsoft.Extensions.Hosting.IHostApplicationBuilder)">
|
<member name="M:Telegrator.HostBuilderExtensions.get_Handlers(Microsoft.Extensions.Hosting.HostApplicationBuilder)">
|
||||||
<inheritdoc cref="P:Telegrator.HostBuilderExtensions.<G>$605D8CCF64349EA050C790D67C500BD9.Handlers"/>
|
<inheritdoc cref="P:Telegrator.HostBuilderExtensions.<G>$BF7227490CCA365283B3A9274C9033C7.Handlers"/>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:Telegrator.HostBuilderExtensions.AddTelegrator(Microsoft.Extensions.Hosting.IHostApplicationBuilder,Telegrator.TelegratorOptions,Telegrator.Core.IHandlersCollection)">
|
<member name="M:Telegrator.HostBuilderExtensions.AddTelegrator(Telegrator.Hosting.ITelegramBotHostBuilder,Telegrator.TelegratorOptions,Telegrator.Core.IHandlersCollection,System.Action{Telegrator.Hosting.ITelegramBotHostBuilder})">
|
||||||
<summary>
|
<summary>
|
||||||
Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
|
Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:Telegrator.HostBuilderExtensions.<G>$605D8CCF64349EA050C790D67C500BD9.Handlers">
|
<member name="M:Telegrator.HostBuilderExtensions.AddTelegrator(Microsoft.Extensions.Hosting.HostApplicationBuilder,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.AddTelegratorInternal(Microsoft.Extensions.Hosting.IHostApplicationBuilder,Telegrator.TelegratorOptions,Telegrator.Core.IHandlersCollection)">
|
||||||
|
<summary>
|
||||||
|
Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Telegrator.HostBuilderExtensions.<G>$BF7227490CCA365283B3A9274C9033C7.Handlers">
|
||||||
<summary>
|
<summary>
|
||||||
Gets the <see cref="T:Telegrator.Core.IHandlersCollection"/> from the builder properties.
|
Gets the <see cref="T:Telegrator.Core.IHandlersCollection"/> from the builder properties.
|
||||||
</summary>
|
</summary>
|
||||||
@@ -274,6 +284,14 @@
|
|||||||
Provides method to configure Telegram Bot Host
|
Provides method to configure Telegram Bot Host
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:Telegrator.ServicesCollectionExtensions.AddStateStorage``1(Microsoft.Extensions.DependencyInjection.IServiceCollection)">
|
||||||
|
<summary>
|
||||||
|
Registers <see cref="T:Telegrator.Core.States.IStateStorage"/> service
|
||||||
|
</summary>
|
||||||
|
<typeparam name="TStorage"></typeparam>
|
||||||
|
<param name="services"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
<member name="M:Telegrator.ServicesCollectionExtensions.AddTelegramBotHostDefaults(Microsoft.Extensions.DependencyInjection.IServiceCollection)">
|
<member name="M:Telegrator.ServicesCollectionExtensions.AddTelegramBotHostDefaults(Microsoft.Extensions.DependencyInjection.IServiceCollection)">
|
||||||
<summary>
|
<summary>
|
||||||
Registers <see cref="T:Telegrator.Hosting.TelegramBotHost"/> default services
|
Registers <see cref="T:Telegrator.Hosting.TelegramBotHost"/> default services
|
||||||
|
|||||||
@@ -7161,6 +7161,11 @@
|
|||||||
Provides extension methods for working with Telegram Update objects.
|
Provides extension methods for working with Telegram Update objects.
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:Telegrator.UpdateExtensions.GetUserLanguageCode(Telegram.Bot.Types.Update)">
|
||||||
|
<summary>
|
||||||
|
Extracts the IETF language tag of the user's client from the update.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
<member name="M:Telegrator.UpdateExtensions.GetSenderId(Telegram.Bot.Types.Update)">
|
<member name="M:Telegrator.UpdateExtensions.GetSenderId(Telegram.Bot.Types.Update)">
|
||||||
<summary>
|
<summary>
|
||||||
Selects from Update an object from which you can get the sender's ID
|
Selects from Update an object from which you can get the sender's ID
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||||
|
|
||||||
<Title>Telegrator.RedisStateStorage</Title>
|
<Title>Telegrator.RedisStateStorage</Title>
|
||||||
<Version>1.16.4</Version>
|
<Version>1.16.6</Version>
|
||||||
<Authors>Rikitav Tim4ik</Authors>
|
<Authors>Rikitav Tim4ik</Authors>
|
||||||
<Company>Rikitav Tim4ik</Company>
|
<Company>Rikitav Tim4ik</Company>
|
||||||
<RepositoryUrl>https://github.com/Rikitav/Telegrator</RepositoryUrl>
|
<RepositoryUrl>https://github.com/Rikitav/Telegrator</RepositoryUrl>
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="StackExchange.Redis" Version="2.11.8 " />
|
<PackageReference Include="StackExchange.Redis" Version="2.11.8" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
[assembly: SuppressMessage("Style", "IDE0090")]
|
[assembly: SuppressMessage("Style", "IDE0090")]
|
||||||
[assembly: SuppressMessage("Usage", "CA2254")]
|
[assembly: SuppressMessage("Usage", "CA2254")]
|
||||||
[assembly: SuppressMessage("Maintainability", "CA1510")]
|
[assembly: SuppressMessage("Maintainability", "CA1510")]
|
||||||
|
[assembly: SuppressMessage("Style", "IDE0270")]
|
||||||
|
|||||||
@@ -7,154 +7,153 @@ using Microsoft.Extensions.Hosting;
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Telegrator.Core;
|
using Telegrator.Core;
|
||||||
|
|
||||||
namespace Telegrator.Hosting.Web
|
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>
|
/// <summary>
|
||||||
/// Represents a web hosted telegram bot
|
/// Allows consumers to be notified of application lifetime events.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TelegramBotWebHost : IHost, IApplicationBuilder, IEndpointRouteBuilder, IAsyncDisposable
|
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)
|
||||||
{
|
{
|
||||||
private readonly WebApplication _innerApp;
|
// Building proxy application
|
||||||
private readonly IUpdateRouter _updateRouter;
|
_innerApp = webApplicationBuilder.Build();
|
||||||
private readonly ILogger<TelegramBotWebHost> _logger;
|
|
||||||
|
|
||||||
private bool _disposed;
|
// Reruesting services for this host
|
||||||
|
_updateRouter = Services.GetRequiredService<IUpdateRouter>();
|
||||||
|
_logger = Services.GetRequiredService<ILogger<TelegramBotWebHost>>();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>
|
||||||
public IServiceProvider Services => _innerApp.Services;
|
/// 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, settings);
|
||||||
|
builder.AddTelegratorWeb();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>
|
||||||
public IUpdateRouter UpdateRouter => _updateRouter;
|
/// 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, settings);
|
||||||
|
builder.AddTelegratorWeb();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>
|
||||||
public ICollection<EndpointDataSource> DataSources => ((IEndpointRouteBuilder)_innerApp).DataSources;
|
/// 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, settings);
|
||||||
|
builder.AddTelegratorWeb();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc/>
|
||||||
/// Allows consumers to be notified of application lifetime events.
|
public async Task StartAsync(CancellationToken cancellationToken = default)
|
||||||
/// </summary>
|
{
|
||||||
public IHostApplicationLifetime Lifetime => _innerApp.Lifetime;
|
await _innerApp.StartAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc/>
|
||||||
/// This application's logger
|
public async Task StopAsync(CancellationToken cancellationToken = default)
|
||||||
/// </summary>
|
{
|
||||||
public ILogger<TelegramBotWebHost> Logger => _logger;
|
await _innerApp.StopAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
// Private interface fields
|
/// <inheritdoc/>
|
||||||
IServiceProvider IEndpointRouteBuilder.ServiceProvider => Services;
|
public IApplicationBuilder CreateApplicationBuilder()
|
||||||
IServiceProvider IApplicationBuilder.ApplicationServices { get => Services; set => throw new NotImplementedException(); }
|
=> ((IEndpointRouteBuilder)_innerApp).CreateApplicationBuilder();
|
||||||
IFeatureCollection IApplicationBuilder.ServerFeatures => ((IApplicationBuilder)_innerApp).ServerFeatures;
|
|
||||||
IDictionary<string, object?> IApplicationBuilder.Properties => ((IApplicationBuilder)_innerApp).Properties;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc/>
|
||||||
/// Initializes a new instance of the <see cref="WebApplicationBuilder"/> class.
|
public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
|
||||||
/// </summary>
|
=> _innerApp.Use(middleware);
|
||||||
/// <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
|
/// <inheritdoc/>
|
||||||
_updateRouter = Services.GetRequiredService<IUpdateRouter>();
|
public IApplicationBuilder New()
|
||||||
_logger = Services.GetRequiredService<ILogger<TelegramBotWebHost>>();
|
=> ((IApplicationBuilder)_innerApp).New();
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc/>
|
||||||
/// Creates new <see cref="TelegramBotHostBuilder"/> with default services and webhook update receiving scheme
|
public RequestDelegate Build()
|
||||||
/// </summary>
|
=> ((IApplicationBuilder)_innerApp).Build();
|
||||||
/// <returns></returns>
|
|
||||||
public static TelegramBotWebHostBuilder CreateBuilder(WebApplicationOptions settings)
|
|
||||||
{
|
|
||||||
ArgumentNullException.ThrowIfNull(settings, nameof(settings));
|
|
||||||
WebApplicationBuilder innerApp = WebApplication.CreateBuilder(settings);
|
|
||||||
TelegramBotWebHostBuilder builder = new TelegramBotWebHostBuilder(innerApp, settings);
|
|
||||||
|
|
||||||
builder.Services.AddTelegramBotHostDefaults();
|
/// <summary>
|
||||||
builder.Services.AddTelegramWebhook();
|
/// Disposes the host.
|
||||||
return builder;
|
/// </summary>
|
||||||
}
|
public async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
return;
|
||||||
|
|
||||||
/// <summary>
|
await _innerApp.DisposeAsync();
|
||||||
/// 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, settings);
|
|
||||||
|
|
||||||
builder.Services.AddTelegramBotHostDefaults();
|
GC.SuppressFinalize(this);
|
||||||
builder.Services.AddTelegramWebhook();
|
_disposed = true;
|
||||||
return builder;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates new EMPTY <see cref="TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes
|
/// Disposes the host.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
public void Dispose()
|
||||||
public static TelegramBotWebHostBuilder CreateEmptyBuilder(WebApplicationOptions settings)
|
{
|
||||||
{
|
if (_disposed)
|
||||||
ArgumentNullException.ThrowIfNull(settings, nameof(settings));
|
return;
|
||||||
WebApplicationBuilder innerApp = WebApplication.CreateEmptyBuilder(settings);
|
|
||||||
return new TelegramBotWebHostBuilder(innerApp, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
ValueTask disposeTask = _innerApp.DisposeAsync();
|
||||||
public async Task StartAsync(CancellationToken cancellationToken = default)
|
disposeTask.AsTask().Wait();
|
||||||
{
|
|
||||||
await _innerApp.StartAsync(cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
GC.SuppressFinalize(this);
|
||||||
public async Task StopAsync(CancellationToken cancellationToken = default)
|
_disposed = true;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,109 +7,100 @@ using Microsoft.Extensions.Logging;
|
|||||||
using Telegrator.Core;
|
using Telegrator.Core;
|
||||||
|
|
||||||
#pragma warning disable IDE0001
|
#pragma warning disable IDE0001
|
||||||
namespace Telegrator.Hosting.Web
|
namespace Telegrator.Hosting.Web;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a web hosted telegram bots and services builder that helps manage configuration, logging, lifetime, and more.
|
||||||
|
/// </summary>
|
||||||
|
public class TelegramBotWebHostBuilder : ITelegramBotHostBuilder
|
||||||
{
|
{
|
||||||
|
private readonly WebApplicationBuilder _innerBuilder;
|
||||||
|
private readonly WebApplicationOptions _settings;
|
||||||
|
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>
|
/// <summary>
|
||||||
/// Represents a web hosted telegram bots and services builder that helps manage configuration, logging, lifetime, and more.
|
/// Initializes a new instance of the <see cref="TelegramBotWebHostBuilder"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TelegramBotWebHostBuilder : IHostApplicationBuilder, ICollectingProvider
|
/// <param name="webApplicationBuilder"></param>
|
||||||
|
/// <param name="settings"></param>
|
||||||
|
public TelegramBotWebHostBuilder(WebApplicationBuilder webApplicationBuilder, WebApplicationOptions? settings = null)
|
||||||
{
|
{
|
||||||
private readonly WebApplicationBuilder _innerBuilder;
|
_innerBuilder = webApplicationBuilder ?? throw new ArgumentNullException(nameof(webApplicationBuilder));
|
||||||
private readonly WebApplicationOptions _settings;
|
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
|
||||||
internal IHandlersCollection _handlers = null!;
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>
|
||||||
public IHandlersCollection Handlers => _handlers;
|
/// Initializes a new instance of the <see cref="TelegramBotWebHostBuilder"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="webApplicationBuilder"></param>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <param name="settings"></param>
|
||||||
|
public TelegramBotWebHostBuilder(WebApplicationBuilder webApplicationBuilder, TelegratorOptions? options, WebApplicationOptions? settings)
|
||||||
|
{
|
||||||
|
_innerBuilder = webApplicationBuilder ?? throw new ArgumentNullException(nameof(webApplicationBuilder));
|
||||||
|
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>
|
||||||
public IConfigurationManager Configuration => _innerBuilder.Configuration;
|
/// Initializes a new instance of the <see cref="TelegramBotWebHostBuilder"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="webApplicationBuilder"></param>
|
||||||
|
/// <param name="handlers"></param>
|
||||||
|
/// <param name="settings"></param>
|
||||||
|
public TelegramBotWebHostBuilder(WebApplicationBuilder webApplicationBuilder, IHandlersCollection handlers, WebApplicationOptions settings)
|
||||||
|
{
|
||||||
|
_innerBuilder = webApplicationBuilder ?? throw new ArgumentNullException(nameof(webApplicationBuilder));
|
||||||
|
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>
|
||||||
public ILoggingBuilder Logging => _innerBuilder.Logging;
|
/// Initializes a new instance of the <see cref="TelegramBotWebHostBuilder"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="webApplicationBuilder"></param>
|
||||||
|
/// <param name="handlers"></param>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <param name="settings"></param>
|
||||||
|
public TelegramBotWebHostBuilder(WebApplicationBuilder webApplicationBuilder, IHandlersCollection handlers, TelegratorOptions? options, WebApplicationOptions settings)
|
||||||
|
{
|
||||||
|
_innerBuilder = webApplicationBuilder ?? throw new ArgumentNullException(nameof(webApplicationBuilder));
|
||||||
|
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>
|
||||||
public IServiceCollection Services => _innerBuilder.Services;
|
/// Builds the host.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public TelegramBotWebHost Build()
|
||||||
|
{
|
||||||
|
TelegramBotWebHost host = new TelegramBotWebHost(_innerBuilder);
|
||||||
|
host.UseTelegrator();
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IHostEnvironment Environment => _innerBuilder.Environment;
|
public void ConfigureContainer<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory, Action<TContainerBuilder>? configure = null) where TContainerBuilder : notnull
|
||||||
|
{
|
||||||
/// <inheritdoc/>
|
((IHostApplicationBuilder)_innerBuilder).ConfigureContainer(factory, configure);
|
||||||
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>
|
|
||||||
/// <param name="settings"></param>
|
|
||||||
public TelegramBotWebHostBuilder(WebApplicationBuilder webApplicationBuilder, WebApplicationOptions? settings = null)
|
|
||||||
{
|
|
||||||
_innerBuilder = webApplicationBuilder ?? throw new ArgumentNullException(nameof(webApplicationBuilder));
|
|
||||||
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
|
|
||||||
|
|
||||||
this.AddTelegratorWeb();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="TelegramBotWebHostBuilder"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="webApplicationBuilder"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <param name="settings"></param>
|
|
||||||
public TelegramBotWebHostBuilder(WebApplicationBuilder webApplicationBuilder, TelegratorOptions? options, WebApplicationOptions? settings)
|
|
||||||
{
|
|
||||||
_innerBuilder = webApplicationBuilder ?? throw new ArgumentNullException(nameof(webApplicationBuilder));
|
|
||||||
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
|
|
||||||
|
|
||||||
this.AddTelegratorWeb(options, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="TelegramBotWebHostBuilder"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="webApplicationBuilder"></param>
|
|
||||||
/// <param name="handlers"></param>
|
|
||||||
/// <param name="settings"></param>
|
|
||||||
public TelegramBotWebHostBuilder(WebApplicationBuilder webApplicationBuilder, IHandlersCollection handlers, WebApplicationOptions settings)
|
|
||||||
{
|
|
||||||
_innerBuilder = webApplicationBuilder ?? throw new ArgumentNullException(nameof(webApplicationBuilder));
|
|
||||||
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
|
|
||||||
|
|
||||||
this.AddTelegratorWeb(null, handlers);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="TelegramBotWebHostBuilder"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="webApplicationBuilder"></param>
|
|
||||||
/// <param name="handlers"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <param name="settings"></param>
|
|
||||||
public TelegramBotWebHostBuilder(WebApplicationBuilder webApplicationBuilder, IHandlersCollection handlers, TelegratorOptions? options, WebApplicationOptions settings)
|
|
||||||
{
|
|
||||||
_innerBuilder = webApplicationBuilder ?? throw new ArgumentNullException(nameof(webApplicationBuilder));
|
|
||||||
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
|
|
||||||
|
|
||||||
this.AddTelegratorWeb(options, handlers);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Builds the host.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public TelegramBotWebHost Build()
|
|
||||||
{
|
|
||||||
TelegramBotWebHost host = new TelegramBotWebHost(_innerBuilder);
|
|
||||||
host.UseTelegrator();
|
|
||||||
return host;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void ConfigureContainer<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory, Action<TContainerBuilder>? configure = null) where TContainerBuilder : notnull
|
|
||||||
{
|
|
||||||
((IHostApplicationBuilder)_innerBuilder).ConfigureContainer(factory, configure);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,34 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace Telegrator.Hosting.Web
|
namespace Telegrator.Hosting.Web;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configuration options for Telegram bot behavior and execution settings.
|
||||||
|
/// Controls various aspects of bot operation including concurrency, routing, webhook receiving, and execution policies.
|
||||||
|
/// </summary>
|
||||||
|
public class WebhookerOptions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configuration options for Telegram bot behavior and execution settings.
|
/// Gets or sets HTTPS URL to send updates to. Use an empty string to remove webhook integration
|
||||||
/// Controls various aspects of bot operation including concurrency, routing, webhook receiving, and execution policies.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WebhookerOptions
|
[StringSyntax(StringSyntaxAttribute.Uri)]
|
||||||
{
|
public string WebhookUri { get; set; } = string.Empty;
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets HTTPS URL to send updates to. Use an empty string to remove webhook integration
|
|
||||||
/// </summary>
|
|
||||||
[StringSyntax(StringSyntaxAttribute.Uri)]
|
|
||||||
public string WebhookUri { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A secret token to be sent in a header “X-Telegram-Bot-Api-Secret-Token” in every webhook request, 1-256 characters.
|
/// A secret token to be sent in a header “X-Telegram-Bot-Api-Secret-Token” in every webhook request, 1-256 characters.
|
||||||
/// Only characters A-Z, a-z, 0-9, _ and - are allowed.
|
/// Only characters A-Z, a-z, 0-9, _ and - are allowed.
|
||||||
/// The header is useful to ensure that the request comes from a webhook set by you.
|
/// The header is useful to ensure that the request comes from a webhook set by you.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? SecretToken { get; set; } = null;
|
public string? SecretToken { get; set; } = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum allowed number of simultaneous HTTPS connections to the webhook for update delivery, 1-100. Defaults to 40.
|
/// The maximum allowed number of simultaneous HTTPS connections to the webhook for update delivery, 1-100. Defaults to 40.
|
||||||
/// Use lower values to limit the load on your bot's server, and higher values to increase your bot's throughput.
|
/// Use lower values to limit the load on your bot's server, and higher values to increase your bot's throughput.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int MaxConnections { get; set; } = 40;
|
public int MaxConnections { get; set; } = 40;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pass true to drop all pending updates
|
/// Pass true to drop all pending updates
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool DropPendingUpdates { get; set; } = false;
|
public bool DropPendingUpdates { get; set; } = false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,88 +10,92 @@ using Telegram.Bot.Types;
|
|||||||
using Telegrator.Core;
|
using Telegrator.Core;
|
||||||
using Telegrator.Hosting.Web;
|
using Telegrator.Hosting.Web;
|
||||||
|
|
||||||
namespace Telegrator.Mediation
|
namespace Telegrator.Mediation;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Service for receiving updates for Hosted telegram bots via Webhooks
|
||||||
|
/// </summary>
|
||||||
|
public class HostedUpdateWebhooker : IHostedService
|
||||||
{
|
{
|
||||||
|
private const string SecretTokenHeader = "X-Telegram-Bot-Api-Secret-Token";
|
||||||
|
|
||||||
|
private readonly ITelegramBotClient _botClient;
|
||||||
|
private readonly IUpdateRouter _updateRouter;
|
||||||
|
private readonly WebhookerOptions _options;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Service for receiving updates for Hosted telegram bots via Webhooks
|
/// Initiallizes new instance of <see cref="HostedUpdateWebhooker"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class HostedUpdateWebhooker : IHostedService
|
/// <param name="botHost"></param>
|
||||||
|
/// <param name="botClient"></param>
|
||||||
|
/// <param name="updateRouter"></param>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <exception cref="ArgumentNullException"></exception>
|
||||||
|
public HostedUpdateWebhooker(ITelegramBotClient botClient, IUpdateRouter updateRouter, IOptions<WebhookerOptions> options)
|
||||||
{
|
{
|
||||||
private const string SecretTokenHeader = "X-Telegram-Bot-Api-Secret-Token";
|
if (string.IsNullOrEmpty(options.Value.WebhookUri))
|
||||||
|
throw new ArgumentNullException(nameof(options), "Option \"WebhookUrl\" must be set to subscribe for update recieving");
|
||||||
|
|
||||||
private readonly IEndpointRouteBuilder _botHost;
|
_botClient = botClient;
|
||||||
private readonly ITelegramBotClient _botClient;
|
_updateRouter = updateRouter;
|
||||||
private readonly IUpdateRouter _updateRouter;
|
_options = options.Value;
|
||||||
private readonly WebhookerOptions _options;
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc/>
|
||||||
/// Initiallizes new instance of <see cref="HostedUpdateWebhooker"/>
|
public Task StartAsync(CancellationToken cancellationToken)
|
||||||
/// </summary>
|
{
|
||||||
/// <param name="botHost"></param>
|
StartInternal(cancellationToken);
|
||||||
/// <param name="botClient"></param>
|
return Task.CompletedTask;
|
||||||
/// <param name="updateRouter"></param>
|
}
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <exception cref="ArgumentNullException"></exception>
|
private async void StartInternal(CancellationToken cancellationToken)
|
||||||
public HostedUpdateWebhooker(IEndpointRouteBuilder botHost, ITelegramBotClient botClient, IUpdateRouter updateRouter, IOptions<WebhookerOptions> options)
|
{
|
||||||
|
await _botClient.SetWebhook(
|
||||||
|
url: _options.WebhookUri,
|
||||||
|
maxConnections: _options.MaxConnections,
|
||||||
|
allowedUpdates: _updateRouter.HandlersProvider.AllowedTypes,
|
||||||
|
dropPendingUpdates: _options.DropPendingUpdates,
|
||||||
|
secretToken: _options.SecretToken,
|
||||||
|
cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public Task StopAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_botClient.DeleteWebhook(_options.DropPendingUpdates, cancellationToken);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maps bot webhook to application builder
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="routeBuilder"></param>
|
||||||
|
public void MapWebhook(IEndpointRouteBuilder routeBuilder)
|
||||||
|
{
|
||||||
|
string pattern = new UriBuilder(_options.WebhookUri).Path;
|
||||||
|
routeBuilder.MapPost(pattern, (Delegate)ReceiveUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IResult> ReceiveUpdate(HttpContext ctx)
|
||||||
|
{
|
||||||
|
if (_options.SecretToken != null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(options.Value.WebhookUri))
|
if (!ctx.Request.Headers.TryGetValue(SecretTokenHeader, out StringValues strings))
|
||||||
throw new ArgumentNullException(nameof(options), "Option \"WebhookUrl\" must be set to subscribe for update recieving");
|
|
||||||
|
|
||||||
_botHost = botHost;
|
|
||||||
_botClient = botClient;
|
|
||||||
_updateRouter = updateRouter;
|
|
||||||
_options = options.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
StartInternal(cancellationToken);
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void StartInternal(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
string pattern = new UriBuilder(_options.WebhookUri).Path;
|
|
||||||
_botHost.MapPost(pattern, (Delegate)ReceiveUpdate);
|
|
||||||
|
|
||||||
await _botClient.SetWebhook(
|
|
||||||
url: _options.WebhookUri,
|
|
||||||
maxConnections: _options.MaxConnections,
|
|
||||||
allowedUpdates: _updateRouter.HandlersProvider.AllowedTypes,
|
|
||||||
dropPendingUpdates: _options.DropPendingUpdates,
|
|
||||||
secretToken: _options.SecretToken,
|
|
||||||
cancellationToken: cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
_botClient.DeleteWebhook(_options.DropPendingUpdates, cancellationToken);
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<IResult> ReceiveUpdate(HttpContext ctx)
|
|
||||||
{
|
|
||||||
if (_options.SecretToken != null)
|
|
||||||
{
|
|
||||||
if (!ctx.Request.Headers.TryGetValue(SecretTokenHeader, out StringValues strings))
|
|
||||||
return Results.BadRequest();
|
|
||||||
|
|
||||||
string? secret = strings.SingleOrDefault();
|
|
||||||
if (secret == null)
|
|
||||||
return Results.BadRequest();
|
|
||||||
|
|
||||||
if (_options.SecretToken != secret)
|
|
||||||
return Results.StatusCode(401);
|
|
||||||
}
|
|
||||||
|
|
||||||
Update? update = await JsonSerializer.DeserializeAsync<Update>(ctx.Request.Body, JsonBotAPI.Options, ctx.RequestAborted);
|
|
||||||
if (update is not { Id: > 0 })
|
|
||||||
return Results.BadRequest();
|
return Results.BadRequest();
|
||||||
|
|
||||||
await _updateRouter.HandleUpdateAsync(_botClient, update, ctx.RequestAborted);
|
string? secret = strings.SingleOrDefault();
|
||||||
return Results.Ok();
|
if (secret == null)
|
||||||
|
return Results.BadRequest();
|
||||||
|
|
||||||
|
if (_options.SecretToken != secret)
|
||||||
|
return Results.StatusCode(401);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Update? update = await JsonSerializer.DeserializeAsync<Update>(ctx.Request.Body, JsonBotAPI.Options, ctx.RequestAborted);
|
||||||
|
if (update is not { Id: > 0 })
|
||||||
|
return Results.BadRequest();
|
||||||
|
|
||||||
|
await _updateRouter.HandleUpdateAsync(_botClient, update, ctx.RequestAborted);
|
||||||
|
return Results.Ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||||
|
|
||||||
<Title>Telegrator.Hosting.Web</Title>
|
<Title>Telegrator.Hosting.Web</Title>
|
||||||
<Version>1.16.4</Version>
|
<Version>1.16.6</Version>
|
||||||
<Authors>Rikitav Tim4ik</Authors>
|
<Authors>Rikitav Tim4ik</Authors>
|
||||||
<Company>Rikitav Tim4ik</Company>
|
<Company>Rikitav Tim4ik</Company>
|
||||||
<RepositoryUrl>https://github.com/Rikitav/Telegrator</RepositoryUrl>
|
<RepositoryUrl>https://github.com/Rikitav/Telegrator</RepositoryUrl>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
@@ -42,7 +43,27 @@ namespace Telegrator
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
|
/// Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IHostApplicationBuilder AddTelegratorWeb(this IHostApplicationBuilder builder, TelegratorOptions? options = null, IHandlersCollection? handlers = null)
|
public static ITelegramBotHostBuilder AddTelegratorWeb(this ITelegramBotHostBuilder builder, TelegratorOptions? options = null, IHandlersCollection? handlers = null, Action<ITelegramBotHostBuilder>? action = null)
|
||||||
|
{
|
||||||
|
builder.AddTelegratorWebInternal(options, 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)
|
||||||
|
{
|
||||||
|
builder.AddTelegratorWebInternal(options, handlers);
|
||||||
|
action?.Invoke(new TelegramBotWebHostBuilder(builder));
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
|
||||||
|
/// </summary>
|
||||||
|
internal static IHostApplicationBuilder AddTelegratorWebInternal(this IHostApplicationBuilder builder, TelegratorOptions? options = null, IHandlersCollection? handlers = null)
|
||||||
{
|
{
|
||||||
IServiceCollection services = builder.Services;
|
IServiceCollection services = builder.Services;
|
||||||
IConfigurationManager configuration = builder.Configuration;
|
IConfigurationManager configuration = builder.Configuration;
|
||||||
@@ -103,11 +124,12 @@ namespace Telegrator
|
|||||||
/// Replaces the initialization logic from TelegramBotWebHost constructor.
|
/// Replaces the initialization logic from TelegramBotWebHost constructor.
|
||||||
/// Initializes the bot and logs handlers on application startup.
|
/// Initializes the bot and logs handlers on application startup.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static WebApplication UseTelegratorWeb(this WebApplication app)
|
public static T UseTelegratorWeb<T>(this T app) where T : IEndpointRouteBuilder, IHost
|
||||||
{
|
{
|
||||||
ITelegramBotInfo info = app.Services.GetRequiredService<ITelegramBotInfo>();
|
HostedUpdateWebhooker webhooker = app.ServiceProvider.GetRequiredService<HostedUpdateWebhooker>();
|
||||||
IHandlersCollection handlers = app.Services.GetRequiredService<IHandlersCollection>();
|
ITelegramBotInfo info = app.ServiceProvider.GetRequiredService<ITelegramBotInfo>();
|
||||||
ILoggerFactory loggerFactory = app.Services.GetRequiredService<ILoggerFactory>();
|
IHandlersCollection handlers = app.ServiceProvider.GetRequiredService<IHandlersCollection>();
|
||||||
|
ILoggerFactory loggerFactory = app.ServiceProvider.GetRequiredService<ILoggerFactory>();
|
||||||
ILogger logger = loggerFactory.CreateLogger("Telegrator.Hosting.Web.TelegratorHost");
|
ILogger logger = loggerFactory.CreateLogger("Telegrator.Hosting.Web.TelegratorHost");
|
||||||
|
|
||||||
if (logger.IsEnabled(LogLevel.Information))
|
if (logger.IsEnabled(LogLevel.Information))
|
||||||
@@ -117,6 +139,7 @@ namespace Telegrator
|
|||||||
logger.LogHandlers(handlers);
|
logger.LogHandlers(handlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
webhooker.MapWebhook(app);
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
[assembly: SuppressMessage("Style", "IDE0090")]
|
[assembly: SuppressMessage("Style", "IDE0090")]
|
||||||
[assembly: SuppressMessage("Usage", "CA2254")]
|
[assembly: SuppressMessage("Usage", "CA2254")]
|
||||||
[assembly: SuppressMessage("Maintainability", "CA1510")]
|
[assembly: SuppressMessage("Maintainability", "CA1510")]
|
||||||
|
[assembly: SuppressMessage("Style", "IDE0270")]
|
||||||
|
|||||||
@@ -3,28 +3,27 @@ using Telegram.Bot;
|
|||||||
using Telegram.Bot.Types;
|
using Telegram.Bot.Types;
|
||||||
using Telegrator.Core;
|
using Telegrator.Core;
|
||||||
|
|
||||||
namespace Telegrator.Hosting
|
namespace Telegrator.Hosting;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implementation of <see cref="ITelegramBotInfo"/> that provides bot information.
|
||||||
|
/// Contains metadata about the Telegram bot including user details and service provider for wider filterring abilities
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client"></param>
|
||||||
|
/// <param name="services"></param>
|
||||||
|
/// <param name="configuration"></param>
|
||||||
|
public class HostedTelegramBotInfo(ITelegramBotClient client, IServiceProvider services, IConfiguration configuration) : ITelegramBotInfo
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public User User { get; } = client.GetMe().Result;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implementation of <see cref="ITelegramBotInfo"/> that provides bot information.
|
/// Provides access to services of this Hosted telegram bot
|
||||||
/// Contains metadata about the Telegram bot including user details and service provider for wider filterring abilities
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="client"></param>
|
public IServiceProvider Services { get; } = services;
|
||||||
/// <param name="services"></param>
|
|
||||||
/// <param name="configuration"></param>
|
|
||||||
public class HostedTelegramBotInfo(ITelegramBotClient client, IServiceProvider services, IConfiguration configuration) : ITelegramBotInfo
|
|
||||||
{
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public User User { get; } = client.GetMe().Result;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides access to services of this Hosted telegram bot
|
/// Provides access to configuration of this Hosted telegram bot
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IServiceProvider Services { get; } = services;
|
public IConfiguration Configuration { get; } = configuration;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides access to configuration of this Hosted telegram bot
|
|
||||||
/// </summary>
|
|
||||||
public IConfiguration Configuration { get; } = configuration;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using Telegrator.Core;
|
||||||
|
|
||||||
|
namespace Telegrator.Hosting;
|
||||||
|
|
||||||
|
public interface ITelegramBotHostBuilder : IHostApplicationBuilder, ICollectingProvider
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,113 +3,112 @@ using Microsoft.Extensions.Hosting;
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Telegrator.Core;
|
using Telegrator.Core;
|
||||||
|
|
||||||
namespace Telegrator.Hosting
|
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>
|
/// <summary>
|
||||||
/// Represents a hosted telegram bot
|
/// This application's logger
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TelegramBotHost : IHost, ITelegratorBot
|
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)
|
||||||
{
|
{
|
||||||
private readonly IHost _innerHost;
|
// Registering this host in services for easy access
|
||||||
private readonly IUpdateRouter _updateRouter;
|
hostApplicationBuilder.Services.AddSingleton<ITelegratorBot>(this);
|
||||||
private readonly ILogger<TelegramBotHost> _logger;
|
|
||||||
|
|
||||||
private bool _disposed;
|
// Building proxy hoster
|
||||||
|
_innerHost = hostApplicationBuilder.Build();
|
||||||
|
|
||||||
/// <inheritdoc/>
|
// Reruesting services for this host
|
||||||
public IServiceProvider Services => _innerHost.Services;
|
_updateRouter = Services.GetRequiredService<IUpdateRouter>();
|
||||||
|
_logger = Services.GetRequiredService<ILogger<TelegramBotHost>>();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>
|
||||||
public IUpdateRouter UpdateRouter => _updateRouter;
|
/// 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, null);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This application's logger
|
/// Creates new <see cref="TelegramBotHostBuilder"/> with default services and long-polling update receiving scheme
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ILogger<TelegramBotHost> Logger => _logger;
|
/// <returns></returns>
|
||||||
|
public static TelegramBotHostBuilder CreateBuilder(HostApplicationBuilderSettings? settings)
|
||||||
|
{
|
||||||
|
HostApplicationBuilder innerBuilder = new HostApplicationBuilder(settings);
|
||||||
|
TelegramBotHostBuilder builder = new TelegramBotHostBuilder(innerBuilder, settings);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="TelegramBotHost"/> class.
|
/// Creates new EMPTY <see cref="TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="hostApplicationBuilder">The proxied instance of host builder.</param>
|
/// <returns></returns>
|
||||||
public TelegramBotHost(HostApplicationBuilder hostApplicationBuilder)
|
public static TelegramBotHostBuilder CreateEmptyBuilder()
|
||||||
{
|
{
|
||||||
// Registering this host in services for easy access
|
HostApplicationBuilder innerBuilder = Host.CreateEmptyApplicationBuilder(null);
|
||||||
hostApplicationBuilder.Services.AddSingleton<ITelegratorBot>(this);
|
return new TelegramBotHostBuilder(innerBuilder, null);
|
||||||
|
}
|
||||||
|
|
||||||
// Building proxy hoster
|
/// <summary>
|
||||||
_innerHost = hostApplicationBuilder.Build();
|
/// 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(null);
|
||||||
|
return new TelegramBotHostBuilder(innerBuilder, settings);
|
||||||
|
}
|
||||||
|
|
||||||
// Reruesting services for this host
|
/// <inheritdoc/>
|
||||||
_updateRouter = Services.GetRequiredService<IUpdateRouter>();
|
public async Task StartAsync(CancellationToken cancellationToken = default)
|
||||||
_logger = Services.GetRequiredService<ILogger<TelegramBotHost>>();
|
{
|
||||||
}
|
await _innerHost.StartAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc/>
|
||||||
/// Creates new <see cref="TelegramBotHostBuilder"/> with default configuration, services and long-polling update receiving scheme
|
public async Task StopAsync(CancellationToken cancellationToken = default)
|
||||||
/// </summary>
|
{
|
||||||
/// <returns></returns>
|
await _innerHost.StopAsync(cancellationToken);
|
||||||
public static TelegramBotHostBuilder CreateBuilder()
|
}
|
||||||
{
|
|
||||||
HostApplicationBuilder innerBuilder = new HostApplicationBuilder(settings: null);
|
|
||||||
TelegramBotHostBuilder builder = new TelegramBotHostBuilder(innerBuilder, null);
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates new <see cref="TelegramBotHostBuilder"/> with default services and long-polling update receiving scheme
|
/// Disposes the host.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
public void Dispose()
|
||||||
public static TelegramBotHostBuilder CreateBuilder(HostApplicationBuilderSettings? settings)
|
{
|
||||||
{
|
if (_disposed)
|
||||||
HostApplicationBuilder innerBuilder = new HostApplicationBuilder(settings);
|
return;
|
||||||
TelegramBotHostBuilder builder = new TelegramBotHostBuilder(innerBuilder, settings);
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
_innerHost.Dispose();
|
||||||
/// 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, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
GC.SuppressFinalize(this);
|
||||||
/// Creates new EMPTY <see cref="TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes
|
_disposed = true;
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static TelegramBotHostBuilder CreateEmptyBuilder(HostApplicationBuilderSettings? settings)
|
|
||||||
{
|
|
||||||
HostApplicationBuilder innerBuilder = Host.CreateEmptyApplicationBuilder(null);
|
|
||||||
return new TelegramBotHostBuilder(innerBuilder, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,114 +3,103 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
using Microsoft.Extensions.Diagnostics.Metrics;
|
using Microsoft.Extensions.Diagnostics.Metrics;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using Telegrator.Core;
|
using Telegrator.Core;
|
||||||
using Telegrator.Providers;
|
|
||||||
|
|
||||||
#pragma warning disable IDE0001
|
#pragma warning disable IDE0001
|
||||||
namespace Telegrator.Hosting
|
namespace Telegrator.Hosting;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a hosted telegram bots and services builder that helps manage configuration, logging, lifetime, and more.
|
||||||
|
/// </summary>
|
||||||
|
public class TelegramBotHostBuilder : ITelegramBotHostBuilder
|
||||||
{
|
{
|
||||||
|
private readonly HostApplicationBuilder _innerBuilder;
|
||||||
|
private readonly HostApplicationBuilderSettings _settings;
|
||||||
|
internal IHandlersCollection _handlers = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IHandlersCollection Handlers => _handlers;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IServiceCollection Services => _innerBuilder.Services;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IConfigurationManager Configuration => _innerBuilder.Configuration;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ILoggingBuilder Logging => _innerBuilder.Logging;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IHostEnvironment Environment => _innerBuilder.Environment;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IDictionary<object, object> Properties => ((IHostApplicationBuilder)_innerBuilder).Properties;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IMetricsBuilder Metrics => _innerBuilder.Metrics;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a hosted telegram bots and services builder that helps manage configuration, logging, lifetime, and more.
|
/// Initializes a new instance of the <see cref="TelegramBotHostBuilder"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TelegramBotHostBuilder : IHostApplicationBuilder, ICollectingProvider
|
/// <param name="hostApplicationBuilder"></param>
|
||||||
|
/// <param name="settings"></param>
|
||||||
|
public TelegramBotHostBuilder(HostApplicationBuilder hostApplicationBuilder, HostApplicationBuilderSettings? settings = null)
|
||||||
{
|
{
|
||||||
private readonly HostApplicationBuilder _innerBuilder;
|
_innerBuilder = hostApplicationBuilder ?? throw new ArgumentNullException(nameof(hostApplicationBuilder));
|
||||||
private readonly HostApplicationBuilderSettings _settings;
|
_settings = settings ?? new HostApplicationBuilderSettings();
|
||||||
internal IHandlersCollection _handlers = null!;
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>
|
||||||
public IHandlersCollection Handlers => _handlers;
|
/// Initializes a new instance of the <see cref="TelegramBotHostBuilder"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hostApplicationBuilder"></param>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <param name="settings"></param>
|
||||||
|
public TelegramBotHostBuilder(HostApplicationBuilder hostApplicationBuilder, TelegratorOptions? options, HostApplicationBuilderSettings? settings)
|
||||||
|
{
|
||||||
|
_innerBuilder = hostApplicationBuilder ?? throw new ArgumentNullException(nameof(hostApplicationBuilder));
|
||||||
|
_settings = settings ?? new HostApplicationBuilderSettings();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>
|
||||||
public IServiceCollection Services => _innerBuilder.Services;
|
/// Initializes a new instance of the <see cref="TelegramBotHostBuilder"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hostApplicationBuilder"></param>
|
||||||
|
/// <param name="handlers"></param>
|
||||||
|
/// <param name="settings"></param>
|
||||||
|
public TelegramBotHostBuilder(HostApplicationBuilder hostApplicationBuilder, IHandlersCollection handlers, HostApplicationBuilderSettings? settings)
|
||||||
|
{
|
||||||
|
_innerBuilder = hostApplicationBuilder ?? throw new ArgumentNullException(nameof(hostApplicationBuilder));
|
||||||
|
_settings = settings ?? new HostApplicationBuilderSettings();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>
|
||||||
public IConfigurationManager Configuration => _innerBuilder.Configuration;
|
/// Initializes a new instance of the <see cref="TelegramBotHostBuilder"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hostApplicationBuilder"></param>
|
||||||
|
/// <param name="handlers"></param>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <param name="settings"></param>
|
||||||
|
public TelegramBotHostBuilder(HostApplicationBuilder hostApplicationBuilder, IHandlersCollection handlers, TelegratorOptions? options, HostApplicationBuilderSettings? settings)
|
||||||
|
{
|
||||||
|
_innerBuilder = hostApplicationBuilder ?? throw new ArgumentNullException(nameof(hostApplicationBuilder));
|
||||||
|
_settings = settings ?? new HostApplicationBuilderSettings();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>
|
||||||
public ILoggingBuilder Logging => _innerBuilder.Logging;
|
/// Builds the host.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public TelegramBotHost Build()
|
||||||
|
{
|
||||||
|
TelegramBotHost host = new TelegramBotHost(_innerBuilder);
|
||||||
|
host.UseTelegrator();
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IHostEnvironment Environment => _innerBuilder.Environment;
|
public void ConfigureContainer<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory, Action<TContainerBuilder>? configure = null) where TContainerBuilder : notnull
|
||||||
|
{
|
||||||
/// <inheritdoc/>
|
_innerBuilder.ConfigureContainer(factory, configure);
|
||||||
public IDictionary<object, object> Properties => ((IHostApplicationBuilder)_innerBuilder).Properties;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public IMetricsBuilder Metrics => _innerBuilder.Metrics;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="TelegramBotHostBuilder"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hostApplicationBuilder"></param>
|
|
||||||
/// <param name="settings"></param>
|
|
||||||
public TelegramBotHostBuilder(HostApplicationBuilder hostApplicationBuilder, HostApplicationBuilderSettings? settings = null)
|
|
||||||
{
|
|
||||||
_innerBuilder = hostApplicationBuilder ?? throw new ArgumentNullException(nameof(hostApplicationBuilder));
|
|
||||||
_settings = settings ?? new HostApplicationBuilderSettings();
|
|
||||||
|
|
||||||
this.AddTelegrator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="TelegramBotHostBuilder"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hostApplicationBuilder"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <param name="settings"></param>
|
|
||||||
public TelegramBotHostBuilder(HostApplicationBuilder hostApplicationBuilder, TelegratorOptions? options, HostApplicationBuilderSettings? settings)
|
|
||||||
{
|
|
||||||
_innerBuilder = hostApplicationBuilder ?? throw new ArgumentNullException(nameof(hostApplicationBuilder));
|
|
||||||
_settings = settings ?? new HostApplicationBuilderSettings();
|
|
||||||
|
|
||||||
this.AddTelegrator(options, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="TelegramBotHostBuilder"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hostApplicationBuilder"></param>
|
|
||||||
/// <param name="handlers"></param>
|
|
||||||
/// <param name="settings"></param>
|
|
||||||
public TelegramBotHostBuilder(HostApplicationBuilder hostApplicationBuilder, IHandlersCollection handlers, HostApplicationBuilderSettings? settings)
|
|
||||||
{
|
|
||||||
_innerBuilder = hostApplicationBuilder ?? throw new ArgumentNullException(nameof(hostApplicationBuilder));
|
|
||||||
_settings = settings ?? new HostApplicationBuilderSettings();
|
|
||||||
|
|
||||||
this.AddTelegrator(null, handlers);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="TelegramBotHostBuilder"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hostApplicationBuilder"></param>
|
|
||||||
/// <param name="handlers"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <param name="settings"></param>
|
|
||||||
public TelegramBotHostBuilder(HostApplicationBuilder hostApplicationBuilder, IHandlersCollection handlers, TelegratorOptions? options, HostApplicationBuilderSettings? settings)
|
|
||||||
{
|
|
||||||
_innerBuilder = hostApplicationBuilder ?? throw new ArgumentNullException(nameof(hostApplicationBuilder));
|
|
||||||
_settings = settings ?? new HostApplicationBuilderSettings();
|
|
||||||
|
|
||||||
this.AddTelegrator(options, 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
|
|
||||||
{
|
|
||||||
this.ConfigureContainer(factory, configure);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +1,42 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
namespace Telegrator.Logging;
|
||||||
|
|
||||||
namespace Telegrator.Logging
|
/// <summary>
|
||||||
|
/// Adapter for Microsoft.Extensions.Logging to work with Telegrator logging system.
|
||||||
|
/// This allows seamless integration with ASP.NET Core logging infrastructure.
|
||||||
|
/// </summary>
|
||||||
|
public class MicrosoftLoggingAdapter : ITelegratorLogger
|
||||||
{
|
{
|
||||||
|
private readonly Microsoft.Extensions.Logging.ILogger _logger;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adapter for Microsoft.Extensions.Logging to work with Telegrator logging system.
|
/// Initializes a new instance of MicrosoftLoggingAdapter.
|
||||||
/// This allows seamless integration with ASP.NET Core logging infrastructure.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MicrosoftLoggingAdapter : ITelegratorLogger
|
/// <param name="logger">The Microsoft.Extensions.Logging logger instance.</param>
|
||||||
|
public MicrosoftLoggingAdapter(Microsoft.Extensions.Logging.ILogger logger)
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc/>
|
||||||
/// Initializes a new instance of MicrosoftLoggingAdapter.
|
public void Log(LogLevel level, string message, Exception? exception = null)
|
||||||
/// </summary>
|
{
|
||||||
/// <param name="logger">The Microsoft.Extensions.Logging logger instance.</param>
|
var msLogLevel = level switch
|
||||||
public MicrosoftLoggingAdapter(ILogger logger)
|
|
||||||
{
|
{
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
LogLevel.Trace => Microsoft.Extensions.Logging.LogLevel.Trace,
|
||||||
|
LogLevel.Debug => Microsoft.Extensions.Logging.LogLevel.Debug,
|
||||||
|
LogLevel.Information => Microsoft.Extensions.Logging.LogLevel.Information,
|
||||||
|
LogLevel.Warning => Microsoft.Extensions.Logging.LogLevel.Warning,
|
||||||
|
LogLevel.Error => Microsoft.Extensions.Logging.LogLevel.Error,
|
||||||
|
_ => Microsoft.Extensions.Logging.LogLevel.Information
|
||||||
|
};
|
||||||
|
|
||||||
|
if (exception != null)
|
||||||
|
{
|
||||||
|
_logger.Log(msLogLevel, default, message, exception, (str, exc) => string.Format("{0} : {1}", str, exc));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
/// <inheritdoc/>
|
|
||||||
public void Log(LogLevel level, string message, Exception? exception = null)
|
|
||||||
{
|
{
|
||||||
var msLogLevel = level switch
|
_logger.Log(msLogLevel, default, message, null, (str, _) => str);
|
||||||
{
|
|
||||||
Telegrator.Logging.LogLevel.Trace => Microsoft.Extensions.Logging.LogLevel.Trace,
|
|
||||||
Telegrator.Logging.LogLevel.Debug => Microsoft.Extensions.Logging.LogLevel.Debug,
|
|
||||||
Telegrator.Logging.LogLevel.Information => Microsoft.Extensions.Logging.LogLevel.Information,
|
|
||||||
Telegrator.Logging.LogLevel.Warning => Microsoft.Extensions.Logging.LogLevel.Warning,
|
|
||||||
Telegrator.Logging.LogLevel.Error => Microsoft.Extensions.Logging.LogLevel.Error,
|
|
||||||
_ => Microsoft.Extensions.Logging.LogLevel.Information
|
|
||||||
};
|
|
||||||
|
|
||||||
if (exception != null)
|
|
||||||
{
|
|
||||||
_logger.Log(msLogLevel, default, message, exception, (str, exc) => string.Format("{0} : {1}", str, exc));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.Log(msLogLevel, default, message, null, (str, _) => str);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,54 +7,53 @@ using Telegrator.Core;
|
|||||||
using Telegrator.Core.States;
|
using Telegrator.Core.States;
|
||||||
using Telegrator.Mediation;
|
using Telegrator.Mediation;
|
||||||
|
|
||||||
namespace Telegrator.Polling
|
namespace Telegrator.Polling;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public class HostUpdateRouter : UpdateRouter
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="ILogger"/> of this router
|
||||||
|
/// </summary>
|
||||||
|
protected readonly ILogger<HostUpdateRouter> Logger;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public class HostUpdateRouter : UpdateRouter
|
public HostUpdateRouter(
|
||||||
|
IHandlersProvider handlersProvider,
|
||||||
|
IAwaitingProvider awaitingProvider,
|
||||||
|
IStateStorage stateStorage,
|
||||||
|
IOptions<TelegratorOptions> options,
|
||||||
|
ITelegramBotInfo botInfo,
|
||||||
|
ILogger<HostUpdateRouter> logger) : base(handlersProvider, awaitingProvider, stateStorage, options.Value, botInfo)
|
||||||
{
|
{
|
||||||
/// <summary>
|
Logger = logger;
|
||||||
/// <see cref="ILogger"/> of this router
|
ExceptionHandler = new DefaultRouterExceptionHandler(HandleException);
|
||||||
/// </summary>
|
}
|
||||||
protected readonly ILogger<HostUpdateRouter> Logger;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public HostUpdateRouter(
|
public override Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)
|
||||||
IHandlersProvider handlersProvider,
|
{
|
||||||
IAwaitingProvider awaitingProvider,
|
//Logger.LogInformation("Received update of type \"{type}\"", update.Type);
|
||||||
IStateStorage stateStorage,
|
return base.HandleUpdateAsync(botClient, update, cancellationToken);
|
||||||
IOptions<TelegratorOptions> options,
|
}
|
||||||
ITelegramBotInfo botInfo,
|
|
||||||
ILogger<HostUpdateRouter> logger) : base(handlersProvider, awaitingProvider, stateStorage, options.Value, botInfo)
|
/// <summary>
|
||||||
|
/// Default exception handler of this router
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="botClient"></param>
|
||||||
|
/// <param name="exception"></param>
|
||||||
|
/// <param name="source"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
public void HandleException(ITelegramBotClient botClient, Exception exception, HandleErrorSource source, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (exception is HandlerFaultedException handlerFaultedException)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger.LogError("\"{handler}\" handler's execution was faulted :\n{exception}",
|
||||||
ExceptionHandler = new DefaultRouterExceptionHandler(HandleException);
|
handlerFaultedException.HandlerInfo.ToString(),
|
||||||
|
handlerFaultedException.InnerException?.ToString() ?? "No inner exception");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
Logger.LogError("Exception was thrown during update routing faulted :\n{exception}", exception.ToString());
|
||||||
public override Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
//Logger.LogInformation("Received update of type \"{type}\"", update.Type);
|
|
||||||
return base.HandleUpdateAsync(botClient, update, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Default exception handler of this router
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="botClient"></param>
|
|
||||||
/// <param name="exception"></param>
|
|
||||||
/// <param name="source"></param>
|
|
||||||
/// <param name="cancellationToken"></param>
|
|
||||||
public void HandleException(ITelegramBotClient botClient, Exception exception, HandleErrorSource source, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
if (exception is HandlerFaultedException handlerFaultedException)
|
|
||||||
{
|
|
||||||
Logger.LogError("\"{handler}\" handler's execution was faulted :\n{exception}",
|
|
||||||
handlerFaultedException.HandlerInfo.ToString(),
|
|
||||||
handlerFaultedException.InnerException?.ToString() ?? "No inner exception");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.LogError("Exception was thrown during update routing faulted :\n{exception}", exception.ToString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,27 +6,26 @@ using Telegram.Bot.Polling;
|
|||||||
using Telegrator.Core;
|
using Telegrator.Core;
|
||||||
using Telegrator.Mediation;
|
using Telegrator.Mediation;
|
||||||
|
|
||||||
namespace Telegrator.Polling
|
namespace Telegrator.Polling;
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Service for receiving updates for Hosted telegram bots
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="botClient"></param>
|
|
||||||
/// <param name="updateRouter"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <param name="logger"></param>
|
|
||||||
public class HostedUpdateReceiver(ITelegramBotClient botClient, IUpdateRouter updateRouter, IOptions<ReceiverOptions> options, ILogger<HostedUpdateReceiver> logger) : BackgroundService
|
|
||||||
{
|
|
||||||
private readonly ReceiverOptions _receiverOptions = options.Value;
|
|
||||||
private readonly IUpdateRouter _updateRouter = updateRouter;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
/// Service for receiving updates for Hosted telegram bots
|
||||||
{
|
/// </summary>
|
||||||
logger.LogInformation("Starting receiving updates via long-polling");
|
/// <param name="botClient"></param>
|
||||||
_receiverOptions.AllowedUpdates = _updateRouter.HandlersProvider.AllowedTypes.ToArray();
|
/// <param name="updateRouter"></param>
|
||||||
DefaultUpdateReceiver updateReceiver = new DefaultUpdateReceiver(botClient, _receiverOptions);
|
/// <param name="options"></param>
|
||||||
await updateReceiver.ReceiveAsync(_updateRouter, stoppingToken).ConfigureAwait(false);
|
/// <param name="logger"></param>
|
||||||
}
|
public class HostedUpdateReceiver(ITelegramBotClient botClient, IUpdateRouter updateRouter, IOptions<ReceiverOptions> options, ILogger<HostedUpdateReceiver> logger) : BackgroundService
|
||||||
|
{
|
||||||
|
private readonly ReceiverOptions _receiverOptions = options.Value;
|
||||||
|
private readonly IUpdateRouter _updateRouter = updateRouter;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
|
{
|
||||||
|
logger.LogInformation("Starting receiving updates via long-polling");
|
||||||
|
_receiverOptions.AllowedUpdates = _updateRouter.HandlersProvider.AllowedTypes.ToArray();
|
||||||
|
DefaultUpdateReceiver updateReceiver = new DefaultUpdateReceiver(botClient, _receiverOptions);
|
||||||
|
await updateReceiver.ReceiveAsync(_updateRouter, stoppingToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Options;
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace Telegrator.Providers
|
namespace Telegrator.Providers;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public class HostAwaitingProvider(IOptions<TelegratorOptions> options) : AwaitingProvider(options.Value)
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
|
||||||
public class HostAwaitingProvider(IOptions<TelegratorOptions> options, ILogger<HostAwaitingProvider> logger) : AwaitingProvider(options.Value)
|
|
||||||
{
|
|
||||||
private readonly ILogger<HostAwaitingProvider> _logger = logger;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,61 +2,60 @@
|
|||||||
using Telegrator.Core;
|
using Telegrator.Core;
|
||||||
using Telegrator.Core.Descriptors;
|
using Telegrator.Core.Descriptors;
|
||||||
|
|
||||||
namespace Telegrator.Providers
|
namespace Telegrator.Providers;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public class HostHandlersCollection(IServiceCollection hostServiceColletion, TelegratorOptions options) : HandlersCollection(options)
|
||||||
{
|
{
|
||||||
|
private readonly IServiceCollection Services = hostServiceColletion;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public class HostHandlersCollection(IServiceCollection hostServiceColletion, TelegratorOptions options) : HandlersCollection(options)
|
protected override bool MustHaveParameterlessCtor => false;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override IHandlersCollection AddDescriptor(HandlerDescriptor descriptor)
|
||||||
{
|
{
|
||||||
private readonly IServiceCollection Services = hostServiceColletion;
|
switch (descriptor.Type)
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override bool MustHaveParameterlessCtor => false;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override IHandlersCollection AddDescriptor(HandlerDescriptor descriptor)
|
|
||||||
{
|
{
|
||||||
switch (descriptor.Type)
|
case DescriptorType.General:
|
||||||
{
|
{
|
||||||
case DescriptorType.General:
|
if (descriptor.InstanceFactory != null)
|
||||||
{
|
Services.AddScoped(descriptor.HandlerType, _ => descriptor.InstanceFactory.Invoke());
|
||||||
if (descriptor.InstanceFactory != null)
|
else
|
||||||
Services.AddScoped(descriptor.HandlerType, _ => descriptor.InstanceFactory.Invoke());
|
Services.AddScoped(descriptor.HandlerType);
|
||||||
else
|
|
||||||
Services.AddScoped(descriptor.HandlerType);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DescriptorType.Keyed:
|
case DescriptorType.Keyed:
|
||||||
{
|
{
|
||||||
if (descriptor.InstanceFactory != null)
|
if (descriptor.InstanceFactory != null)
|
||||||
Services.AddKeyedScoped(descriptor.HandlerType, descriptor.ServiceKey, (_, _) => descriptor.InstanceFactory.Invoke());
|
Services.AddKeyedScoped(descriptor.HandlerType, descriptor.ServiceKey, (_, _) => descriptor.InstanceFactory.Invoke());
|
||||||
else
|
else
|
||||||
Services.AddKeyedScoped(descriptor.HandlerType, descriptor.ServiceKey);
|
Services.AddKeyedScoped(descriptor.HandlerType, descriptor.ServiceKey);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DescriptorType.Singleton:
|
case DescriptorType.Singleton:
|
||||||
{
|
{
|
||||||
Services.AddSingleton(descriptor.HandlerType, descriptor.SingletonInstance ?? (descriptor.InstanceFactory != null
|
Services.AddSingleton(descriptor.HandlerType, descriptor.SingletonInstance ?? (descriptor.InstanceFactory != null
|
||||||
? descriptor.InstanceFactory.Invoke()
|
? descriptor.InstanceFactory.Invoke()
|
||||||
: throw new Exception()));
|
: throw new Exception()));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DescriptorType.Implicit:
|
case DescriptorType.Implicit:
|
||||||
{
|
{
|
||||||
Services.AddKeyedSingleton(descriptor.HandlerType, descriptor.ServiceKey, descriptor.SingletonInstance ?? (descriptor.InstanceFactory != null
|
Services.AddKeyedSingleton(descriptor.HandlerType, descriptor.ServiceKey, descriptor.SingletonInstance ?? (descriptor.InstanceFactory != null
|
||||||
? descriptor.InstanceFactory.Invoke()
|
? descriptor.InstanceFactory.Invoke()
|
||||||
: throw new Exception()));
|
: throw new Exception()));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return base.AddDescriptor(descriptor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return base.AddDescriptor(descriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +1,40 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Telegrator.Core;
|
using Telegrator.Core;
|
||||||
using Telegrator.Core.Descriptors;
|
using Telegrator.Core.Descriptors;
|
||||||
using Telegrator.Core.Handlers;
|
using Telegrator.Core.Handlers;
|
||||||
|
|
||||||
namespace Telegrator.Providers
|
namespace Telegrator.Providers;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public class HostHandlersProvider : HandlersProvider
|
||||||
{
|
{
|
||||||
|
private readonly IServiceProvider Services;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public class HostHandlersProvider : HandlersProvider
|
public HostHandlersProvider(
|
||||||
|
IHandlersCollection handlers,
|
||||||
|
IOptions<TelegratorOptions> options,
|
||||||
|
IServiceProvider serviceProvider) : base(handlers, options.Value)
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider Services;
|
Services = serviceProvider;
|
||||||
private readonly ILogger<HostHandlersProvider> Logger;
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public HostHandlersProvider(
|
public override UpdateHandlerBase GetHandlerInstance(HandlerDescriptor descriptor, CancellationToken cancellationToken = default)
|
||||||
IHandlersCollection handlers,
|
{
|
||||||
IOptions<TelegratorOptions> options,
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
IServiceProvider serviceProvider,
|
IServiceScope scope = Services.CreateScope();
|
||||||
ILogger<HostHandlersProvider> logger) : base(handlers, options.Value)
|
|
||||||
{
|
|
||||||
Services = serviceProvider;
|
|
||||||
Logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
object handlerInstance = descriptor.ServiceKey == null
|
||||||
public override UpdateHandlerBase GetHandlerInstance(HandlerDescriptor descriptor, CancellationToken cancellationToken = default)
|
? scope.ServiceProvider.GetRequiredService(descriptor.HandlerType)
|
||||||
{
|
: scope.ServiceProvider.GetRequiredKeyedService(descriptor.HandlerType, descriptor.ServiceKey);
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
|
||||||
IServiceScope scope = Services.CreateScope();
|
|
||||||
|
|
||||||
object handlerInstance = descriptor.ServiceKey == null
|
if (handlerInstance is not UpdateHandlerBase updateHandler)
|
||||||
? scope.ServiceProvider.GetRequiredService(descriptor.HandlerType)
|
throw new InvalidOperationException("Failed to resolve " + descriptor.HandlerType + " as UpdateHandlerBase");
|
||||||
: scope.ServiceProvider.GetRequiredKeyedService(descriptor.HandlerType, descriptor.ServiceKey);
|
|
||||||
|
|
||||||
if (handlerInstance is not UpdateHandlerBase updateHandler)
|
descriptor.LazyInitialization?.Invoke(updateHandler);
|
||||||
throw new InvalidOperationException("Failed to resolve " + descriptor.HandlerType + " as UpdateHandlerBase");
|
updateHandler.LifetimeToken.OnLifetimeEnded += _ => scope.Dispose();
|
||||||
|
return updateHandler;
|
||||||
descriptor.LazyInitialization?.Invoke(updateHandler);
|
|
||||||
updateHandler.LifetimeToken.OnLifetimeEnded += _ => scope.Dispose();
|
|
||||||
return updateHandler;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||||
|
|
||||||
<Title>Telegrator.Hosting</Title>
|
<Title>Telegrator.Hosting</Title>
|
||||||
<Version>1.16.4</Version>
|
<Version>1.16.6</Version>
|
||||||
<Authors>Rikitav Tim4ik</Authors>
|
<Authors>Rikitav Tim4ik</Authors>
|
||||||
<Company>Rikitav Tim4ik</Company>
|
<Company>Rikitav Tim4ik</Company>
|
||||||
<RepositoryUrl>https://github.com/Rikitav/Telegrator</RepositoryUrl>
|
<RepositoryUrl>https://github.com/Rikitav/Telegrator</RepositoryUrl>
|
||||||
|
|||||||
@@ -11,10 +11,12 @@ using Telegram.Bot.Types;
|
|||||||
using Telegram.Bot.Types.Enums;
|
using Telegram.Bot.Types.Enums;
|
||||||
using Telegrator.Core;
|
using Telegrator.Core;
|
||||||
using Telegrator.Core.Descriptors;
|
using Telegrator.Core.Descriptors;
|
||||||
|
using Telegrator.Core.States;
|
||||||
using Telegrator.Hosting;
|
using Telegrator.Hosting;
|
||||||
using Telegrator.Logging;
|
using Telegrator.Logging;
|
||||||
using Telegrator.Polling;
|
using Telegrator.Polling;
|
||||||
using Telegrator.Providers;
|
using Telegrator.Providers;
|
||||||
|
using Telegrator.States;
|
||||||
|
|
||||||
namespace Telegrator;
|
namespace Telegrator;
|
||||||
|
|
||||||
@@ -28,7 +30,7 @@ public static class HostBuilderExtensions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const string HandlersCollectionPropertyKey = nameof(IHandlersCollection);
|
public const string HandlersCollectionPropertyKey = nameof(IHandlersCollection);
|
||||||
|
|
||||||
extension (IHostApplicationBuilder builder)
|
extension (HostApplicationBuilder builder)
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="IHandlersCollection"/> from the builder properties.
|
/// Gets the <see cref="IHandlersCollection"/> from the builder properties.
|
||||||
@@ -37,18 +39,35 @@ public static class HostBuilderExtensions
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (builder is TelegramBotHostBuilder botHostBuilder)
|
return (IHandlersCollection)((IHostApplicationBuilder)builder).Properties[HandlersCollectionPropertyKey];
|
||||||
return botHostBuilder.Handlers;
|
|
||||||
|
|
||||||
return (IHandlersCollection)builder.Properties[HandlersCollectionPropertyKey];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
|
/// Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IHostApplicationBuilder AddTelegrator(this IHostApplicationBuilder builder, TelegratorOptions? options = null, IHandlersCollection? handlers = null)
|
public static ITelegramBotHostBuilder AddTelegrator(this ITelegramBotHostBuilder builder, TelegratorOptions? options = null, IHandlersCollection? handlers = null, Action<ITelegramBotHostBuilder>? action = null)
|
||||||
|
{
|
||||||
|
builder.AddTelegratorInternal(options, 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)
|
||||||
|
{
|
||||||
|
builder.AddTelegratorInternal(options, handlers);
|
||||||
|
action?.Invoke(new TelegramBotHostBuilder(builder));
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Replaces TelegramBotHostBuilder. Configures DI, options, and handlers.
|
||||||
|
/// </summary>
|
||||||
|
public static IHostApplicationBuilder AddTelegratorInternal(this IHostApplicationBuilder builder, TelegratorOptions? options = null, IHandlersCollection? handlers = null)
|
||||||
{
|
{
|
||||||
IServiceCollection services = builder.Services;
|
IServiceCollection services = builder.Services;
|
||||||
IConfigurationManager configuration = builder.Configuration;
|
IConfigurationManager configuration = builder.Configuration;
|
||||||
@@ -112,6 +131,18 @@ public static class HostBuilderExtensions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ServicesCollectionExtensions
|
public static class ServicesCollectionExtensions
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Registers <see cref="IStateStorage"/> service
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TStorage"></typeparam>
|
||||||
|
/// <param name="services"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IServiceCollection AddStateStorage<TStorage>(this IServiceCollection services) where TStorage : IStateStorage
|
||||||
|
{
|
||||||
|
services.Replace(new ServiceDescriptor(typeof(IStateStorage), typeof(TStorage), ServiceLifetime.Singleton));
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers <see cref="TelegramBotHost"/> default services
|
/// Registers <see cref="TelegramBotHost"/> default services
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -119,11 +150,11 @@ public static class ServicesCollectionExtensions
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static IServiceCollection AddTelegramBotHostDefaults(this IServiceCollection services)
|
public static IServiceCollection AddTelegramBotHostDefaults(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddLogging(builder => builder.AddConsole().AddDebug());
|
|
||||||
services.AddSingleton<IAwaitingProvider, HostAwaitingProvider>();
|
services.AddSingleton<IAwaitingProvider, HostAwaitingProvider>();
|
||||||
services.AddSingleton<IHandlersProvider, HostHandlersProvider>();
|
services.AddSingleton<IHandlersProvider, HostHandlersProvider>();
|
||||||
services.AddSingleton<IUpdateRouter, HostUpdateRouter>();
|
services.AddSingleton<IUpdateRouter, HostUpdateRouter>();
|
||||||
services.AddSingleton<ITelegramBotInfo, HostedTelegramBotInfo>();
|
services.AddSingleton<ITelegramBotInfo, HostedTelegramBotInfo>();
|
||||||
|
services.AddSingleton<IStateStorage, DefaultStateStorage>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,13 @@ using System.Threading.Tasks;
|
|||||||
using Telegram.Bot.Types;
|
using Telegram.Bot.Types;
|
||||||
using Telegrator.Handlers;
|
using Telegrator.Handlers;
|
||||||
|
|
||||||
namespace Telegrator.Localized
|
namespace Telegrator.Localized;
|
||||||
|
|
||||||
|
public static class LocalizedMessageHandlerExtensions
|
||||||
{
|
{
|
||||||
public static class LocalizedMessageHandlerExtensions
|
public static async Task<Message> ResponseLocalized(this ILocalizedHandler<Message> localizedHandler, string localizedReplyIdentifier, params IEnumerable<string> formatArgs)
|
||||||
{
|
{
|
||||||
public static async Task<Message> ResponseLocalized(this ILocalizedHandler<Message> localizedHandler, string localizedReplyIdentifier, params IEnumerable<string> formatArgs)
|
LocalizedString localizedString = localizedHandler.LocalizationProvider[localizedReplyIdentifier, formatArgs];
|
||||||
{
|
return await localizedHandler.Container.Responce(localizedString.Value);
|
||||||
LocalizedString localizedString = localizedHandler.LocalizationProvider[localizedReplyIdentifier, formatArgs];
|
|
||||||
return await localizedHandler.Container.Responce(localizedString.Value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,41 +4,40 @@ using Telegrator.Attributes;
|
|||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
using Telegrator.Filters;
|
using Telegrator.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Annotations
|
namespace Telegrator.Annotations;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract base attribute for filtering callback-based updates.
|
||||||
|
/// Supports various message types including regular messages, edited messages, channel posts, and business messages.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filters">The filters to apply to messages</param>
|
||||||
|
public abstract class CallbackQueryAttribute(params IFilter<CallbackQuery>[] filters) : UpdateFilterAttribute<CallbackQuery>(filters)
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstract base attribute for filtering callback-based updates.
|
/// Gets the allowed update types that this filter can process.
|
||||||
/// Supports various message types including regular messages, edited messages, channel posts, and business messages.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filters">The filters to apply to messages</param>
|
public override UpdateType[] AllowedTypes => [UpdateType.CallbackQuery];
|
||||||
public abstract class CallbackQueryAttribute(params IFilter<CallbackQuery>[] filters) : UpdateFilterAttribute<CallbackQuery>(filters)
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the allowed update types that this filter can process.
|
|
||||||
/// </summary>
|
|
||||||
public override UpdateType[] AllowedTypes => [UpdateType.CallbackQuery];
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Extracts the message from various types of updates.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="update">The Telegram update</param>
|
|
||||||
/// <returns>The message from the update, or null if not present</returns>
|
|
||||||
public override CallbackQuery? GetFilterringTarget(Update update)
|
|
||||||
=> update.CallbackQuery;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering <see cref="CallbackQuery"/>'s data
|
/// Extracts the message from various types of updates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data"></param>
|
/// <param name="update">The Telegram update</param>
|
||||||
public class CallbackDataAttribute(string data)
|
/// <returns>The message from the update, or null if not present</returns>
|
||||||
: CallbackQueryAttribute(new CallbackDataFilter(data))
|
public override CallbackQuery? GetFilterringTarget(Update update)
|
||||||
{ }
|
=> update.CallbackQuery;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute to check if <see cref="CallbackQuery"/> belongs to a specific message by its ID
|
|
||||||
/// </summary>
|
|
||||||
public class CallbackInlineIdAttribute(string inlineMessageId)
|
|
||||||
: CallbackQueryAttribute(new CallbackInlineIdFilter(inlineMessageId))
|
|
||||||
{ }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering <see cref="CallbackQuery"/>'s data
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
public class CallbackDataAttribute(string data)
|
||||||
|
: CallbackQueryAttribute(new CallbackDataFilter(data))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute to check if <see cref="CallbackQuery"/> belongs to a specific message by its ID
|
||||||
|
/// </summary>
|
||||||
|
public class CallbackInlineIdAttribute(string inlineMessageId)
|
||||||
|
: CallbackQueryAttribute(new CallbackInlineIdFilter(inlineMessageId))
|
||||||
|
{ }
|
||||||
|
|||||||
@@ -3,58 +3,57 @@ using Telegram.Bot.Types.Enums;
|
|||||||
using Telegrator.Filters;
|
using Telegrator.Filters;
|
||||||
using Telegrator.Attributes;
|
using Telegrator.Attributes;
|
||||||
|
|
||||||
namespace Telegrator.Annotations
|
namespace Telegrator.Annotations;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering messages based on command aliases.
|
||||||
|
/// Allows handlers to respond to multiple command variations using a single attribute.
|
||||||
|
/// </summary>
|
||||||
|
public class CommandAlliasAttribute : UpdateFilterAttribute<Message>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering messages based on command aliases.
|
/// Gets the allowed update types for this filter.
|
||||||
/// Allows handlers to respond to multiple command variations using a single attribute.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CommandAlliasAttribute : UpdateFilterAttribute<Message>
|
public override UpdateType[] AllowedTypes => [UpdateType.Message];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The description of the command (defaults to "no description provided").
|
||||||
|
/// </summary>
|
||||||
|
private string _description = "no description provided";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the array of command aliases that this filter will match.
|
||||||
|
/// </summary>
|
||||||
|
public string[] Alliases
|
||||||
{
|
{
|
||||||
/// <summary>
|
get;
|
||||||
/// Gets the allowed update types for this filter.
|
private set;
|
||||||
/// </summary>
|
|
||||||
public override UpdateType[] AllowedTypes => [UpdateType.Message];
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The description of the command (defaults to "no description provided").
|
|
||||||
/// </summary>
|
|
||||||
private string _description = "no description provided";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the array of command aliases that this filter will match.
|
|
||||||
/// </summary>
|
|
||||||
public string[] Alliases
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the description of the command.
|
|
||||||
/// Must be between 0 and 256 characters in length.
|
|
||||||
/// </summary>
|
|
||||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when the description length is outside the allowed range.</exception>
|
|
||||||
public string Description
|
|
||||||
{
|
|
||||||
get => _description;
|
|
||||||
set => _description = value is { Length: <= 256 and >= 0 }
|
|
||||||
? value : throw new ArgumentOutOfRangeException(nameof(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the CommandAlliasAttribute with the specified command aliases.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="alliases">The command aliases to match against.</param>
|
|
||||||
public CommandAlliasAttribute(params string[] alliases)
|
|
||||||
: base(new CommandAlliasFilter(alliases.Select(c => c.TrimStart('/')).ToArray()))
|
|
||||||
=> Alliases = alliases.Select(c => c.TrimStart('/')).ToArray();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the filtering target (Message) from the update.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="update">The Telegram update.</param>
|
|
||||||
/// <returns>The message from the update, or null if not present.</returns>
|
|
||||||
public override Message? GetFilterringTarget(Update update) => update.Message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the description of the command.
|
||||||
|
/// Must be between 0 and 256 characters in length.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown when the description length is outside the allowed range.</exception>
|
||||||
|
public string Description
|
||||||
|
{
|
||||||
|
get => _description;
|
||||||
|
set => _description = value is { Length: <= 256 and >= 0 }
|
||||||
|
? value : throw new ArgumentOutOfRangeException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the CommandAlliasAttribute with the specified command aliases.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="alliases">The command aliases to match against.</param>
|
||||||
|
public CommandAlliasAttribute(params string[] alliases)
|
||||||
|
: base(new CommandAlliasFilter(alliases.Select(c => c.TrimStart('/')).ToArray()))
|
||||||
|
=> Alliases = alliases.Select(c => c.TrimStart('/')).ToArray();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the filtering target (Message) from the update.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="update">The Telegram update.</param>
|
||||||
|
/// <returns>The message from the update, or null if not present.</returns>
|
||||||
|
public override Message? GetFilterringTarget(Update update) => update.Message;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,63 +1,62 @@
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Telegrator.Filters;
|
using Telegrator.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Annotations
|
namespace Telegrator.Annotations;
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute for filtering messages where a command has arguments count >= <paramref name="count"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="count"></param>
|
|
||||||
public class ArgumentCountAttribute(int count)
|
|
||||||
: MessageFilterAttribute(new ArgumentCountFilter(count))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering messages where a command argument starts with the specified content.
|
/// Attribute for filtering messages where a command has arguments count >= <paramref name="count"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="content">The content that the command argument should start with.</param>
|
/// <param name="count"></param>
|
||||||
/// <param name="comparison">The string comparison type to use for the check.</param>
|
public class ArgumentCountAttribute(int count)
|
||||||
/// <param name="index">The index of the argument to check (0-based).</param>
|
: MessageFilterAttribute(new ArgumentCountFilter(count))
|
||||||
public class ArgumentStartsWithAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0)
|
{ }
|
||||||
: MessageFilterAttribute(new ArgumentStartsWithFilter(content, comparison, index))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering messages where a command argument ends with the specified content.
|
/// Attribute for filtering messages where a command argument starts with the specified content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="content">The content that the command argument should end with.</param>
|
/// <param name="content">The content that the command argument should start with.</param>
|
||||||
/// <param name="comparison">The string comparison type to use for the check.</param>
|
/// <param name="comparison">The string comparison type to use for the check.</param>
|
||||||
/// <param name="index">The index of the argument to check (0-based).</param>
|
/// <param name="index">The index of the argument to check (0-based).</param>
|
||||||
public class ArgumentEndsWithAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0)
|
public class ArgumentStartsWithAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0)
|
||||||
: MessageFilterAttribute(new ArgumentEndsWithFilter(content, comparison, index))
|
: MessageFilterAttribute(new ArgumentStartsWithFilter(content, comparison, index))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering messages where a command argument contains the specified content.
|
/// Attribute for filtering messages where a command argument ends with the specified content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="content">The content that the command argument should contain.</param>
|
/// <param name="content">The content that the command argument should end with.</param>
|
||||||
/// <param name="comparison">The string comparison type to use for the check.</param>
|
/// <param name="comparison">The string comparison type to use for the check.</param>
|
||||||
/// <param name="index">The index of the argument to check (0-based).</param>
|
/// <param name="index">The index of the argument to check (0-based).</param>
|
||||||
public class ArgumentContainsAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0)
|
public class ArgumentEndsWithAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0)
|
||||||
: MessageFilterAttribute(new ArgumentContainsFilter(content, comparison, index))
|
: MessageFilterAttribute(new ArgumentEndsWithFilter(content, comparison, index))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering messages where a command argument equals the specified content.
|
/// Attribute for filtering messages where a command argument contains the specified content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="content">The content that the command argument should equal.</param>
|
/// <param name="content">The content that the command argument should contain.</param>
|
||||||
/// <param name="comparison">The string comparison type to use for the check.</param>
|
/// <param name="comparison">The string comparison type to use for the check.</param>
|
||||||
/// <param name="index">The index of the argument to check (0-based).</param>
|
/// <param name="index">The index of the argument to check (0-based).</param>
|
||||||
public class ArgumentEqualsAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0)
|
public class ArgumentContainsAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0)
|
||||||
: MessageFilterAttribute(new ArgumentEqualsFilter(content, comparison, index))
|
: MessageFilterAttribute(new ArgumentContainsFilter(content, comparison, index))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering messages where a command argument matches a regular expression pattern.
|
/// Attribute for filtering messages where a command argument equals the specified content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pattern">The regular expression pattern to match against the command argument.</param>
|
/// <param name="content">The content that the command argument should equal.</param>
|
||||||
/// <param name="options">The regex options to use for the pattern matching.</param>
|
/// <param name="comparison">The string comparison type to use for the check.</param>
|
||||||
/// <param name="index">The index of the argument to check (0-based).</param>
|
/// <param name="index">The index of the argument to check (0-based).</param>
|
||||||
public class ArgumentRegexAttribute(string pattern, RegexOptions options = RegexOptions.None, int index = 0)
|
public class ArgumentEqualsAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0)
|
||||||
: MessageFilterAttribute(new ArgumentRegexFilter(pattern, options, index: index))
|
: MessageFilterAttribute(new ArgumentEqualsFilter(content, comparison, index))
|
||||||
{ }
|
{ }
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering messages where a command argument matches a regular expression pattern.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pattern">The regular expression pattern to match against the command argument.</param>
|
||||||
|
/// <param name="options">The regex options to use for the pattern matching.</param>
|
||||||
|
/// <param name="index">The index of the argument to check (0-based).</param>
|
||||||
|
public class ArgumentRegexAttribute(string pattern, RegexOptions options = RegexOptions.None, int index = 0)
|
||||||
|
: MessageFilterAttribute(new ArgumentRegexFilter(pattern, options, index: index))
|
||||||
|
{ }
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
namespace Telegrator.Annotations
|
namespace Telegrator.Annotations;
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute that prevents a class from being automatically collected by the handler collection system.
|
/// Attribute that prevents a class from being automatically collected by the handler collection system.
|
||||||
/// When applied to a class, it will be excluded from domain-wide handler collection operations.
|
/// When applied to a class, it will be excluded from domain-wide handler collection operations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
|
||||||
public class DontCollectAttribute : Attribute
|
public class DontCollectAttribute : Attribute
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,82 +4,81 @@ using Telegrator.Filters;
|
|||||||
using Telegrator.Attributes;
|
using Telegrator.Attributes;
|
||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Annotations
|
namespace Telegrator.Annotations;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract base attribute for filtering updates based on environment conditions.
|
||||||
|
/// Can process all types of updates and provides environment-specific filtering logic.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filters">The environment filters to apply</param>
|
||||||
|
public abstract class EnvironmentFilterAttribute(params IFilter<Update>[] filters) : UpdateFilterAttribute<Update>(filters)
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstract base attribute for filtering updates based on environment conditions.
|
/// Gets the allowed update types that this filter can process.
|
||||||
/// Can process all types of updates and provides environment-specific filtering logic.
|
/// Environment filters can process all update types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filters">The environment filters to apply</param>
|
public override UpdateType[] AllowedTypes => Update.AllTypes;
|
||||||
public abstract class EnvironmentFilterAttribute(params IFilter<Update>[] filters) : UpdateFilterAttribute<Update>(filters)
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the allowed update types that this filter can process.
|
|
||||||
/// Environment filters can process all update types.
|
|
||||||
/// </summary>
|
|
||||||
public override UpdateType[] AllowedTypes => Update.AllTypes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the update as the filtering target.
|
|
||||||
/// Environment filters work with the entire update object.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="update">The Telegram update</param>
|
|
||||||
/// <returns>The update object itself</returns>
|
|
||||||
public override Update? GetFilterringTarget(Update update)
|
|
||||||
=> update;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering updates that occur in debug environment.
|
/// Gets the update as the filtering target.
|
||||||
/// Only allows updates when the application is running in debug mode.
|
/// Environment filters work with the entire update object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class IsDebugEnvironmentAttribute()
|
/// <param name="update">The Telegram update</param>
|
||||||
: EnvironmentFilterAttribute(new IsDebugEnvironmentFilter())
|
/// <returns>The update object itself</returns>
|
||||||
{ }
|
public override Update? GetFilterringTarget(Update update)
|
||||||
|
=> update;
|
||||||
/// <summary>
|
}
|
||||||
/// Attribute for filtering updates that occur in release environment.
|
|
||||||
/// Only allows updates when the application is running in release mode.
|
/// <summary>
|
||||||
/// </summary>
|
/// Attribute for filtering updates that occur in debug environment.
|
||||||
public class IsReleaseEnvironmentAttribute()
|
/// Only allows updates when the application is running in debug mode.
|
||||||
: EnvironmentFilterAttribute(new IsReleaseEnvironmentFilter())
|
/// </summary>
|
||||||
{ }
|
public class IsDebugEnvironmentAttribute()
|
||||||
|
: EnvironmentFilterAttribute(new IsDebugEnvironmentFilter())
|
||||||
/// <summary>
|
{ }
|
||||||
/// Attribute for filtering updates based on environment variable values.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public class EnvironmentVariableAttribute : EnvironmentFilterAttribute
|
/// Attribute for filtering updates that occur in release environment.
|
||||||
{
|
/// Only allows updates when the application is running in release mode.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Initializes the attribute to filter based on an environment variable with a specific value and comparison method.
|
public class IsReleaseEnvironmentAttribute()
|
||||||
/// </summary>
|
: EnvironmentFilterAttribute(new IsReleaseEnvironmentFilter())
|
||||||
/// <param name="variable">The name of the environment variable</param>
|
{ }
|
||||||
/// <param name="value">The expected value of the environment variable</param>
|
|
||||||
/// <param name="comparison">The string comparison method</param>
|
/// <summary>
|
||||||
public EnvironmentVariableAttribute(string variable, string? value, StringComparison comparison)
|
/// Attribute for filtering updates based on environment variable values.
|
||||||
: base(new EnvironmentVariableFilter(variable, value, comparison)) { }
|
/// </summary>
|
||||||
|
public class EnvironmentVariableAttribute : EnvironmentFilterAttribute
|
||||||
/// <summary>
|
{
|
||||||
/// Initializes the attribute to filter based on an environment variable with a specific value.
|
/// <summary>
|
||||||
/// </summary>
|
/// Initializes the attribute to filter based on an environment variable with a specific value and comparison method.
|
||||||
/// <param name="variable">The name of the environment variable</param>
|
/// </summary>
|
||||||
/// <param name="value">The expected value of the environment variable</param>
|
/// <param name="variable">The name of the environment variable</param>
|
||||||
public EnvironmentVariableAttribute(string variable, string? value)
|
/// <param name="value">The expected value of the environment variable</param>
|
||||||
: base(new EnvironmentVariableFilter(variable, value)) { }
|
/// <param name="comparison">The string comparison method</param>
|
||||||
|
public EnvironmentVariableAttribute(string variable, string? value, StringComparison comparison)
|
||||||
/// <summary>
|
: base(new EnvironmentVariableFilter(variable, value, comparison)) { }
|
||||||
/// Initializes the attribute to filter based on the existence of an environment variable.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <param name="variable">The name of the environment variable</param>
|
/// Initializes the attribute to filter based on an environment variable with a specific value.
|
||||||
public EnvironmentVariableAttribute(string variable)
|
/// </summary>
|
||||||
: base(new EnvironmentVariableFilter(variable)) { }
|
/// <param name="variable">The name of the environment variable</param>
|
||||||
|
/// <param name="value">The expected value of the environment variable</param>
|
||||||
/// <summary>
|
public EnvironmentVariableAttribute(string variable, string? value)
|
||||||
/// Initializes the attribute to filter based on an environment variable with a specific comparison method.
|
: base(new EnvironmentVariableFilter(variable, value)) { }
|
||||||
/// </summary>
|
|
||||||
/// <param name="variable">The name of the environment variable</param>
|
/// <summary>
|
||||||
/// <param name="comparison">The string comparison method</param>
|
/// Initializes the attribute to filter based on the existence of an environment variable.
|
||||||
public EnvironmentVariableAttribute(string variable, StringComparison comparison)
|
/// </summary>
|
||||||
: base(new EnvironmentVariableFilter(variable, comparison)) { }
|
/// <param name="variable">The name of the environment variable</param>
|
||||||
}
|
public EnvironmentVariableAttribute(string variable)
|
||||||
|
: base(new EnvironmentVariableFilter(variable)) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the attribute to filter based on an environment variable with a specific comparison method.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="variable">The name of the environment variable</param>
|
||||||
|
/// <param name="comparison">The string comparison method</param>
|
||||||
|
public EnvironmentVariableAttribute(string variable, StringComparison comparison)
|
||||||
|
: base(new EnvironmentVariableFilter(variable, comparison)) { }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +1,39 @@
|
|||||||
using Telegram.Bot.Types.Enums;
|
using Telegram.Bot.Types.Enums;
|
||||||
using Telegrator.Filters;
|
using Telegrator.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Annotations
|
namespace Telegrator.Annotations;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering messages that contain mentions.
|
||||||
|
/// Allows handlers to respond only to messages that mention the bot or specific users.
|
||||||
|
/// </summary>
|
||||||
|
public class MentionedAttribute : MessageFilterAttribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering messages that contain mentions.
|
/// Initializes a new instance of the MentionedAttribute that matches any mention.
|
||||||
/// Allows handlers to respond only to messages that mention the bot or specific users.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MentionedAttribute : MessageFilterAttribute
|
public MentionedAttribute()
|
||||||
{
|
: base(new MessageHasEntityFilter(MessageEntityType.Mention, null, null), new MentionedFilter()) { }
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the MentionedAttribute that matches any mention.
|
|
||||||
/// </summary>
|
|
||||||
public MentionedAttribute()
|
|
||||||
: base(new MessageHasEntityFilter(MessageEntityType.Mention, null, null), new MentionedFilter()) { }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the MentionedAttribute that matches mentions at a specific offset.
|
/// Initializes a new instance of the MentionedAttribute that matches mentions at a specific offset.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="offset">The offset position where the mention should occur.</param>
|
/// <param name="offset">The offset position where the mention should occur.</param>
|
||||||
public MentionedAttribute(int offset)
|
public MentionedAttribute(int offset)
|
||||||
: base(new MessageHasEntityFilter(MessageEntityType.Mention, offset, null), new MentionedFilter()) { }
|
: base(new MessageHasEntityFilter(MessageEntityType.Mention, offset, null), new MentionedFilter()) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the MentionedAttribute that matches a specific mention.
|
/// Initializes a new instance of the MentionedAttribute that matches a specific mention.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="mention">The specific mention text to match.</param>
|
/// <param name="mention">The specific mention text to match.</param>
|
||||||
public MentionedAttribute(string mention)
|
public MentionedAttribute(string mention)
|
||||||
: base(new MessageHasEntityFilter(MessageEntityType.Mention), new MentionedFilter(mention)) { }
|
: base(new MessageHasEntityFilter(MessageEntityType.Mention), new MentionedFilter(mention)) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the MentionedAttribute that matches a specific mention at a specific offset.
|
/// Initializes a new instance of the MentionedAttribute that matches a specific mention at a specific offset.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="mention">The specific mention text to match.</param>
|
/// <param name="mention">The specific mention text to match.</param>
|
||||||
/// <param name="offset">The offset position where the mention should occur.</param>
|
/// <param name="offset">The offset position where the mention should occur.</param>
|
||||||
public MentionedAttribute(string mention, int offset)
|
public MentionedAttribute(string mention, int offset)
|
||||||
: base(new MessageHasEntityFilter(MessageEntityType.Mention, offset, null), new MentionedFilter(mention)) { }
|
: base(new MessageHasEntityFilter(MessageEntityType.Mention, offset, null), new MentionedFilter(mention)) { }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,105 +1,104 @@
|
|||||||
using Telegram.Bot.Types.Enums;
|
using Telegram.Bot.Types.Enums;
|
||||||
using Telegrator.Filters;
|
using Telegrator.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Annotations
|
namespace Telegrator.Annotations;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering messages sent in forum chats.
|
||||||
|
/// </summary>
|
||||||
|
public class ChatIsForumAttribute()
|
||||||
|
: MessageFilterAttribute(new MessageChatIsForumFilter())
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering messages sent in a specific chat by ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The chat ID to match</param>
|
||||||
|
public class ChatIdAttribute(long id)
|
||||||
|
: MessageFilterAttribute(new MessageChatIdFilter(id))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering messages sent in chats of a specific type.
|
||||||
|
/// </summary>
|
||||||
|
public class ChatTypeAttribute : MessageFilterAttribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering messages sent in forum chats.
|
/// Initialize new instance of <see cref="ChatTypeAttribute"/> to filter messages from chat from specific chats
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ChatIsForumAttribute()
|
/// <param name="type"></param>
|
||||||
: MessageFilterAttribute(new MessageChatIsForumFilter())
|
public ChatTypeAttribute(ChatType type)
|
||||||
{ }
|
: base(new MessageChatTypeFilter(type)) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering messages sent in a specific chat by ID.
|
/// Initialize new instance of <see cref="ChatTypeAttribute"/> to filter messages from chat from specific chats (with flags)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The chat ID to match</param>
|
/// <param name="flags"></param>
|
||||||
public class ChatIdAttribute(long id)
|
public ChatTypeAttribute(ChatTypeFlags flags)
|
||||||
: MessageFilterAttribute(new MessageChatIdFilter(id))
|
: base(new MessageChatTypeFilter(flags)) { }
|
||||||
{ }
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering messages sent in chats of a specific type.
|
/// Attribute for filtering messages based on the chat title.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ChatTypeAttribute : MessageFilterAttribute
|
public class ChatTitleAttribute : MessageFilterAttribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize new instance of <see cref="ChatTypeAttribute"/> to filter messages from chat from specific chats
|
/// Initializes the attribute to filter messages from chats with a specific title and comparison method.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type"></param>
|
/// <param name="title">The chat title to match</param>
|
||||||
public ChatTypeAttribute(ChatType type)
|
/// <param name="comparison">The string comparison method</param>
|
||||||
: base(new MessageChatTypeFilter(type)) { }
|
public ChatTitleAttribute(string? title, StringComparison comparison)
|
||||||
|
: base(new MessageChatTitleFilter(title, comparison)) { }
|
||||||
/// <summary>
|
|
||||||
/// Initialize new instance of <see cref="ChatTypeAttribute"/> to filter messages from chat from specific chats (with flags)
|
/// <summary>
|
||||||
/// </summary>
|
/// Initializes the attribute to filter messages from chats with a specific title.
|
||||||
/// <param name="flags"></param>
|
/// </summary>
|
||||||
public ChatTypeAttribute(ChatTypeFlags flags)
|
/// <param name="title">The chat title to match</param>
|
||||||
: base(new MessageChatTypeFilter(flags)) { }
|
public ChatTitleAttribute(string? title)
|
||||||
}
|
: base(new MessageChatTitleFilter(title)) { }
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Attribute for filtering messages based on the chat title.
|
/// <summary>
|
||||||
/// </summary>
|
/// Attribute for filtering messages based on the chat username.
|
||||||
public class ChatTitleAttribute : MessageFilterAttribute
|
/// </summary>
|
||||||
{
|
public class ChatUsernameAttribute : MessageFilterAttribute
|
||||||
/// <summary>
|
{
|
||||||
/// Initializes the attribute to filter messages from chats with a specific title and comparison method.
|
/// <summary>
|
||||||
/// </summary>
|
/// Initializes the attribute to filter messages from chats with a specific username and comparison method.
|
||||||
/// <param name="title">The chat title to match</param>
|
/// </summary>
|
||||||
/// <param name="comparison">The string comparison method</param>
|
/// <param name="userName">The chat username to match</param>
|
||||||
public ChatTitleAttribute(string? title, StringComparison comparison)
|
/// <param name="comparison">The string comparison method</param>
|
||||||
: base(new MessageChatTitleFilter(title, comparison)) { }
|
public ChatUsernameAttribute(string? userName, StringComparison comparison)
|
||||||
|
: base(new MessageChatUsernameFilter(userName, comparison)) { }
|
||||||
/// <summary>
|
|
||||||
/// Initializes the attribute to filter messages from chats with a specific title.
|
/// <summary>
|
||||||
/// </summary>
|
/// Initializes the attribute to filter messages from chats with a specific username.
|
||||||
/// <param name="title">The chat title to match</param>
|
/// </summary>
|
||||||
public ChatTitleAttribute(string? title)
|
/// <param name="userName">The chat username to match</param>
|
||||||
: base(new MessageChatTitleFilter(title)) { }
|
public ChatUsernameAttribute(string? userName)
|
||||||
}
|
: base(new MessageChatUsernameFilter(userName, StringComparison.InvariantCulture)) { }
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Attribute for filtering messages based on the chat username.
|
/// <summary>
|
||||||
/// </summary>
|
/// Attribute for filtering messages based on the chat name (first name and optionally last name).
|
||||||
public class ChatUsernameAttribute : MessageFilterAttribute
|
/// </summary>
|
||||||
{
|
public class ChatNameAttribute : MessageFilterAttribute
|
||||||
/// <summary>
|
{
|
||||||
/// Initializes the attribute to filter messages from chats with a specific username and comparison method.
|
/// <summary>
|
||||||
/// </summary>
|
/// Initializes the attribute to filter messages from chats with specific first and last names.
|
||||||
/// <param name="userName">The chat username to match</param>
|
/// </summary>
|
||||||
/// <param name="comparison">The string comparison method</param>
|
/// <param name="firstName">The first name to match</param>
|
||||||
public ChatUsernameAttribute(string? userName, StringComparison comparison)
|
/// <param name="lastName">The last name to match (optional)</param>
|
||||||
: base(new MessageChatUsernameFilter(userName, comparison)) { }
|
/// <param name="comparison">The string comparison method</param>
|
||||||
|
public ChatNameAttribute(string? firstName, string? lastName, StringComparison comparison)
|
||||||
/// <summary>
|
: base(new MessageChatNameFilter(firstName, lastName, comparison)) { }
|
||||||
/// Initializes the attribute to filter messages from chats with a specific username.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <param name="userName">The chat username to match</param>
|
/// Initializes the attribute to filter messages from chats with specific first and last names.
|
||||||
public ChatUsernameAttribute(string? userName)
|
/// </summary>
|
||||||
: base(new MessageChatUsernameFilter(userName, StringComparison.InvariantCulture)) { }
|
/// <param name="firstName">The first name to match</param>
|
||||||
}
|
/// <param name="lastName">The last name to match (optional)</param>
|
||||||
|
public ChatNameAttribute(string? firstName, string? lastName)
|
||||||
/// <summary>
|
: base(new MessageChatNameFilter(firstName, lastName)) { }
|
||||||
/// Attribute for filtering messages based on the chat name (first name and optionally last name).
|
|
||||||
/// </summary>
|
|
||||||
public class ChatNameAttribute : MessageFilterAttribute
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the attribute to filter messages from chats with specific first and last names.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="firstName">The first name to match</param>
|
|
||||||
/// <param name="lastName">The last name to match (optional)</param>
|
|
||||||
/// <param name="comparison">The string comparison method</param>
|
|
||||||
public ChatNameAttribute(string? firstName, string? lastName, StringComparison comparison)
|
|
||||||
: base(new MessageChatNameFilter(firstName, lastName, comparison)) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the attribute to filter messages from chats with specific first and last names.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="firstName">The first name to match</param>
|
|
||||||
/// <param name="lastName">The last name to match (optional)</param>
|
|
||||||
public ChatNameAttribute(string? firstName, string? lastName)
|
|
||||||
: base(new MessageChatNameFilter(firstName, lastName)) { }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,157 +5,156 @@ using Telegrator.Filters;
|
|||||||
using Telegrator.Attributes;
|
using Telegrator.Attributes;
|
||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Annotations
|
namespace Telegrator.Annotations;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract base attribute for filtering message-based updates.
|
||||||
|
/// Supports various message types including regular messages, edited messages, channel posts, and business messages.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filters">The filters to apply to messages</param>
|
||||||
|
public abstract class MessageFilterAttribute(params IFilter<Message>[] filters) : UpdateFilterAttribute<Message>(filters)
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstract base attribute for filtering message-based updates.
|
/// Gets the allowed update types that this filter can process.
|
||||||
/// Supports various message types including regular messages, edited messages, channel posts, and business messages.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filters">The filters to apply to messages</param>
|
public override UpdateType[] AllowedTypes =>
|
||||||
public abstract class MessageFilterAttribute(params IFilter<Message>[] filters) : UpdateFilterAttribute<Message>(filters)
|
[
|
||||||
{
|
UpdateType.Message,
|
||||||
/// <summary>
|
UpdateType.EditedMessage,
|
||||||
/// Gets the allowed update types that this filter can process.
|
UpdateType.ChannelPost,
|
||||||
/// </summary>
|
UpdateType.EditedChannelPost,
|
||||||
public override UpdateType[] AllowedTypes =>
|
UpdateType.BusinessMessage,
|
||||||
[
|
UpdateType.EditedBusinessMessage
|
||||||
UpdateType.Message,
|
];
|
||||||
UpdateType.EditedMessage,
|
|
||||||
UpdateType.ChannelPost,
|
|
||||||
UpdateType.EditedChannelPost,
|
|
||||||
UpdateType.BusinessMessage,
|
|
||||||
UpdateType.EditedBusinessMessage
|
|
||||||
];
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Extracts the message from various types of updates.
|
/// Extracts the message from various types of updates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="update">The Telegram update</param>
|
/// <param name="update">The Telegram update</param>
|
||||||
/// <returns>The message from the update, or null if not present</returns>
|
/// <returns>The message from the update, or null if not present</returns>
|
||||||
public override Message? GetFilterringTarget(Update update)
|
public override Message? GetFilterringTarget(Update update)
|
||||||
|
{
|
||||||
|
return update switch
|
||||||
{
|
{
|
||||||
return update switch
|
{ Message: { } message } => message,
|
||||||
{
|
{ EditedMessage: { } message } => message,
|
||||||
{ Message: { } message } => message,
|
{ ChannelPost: { } message } => message,
|
||||||
{ EditedMessage: { } message } => message,
|
{ EditedChannelPost: { } message } => message,
|
||||||
{ ChannelPost: { } message } => message,
|
{ BusinessMessage: { } message } => message,
|
||||||
{ EditedChannelPost: { } message } => message,
|
{ EditedBusinessMessage: { } message } => message,
|
||||||
{ BusinessMessage: { } message } => message,
|
_ => null
|
||||||
{ EditedBusinessMessage: { } message } => message,
|
};
|
||||||
_ => null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute for filtering messages based on regular expression patterns.
|
|
||||||
/// </summary>
|
|
||||||
public class MessageRegexAttribute : MessageFilterAttribute
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the attribute with a regex pattern and options.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pattern">The regular expression pattern to match</param>
|
|
||||||
/// <param name="regexOptions">The regex options for matching</param>
|
|
||||||
public MessageRegexAttribute(string pattern, RegexOptions regexOptions = default)
|
|
||||||
: base(new MessageRegexFilter(pattern, regexOptions)) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the attribute with a precompiled regex.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="regex">The precompiled regular expression</param>
|
|
||||||
public MessageRegexAttribute(Regex regex)
|
|
||||||
: base(new MessageRegexFilter(regex)) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute for filtering messages that contain dice throws with specific values.
|
|
||||||
/// </summary>
|
|
||||||
public class DiceThrowedAttribute : MessageFilterAttribute
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the attribute to filter dice throws with a specific value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The dice value to match</param>
|
|
||||||
public DiceThrowedAttribute(int value)
|
|
||||||
: base(new DiceThrowedFilter(value)) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the attribute to filter dice throws with a specific type and value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="diceType">The type of dice</param>
|
|
||||||
/// <param name="value">The dice value to match</param>
|
|
||||||
public DiceThrowedAttribute(DiceType diceType, int value)
|
|
||||||
: base(new DiceThrowedFilter(diceType, value)) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute for filtering messages that are automatically forwarded.
|
|
||||||
/// </summary>
|
|
||||||
public class IsAutomaticFormwardMessageAttribute()
|
|
||||||
: MessageFilterAttribute(new IsAutomaticFormwardMessageFilter())
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute for filtering messages sent while the user was offline.
|
|
||||||
/// </summary>
|
|
||||||
public class IsFromOfflineMessageAttribute()
|
|
||||||
: MessageFilterAttribute(new IsFromOfflineMessageFilter())
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute for filtering service messages (e.g., user joined, left, etc.).
|
|
||||||
/// </summary>
|
|
||||||
public class IsServiceMessageMessageAttribute()
|
|
||||||
: MessageFilterAttribute(new IsServiceMessageMessageFilter())
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute for filtering topic messages in forum chats.
|
|
||||||
/// </summary>
|
|
||||||
public class IsTopicMessageMessageAttribute()
|
|
||||||
: MessageFilterAttribute(new IsServiceMessageMessageFilter())
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute for filtering messages based on their entities (mentions, links, etc.).
|
|
||||||
/// </summary>
|
|
||||||
public class MessageHasEntityAttribute : MessageFilterAttribute
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the attribute to filter messages with a specific entity type.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The entity type to match</param>
|
|
||||||
public MessageHasEntityAttribute(MessageEntityType type)
|
|
||||||
: base(new MessageHasEntityFilter(type)) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the attribute to filter messages with a specific entity type at a specific position.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The entity type to match</param>
|
|
||||||
/// <param name="offset">The starting position of the entity</param>
|
|
||||||
/// <param name="length">The length of the entity (optional)</param>
|
|
||||||
public MessageHasEntityAttribute(MessageEntityType type, int offset, int? length)
|
|
||||||
: base(new MessageHasEntityFilter(type, offset, length)) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the attribute to filter messages with a specific entity type and content.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The entity type to match</param>
|
|
||||||
/// <param name="content">The content that the entity should contain</param>
|
|
||||||
/// <param name="stringComparison">The string comparison method</param>
|
|
||||||
public MessageHasEntityAttribute(MessageEntityType type, string content, StringComparison stringComparison = StringComparison.CurrentCulture)
|
|
||||||
: base(new MessageHasEntityFilter(type, content, stringComparison)) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the attribute to filter messages with a specific entity type, position, and content.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The entity type to match</param>
|
|
||||||
/// <param name="offset">The starting position of the entity</param>
|
|
||||||
/// <param name="length">The length of the entity (optional)</param>
|
|
||||||
/// <param name="content">The content that the entity should contain</param>
|
|
||||||
/// <param name="stringComparison">The string comparison method</param>
|
|
||||||
public MessageHasEntityAttribute(MessageEntityType type, int offset, int? length, string content, StringComparison stringComparison = StringComparison.CurrentCulture)
|
|
||||||
: base(new MessageHasEntityFilter(type, offset, length, content, stringComparison)) { }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering messages based on regular expression patterns.
|
||||||
|
/// </summary>
|
||||||
|
public class MessageRegexAttribute : MessageFilterAttribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the attribute with a regex pattern and options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pattern">The regular expression pattern to match</param>
|
||||||
|
/// <param name="regexOptions">The regex options for matching</param>
|
||||||
|
public MessageRegexAttribute(string pattern, RegexOptions regexOptions = default)
|
||||||
|
: base(new MessageRegexFilter(pattern, regexOptions)) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the attribute with a precompiled regex.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="regex">The precompiled regular expression</param>
|
||||||
|
public MessageRegexAttribute(Regex regex)
|
||||||
|
: base(new MessageRegexFilter(regex)) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering messages that contain dice throws with specific values.
|
||||||
|
/// </summary>
|
||||||
|
public class DiceThrowedAttribute : MessageFilterAttribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the attribute to filter dice throws with a specific value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The dice value to match</param>
|
||||||
|
public DiceThrowedAttribute(int value)
|
||||||
|
: base(new DiceThrowedFilter(value)) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the attribute to filter dice throws with a specific type and value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="diceType">The type of dice</param>
|
||||||
|
/// <param name="value">The dice value to match</param>
|
||||||
|
public DiceThrowedAttribute(DiceType diceType, int value)
|
||||||
|
: base(new DiceThrowedFilter(diceType, value)) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering messages that are automatically forwarded.
|
||||||
|
/// </summary>
|
||||||
|
public class IsAutomaticFormwardMessageAttribute()
|
||||||
|
: MessageFilterAttribute(new IsAutomaticFormwardMessageFilter())
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering messages sent while the user was offline.
|
||||||
|
/// </summary>
|
||||||
|
public class IsFromOfflineMessageAttribute()
|
||||||
|
: MessageFilterAttribute(new IsFromOfflineMessageFilter())
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering service messages (e.g., user joined, left, etc.).
|
||||||
|
/// </summary>
|
||||||
|
public class IsServiceMessageMessageAttribute()
|
||||||
|
: MessageFilterAttribute(new IsServiceMessageMessageFilter())
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering topic messages in forum chats.
|
||||||
|
/// </summary>
|
||||||
|
public class IsTopicMessageMessageAttribute()
|
||||||
|
: MessageFilterAttribute(new IsServiceMessageMessageFilter())
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering messages based on their entities (mentions, links, etc.).
|
||||||
|
/// </summary>
|
||||||
|
public class MessageHasEntityAttribute : MessageFilterAttribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the attribute to filter messages with a specific entity type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The entity type to match</param>
|
||||||
|
public MessageHasEntityAttribute(MessageEntityType type)
|
||||||
|
: base(new MessageHasEntityFilter(type)) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the attribute to filter messages with a specific entity type at a specific position.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The entity type to match</param>
|
||||||
|
/// <param name="offset">The starting position of the entity</param>
|
||||||
|
/// <param name="length">The length of the entity (optional)</param>
|
||||||
|
public MessageHasEntityAttribute(MessageEntityType type, int offset, int? length)
|
||||||
|
: base(new MessageHasEntityFilter(type, offset, length)) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the attribute to filter messages with a specific entity type and content.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The entity type to match</param>
|
||||||
|
/// <param name="content">The content that the entity should contain</param>
|
||||||
|
/// <param name="stringComparison">The string comparison method</param>
|
||||||
|
public MessageHasEntityAttribute(MessageEntityType type, string content, StringComparison stringComparison = StringComparison.CurrentCulture)
|
||||||
|
: base(new MessageHasEntityFilter(type, content, stringComparison)) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the attribute to filter messages with a specific entity type, position, and content.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The entity type to match</param>
|
||||||
|
/// <param name="offset">The starting position of the entity</param>
|
||||||
|
/// <param name="length">The length of the entity (optional)</param>
|
||||||
|
/// <param name="content">The content that the entity should contain</param>
|
||||||
|
/// <param name="stringComparison">The string comparison method</param>
|
||||||
|
public MessageHasEntityAttribute(MessageEntityType type, int offset, int? length, string content, StringComparison stringComparison = StringComparison.CurrentCulture)
|
||||||
|
: base(new MessageHasEntityFilter(type, offset, length, content, stringComparison)) { }
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,27 +1,26 @@
|
|||||||
using Telegrator.Filters;
|
using Telegrator.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Annotations
|
namespace Telegrator.Annotations;
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute for filtering messages with reply to messages of this bot.
|
|
||||||
/// </summary>
|
|
||||||
public class MeRepliedAttribute()
|
|
||||||
: MessageFilterAttribute(new MeRepliedFilter())
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for checking message's reply chain.
|
/// Attribute for filtering messages with reply to messages of this bot.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class HasReplyAttribute(int replyDepth = 1)
|
public class MeRepliedAttribute()
|
||||||
: MessageFilterAttribute(new MessageHasReplyFilter(replyDepth))
|
: MessageFilterAttribute(new MeRepliedFilter())
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Helper filter class for filters that operate on replied messages.
|
/// Attribute for checking message's reply chain.
|
||||||
/// Provides functionality to traverse reply chains and access replied message content.
|
/// </summary>
|
||||||
/// </summary>
|
public class HasReplyAttribute(int replyDepth = 1)
|
||||||
/// <param name="replyDepth"></param>
|
: MessageFilterAttribute(new MessageHasReplyFilter(replyDepth))
|
||||||
public class FromReplyChainAttribute(int replyDepth = 1)
|
{ }
|
||||||
: MessageFilterAttribute(new FromReplyChainFilter(replyDepth))
|
|
||||||
{ }
|
/// <summary>
|
||||||
}
|
/// Helper filter class for filters that operate on replied messages.
|
||||||
|
/// Provides functionality to traverse reply chains and access replied message content.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="replyDepth"></param>
|
||||||
|
public class FromReplyChainAttribute(int replyDepth = 1)
|
||||||
|
: MessageFilterAttribute(new FromReplyChainFilter(replyDepth))
|
||||||
|
{ }
|
||||||
|
|||||||
@@ -1,92 +1,91 @@
|
|||||||
using Telegrator.Filters;
|
using Telegrator.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Annotations
|
namespace Telegrator.Annotations;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering messages based on the sender's username.
|
||||||
|
/// </summary>
|
||||||
|
public class FromUsernameAttribute : MessageFilterAttribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering messages based on the sender's username.
|
/// Initializes the attribute to filter messages from a specific username.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FromUsernameAttribute : MessageFilterAttribute
|
/// <param name="username">The username to match</param>
|
||||||
{
|
public FromUsernameAttribute(string username)
|
||||||
/// <summary>
|
: base(new FromUsernameFilter(username)) { }
|
||||||
/// Initializes the attribute to filter messages from a specific username.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="username">The username to match</param>
|
|
||||||
public FromUsernameAttribute(string username)
|
|
||||||
: base(new FromUsernameFilter(username)) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the attribute to filter messages from a specific username with custom comparison.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="username">The username to match</param>
|
|
||||||
/// <param name="comparison">The string comparison method</param>
|
|
||||||
public FromUsernameAttribute(string username, StringComparison comparison)
|
|
||||||
: base(new FromUsernameFilter(username, comparison)) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering messages based on the sender's name (first name and optionally last name).
|
/// Initializes the attribute to filter messages from a specific username with custom comparison.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FromUserAttribute : MessageFilterAttribute
|
/// <param name="username">The username to match</param>
|
||||||
{
|
/// <param name="comparison">The string comparison method</param>
|
||||||
/// <summary>
|
public FromUsernameAttribute(string username, StringComparison comparison)
|
||||||
/// Initializes the attribute to filter messages from a user with specific first and last names.
|
: base(new FromUsernameFilter(username, comparison)) { }
|
||||||
/// </summary>
|
|
||||||
/// <param name="firstName">The first name to match</param>
|
|
||||||
/// <param name="lastName">The last name to match (optional)</param>
|
|
||||||
/// <param name="comparison">The string comparison method</param>
|
|
||||||
public FromUserAttribute(string firstName, string? lastName, StringComparison comparison)
|
|
||||||
: base(new FromUserFilter(firstName, lastName, comparison)) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the attribute to filter messages from a user with specific first and last names.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="firstName">The first name to match</param>
|
|
||||||
/// <param name="lastName">The last name to match</param>
|
|
||||||
public FromUserAttribute(string firstName, string? lastName)
|
|
||||||
: base(new FromUserFilter(firstName, lastName, StringComparison.InvariantCulture)) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the attribute to filter messages from a user with a specific first name.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="firstName">The first name to match</param>
|
|
||||||
public FromUserAttribute(string firstName)
|
|
||||||
: base(new FromUserFilter(firstName, null, StringComparison.InvariantCulture)) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the attribute to filter messages from a user with a specific first name and custom comparison.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="firstName">The first name to match</param>
|
|
||||||
/// <param name="comparison">The string comparison method</param>
|
|
||||||
public FromUserAttribute(string firstName, StringComparison comparison)
|
|
||||||
: base(new FromUserFilter(firstName, null, comparison)) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute for filtering messages from a specific user ID.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="userId">The user ID to match</param>
|
|
||||||
public class FromUserIdAttribute(long userId)
|
|
||||||
: MessageFilterAttribute(new FromUserIdFilter(userId))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute for filtering messages sent by not bots (users).
|
|
||||||
/// </summary>
|
|
||||||
public class NotFromBotAttribute()
|
|
||||||
: MessageFilterAttribute(new FromBotFilter().Not())
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute for filtering messages sent by bots.
|
|
||||||
/// </summary>
|
|
||||||
public class FromBotAttribute()
|
|
||||||
: MessageFilterAttribute(new FromBotFilter())
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute for filtering messages sent by premium users.
|
|
||||||
/// </summary>
|
|
||||||
public class FromPremiumUserAttribute()
|
|
||||||
: MessageFilterAttribute(new FromPremiumUserFilter())
|
|
||||||
{ }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering messages based on the sender's name (first name and optionally last name).
|
||||||
|
/// </summary>
|
||||||
|
public class FromUserAttribute : MessageFilterAttribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the attribute to filter messages from a user with specific first and last names.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstName">The first name to match</param>
|
||||||
|
/// <param name="lastName">The last name to match (optional)</param>
|
||||||
|
/// <param name="comparison">The string comparison method</param>
|
||||||
|
public FromUserAttribute(string firstName, string? lastName, StringComparison comparison)
|
||||||
|
: base(new FromUserFilter(firstName, lastName, comparison)) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the attribute to filter messages from a user with specific first and last names.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstName">The first name to match</param>
|
||||||
|
/// <param name="lastName">The last name to match</param>
|
||||||
|
public FromUserAttribute(string firstName, string? lastName)
|
||||||
|
: base(new FromUserFilter(firstName, lastName, StringComparison.InvariantCulture)) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the attribute to filter messages from a user with a specific first name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstName">The first name to match</param>
|
||||||
|
public FromUserAttribute(string firstName)
|
||||||
|
: base(new FromUserFilter(firstName, null, StringComparison.InvariantCulture)) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the attribute to filter messages from a user with a specific first name and custom comparison.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstName">The first name to match</param>
|
||||||
|
/// <param name="comparison">The string comparison method</param>
|
||||||
|
public FromUserAttribute(string firstName, StringComparison comparison)
|
||||||
|
: base(new FromUserFilter(firstName, null, comparison)) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering messages from a specific user ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId">The user ID to match</param>
|
||||||
|
public class FromUserIdAttribute(long userId)
|
||||||
|
: MessageFilterAttribute(new FromUserIdFilter(userId))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering messages sent by not bots (users).
|
||||||
|
/// </summary>
|
||||||
|
public class NotFromBotAttribute()
|
||||||
|
: MessageFilterAttribute(new FromBotFilter().Not())
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering messages sent by bots.
|
||||||
|
/// </summary>
|
||||||
|
public class FromBotAttribute()
|
||||||
|
: MessageFilterAttribute(new FromBotFilter())
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering messages sent by premium users.
|
||||||
|
/// </summary>
|
||||||
|
public class FromPremiumUserAttribute()
|
||||||
|
: MessageFilterAttribute(new FromPremiumUserFilter())
|
||||||
|
{ }
|
||||||
|
|||||||
@@ -1,58 +1,57 @@
|
|||||||
using Telegrator.Filters;
|
using Telegrator.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Annotations
|
namespace Telegrator.Annotations;
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute for filtering messages where the text starts with the specified content.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="content">The string that the message text should start with</param>
|
|
||||||
/// <param name="comparison">The string comparison type</param>
|
|
||||||
public class TextStartsWithAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture)
|
|
||||||
: MessageFilterAttribute(new TextStartsWithFilter(content, comparison))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering messages where the text ends with the specified content.
|
/// Attribute for filtering messages where the text starts with the specified content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="content">The string that the message text should end with</param>
|
/// <param name="content">The string that the message text should start with</param>
|
||||||
/// <param name="comparison">The string comparison type</param>
|
/// <param name="comparison">The string comparison type</param>
|
||||||
public class TextEndsWithAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture)
|
public class TextStartsWithAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture)
|
||||||
: MessageFilterAttribute(new TextEndsWithFilter(content, comparison))
|
: MessageFilterAttribute(new TextStartsWithFilter(content, comparison))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering messages where the text contains the specified content.
|
/// Attribute for filtering messages where the text ends with the specified content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="content">The string that the message text should contain</param>
|
/// <param name="content">The string that the message text should end with</param>
|
||||||
/// <param name="comparison">The string comparison type</param>
|
/// <param name="comparison">The string comparison type</param>
|
||||||
public class TextContainsAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture)
|
public class TextEndsWithAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture)
|
||||||
: MessageFilterAttribute(new TextContainsFilter(content, comparison))
|
: MessageFilterAttribute(new TextEndsWithFilter(content, comparison))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering messages where the text equals the specified content.
|
/// Attribute for filtering messages where the text contains the specified content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="content">The string that the message text should equal</param>
|
/// <param name="content">The string that the message text should contain</param>
|
||||||
/// <param name="comparison">The string comparison type</param>
|
/// <param name="comparison">The string comparison type</param>
|
||||||
public class TextEqualsAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture)
|
public class TextContainsAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture)
|
||||||
: MessageFilterAttribute(new TextEqualsFilter(content, comparison))
|
: MessageFilterAttribute(new TextContainsFilter(content, comparison))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering messages that contain any non-empty text.
|
/// Attribute for filtering messages where the text equals the specified content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class HasTextAttribute()
|
/// <param name="content">The string that the message text should equal</param>
|
||||||
: MessageFilterAttribute(new TextNotNullOrEmptyFilter())
|
/// <param name="comparison">The string comparison type</param>
|
||||||
{ }
|
public class TextEqualsAttribute(string content, StringComparison comparison = StringComparison.InvariantCulture)
|
||||||
|
: MessageFilterAttribute(new TextEqualsFilter(content, comparison))
|
||||||
|
{ }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering messages where the text contains a 'word'.
|
/// Attribute for filtering messages that contain any non-empty text.
|
||||||
/// 'Word' must be a separate member of the text, and not have any alphabetic characters next to it.
|
/// </summary>
|
||||||
/// </summary>
|
public class HasTextAttribute()
|
||||||
/// <param name="word"></param>
|
: MessageFilterAttribute(new TextNotNullOrEmptyFilter())
|
||||||
/// <param name="comparison"></param>
|
{ }
|
||||||
/// <param name="startIndex"></param>
|
|
||||||
public class TextContainsWordAttribute(string word, StringComparison comparison = StringComparison.InvariantCulture, int startIndex = 0)
|
/// <summary>
|
||||||
: MessageFilterAttribute(new TextContainsWordFilter(word, comparison, startIndex))
|
/// Attribute for filtering messages where the text contains a 'word'.
|
||||||
{ }
|
/// 'Word' must be a separate member of the text, and not have any alphabetic characters next to it.
|
||||||
}
|
/// </summary>
|
||||||
|
/// <param name="word"></param>
|
||||||
|
/// <param name="comparison"></param>
|
||||||
|
/// <param name="startIndex"></param>
|
||||||
|
public class TextContainsWordAttribute(string word, StringComparison comparison = StringComparison.InvariantCulture, int startIndex = 0)
|
||||||
|
: MessageFilterAttribute(new TextContainsWordFilter(word, comparison, startIndex))
|
||||||
|
{ }
|
||||||
|
|||||||
@@ -1,27 +1,26 @@
|
|||||||
using Telegram.Bot.Types.Enums;
|
using Telegram.Bot.Types.Enums;
|
||||||
|
|
||||||
namespace Telegrator.Annotations
|
namespace Telegrator.Annotations;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute that says if this handler can await some of await types, that is not listed by its handler base.
|
||||||
|
/// Used for automatic collecting allowed to receiving <see cref="UpdateType"/>'s.
|
||||||
|
/// If you don't use it, you won't be able to await the updates inside handler.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||||
|
public class MightAwaitAttribute : Attribute
|
||||||
{
|
{
|
||||||
|
private readonly UpdateType[] _updateTypes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute that says if this handler can await some of await types, that is not listed by its handler base.
|
/// Update types that may be awaited
|
||||||
/// Used for automatic collecting allowed to receiving <see cref="UpdateType"/>'s.
|
|
||||||
/// If you don't use it, you won't be able to await the updates inside handler.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
public UpdateType[] UpdateTypes => _updateTypes;
|
||||||
public class MightAwaitAttribute : Attribute
|
|
||||||
{
|
|
||||||
private readonly UpdateType[] _updateTypes;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update types that may be awaited
|
/// main ctor of <see cref="MightAwaitAttribute"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public UpdateType[] UpdateTypes => _updateTypes;
|
/// <param name="updateTypes"></param>
|
||||||
|
public MightAwaitAttribute(params UpdateType[] updateTypes)
|
||||||
/// <summary>
|
=> _updateTypes = updateTypes;
|
||||||
/// main ctor of <see cref="MightAwaitAttribute"/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="updateTypes"></param>
|
|
||||||
public MightAwaitAttribute(params UpdateType[] updateTypes)
|
|
||||||
=> _updateTypes = updateTypes;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,22 +2,21 @@
|
|||||||
using Telegram.Bot.Types.Enums;
|
using Telegram.Bot.Types.Enums;
|
||||||
using Telegrator.Filters;
|
using Telegrator.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Annotations
|
namespace Telegrator.Annotations;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for filtering message with command "start" in bot's private chats.
|
||||||
|
/// Allows handlers to respond to "welcome" bot commands.
|
||||||
|
/// </summary>
|
||||||
|
public class WelcomeAttribute : MessageFilterAttribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for filtering message with command "start" in bot's private chats.
|
/// Creates new instance of <see cref="WelcomeAttribute"/>
|
||||||
/// Allows handlers to respond to "welcome" bot commands.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WelcomeAttribute : MessageFilterAttribute
|
/// <param name="onlyFirst"></param>
|
||||||
{
|
public WelcomeAttribute(bool onlyFirst = false) : base(
|
||||||
/// <summary>
|
new MessageChatTypeFilter(ChatType.Private),
|
||||||
/// Creates new instance of <see cref="WelcomeAttribute"/>
|
new CommandAlliasFilter("start"),
|
||||||
/// </summary>
|
Filter<Message>.If(ctx => !onlyFirst || ctx.Input.Id == 0))
|
||||||
/// <param name="onlyFirst"></param>
|
{ }
|
||||||
public WelcomeAttribute(bool onlyFirst = false) : base(
|
|
||||||
new MessageChatTypeFilter(ChatType.Private),
|
|
||||||
new CommandAlliasFilter("start"),
|
|
||||||
Filter<Message>.If(ctx => !onlyFirst || ctx.Input.Id == 0))
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
namespace Telegrator.Aspects
|
namespace Telegrator.Aspects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute that specifies a post-execution processor to be executed after the handler.
|
||||||
|
/// The processor type must implement <see cref="IPostProcessor"/> interface.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the post-processor that implements <see cref="IPostProcessor"/>.</typeparam>
|
||||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||||
|
public class AfterExecutionAttribute<T> : Attribute where T : IPostProcessor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute that specifies a post-execution processor to be executed after the handler.
|
/// Gets the type of the post-processor.
|
||||||
/// The processor type must implement <see cref="IPostProcessor"/> interface.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the post-processor that implements <see cref="IPostProcessor"/>.</typeparam>
|
public Type ProcessorType => typeof(T);
|
||||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
|
||||||
public class AfterExecutionAttribute<T> : Attribute where T : IPostProcessor
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the type of the post-processor.
|
|
||||||
/// </summary>
|
|
||||||
public Type ProcessorType => typeof(T);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
namespace Telegrator.Aspects
|
namespace Telegrator.Aspects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute that specifies a pre-execution processor to be executed before the handler.
|
||||||
|
/// The processor type must implement <see cref="IPreProcessor"/> interface.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the pre-processor that implements <see cref="IPreProcessor"/>.</typeparam>
|
||||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||||
|
public class BeforeExecutionAttribute<T> : Attribute where T : IPreProcessor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute that specifies a pre-execution processor to be executed before the handler.
|
/// Gets the type of the pre-processor.
|
||||||
/// The processor type must implement <see cref="IPreProcessor"/> interface.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the pre-processor that implements <see cref="IPreProcessor"/>.</typeparam>
|
public Type ProcessorType => typeof(T);
|
||||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
|
||||||
public class BeforeExecutionAttribute<T> : Attribute where T : IPreProcessor
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the type of the pre-processor.
|
|
||||||
/// </summary>
|
|
||||||
public Type ProcessorType => typeof(T);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
using Telegrator.Core.Handlers;
|
using Telegrator.Core.Handlers;
|
||||||
|
|
||||||
namespace Telegrator.Aspects
|
namespace Telegrator.Aspects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for post-execution processors that are executed after handler execution.
|
||||||
|
/// Implement this interface to add cross-cutting concerns like logging, cleanup, or metrics collection.
|
||||||
|
/// </summary>
|
||||||
|
public interface IPostProcessor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interface for post-execution processors that are executed after handler execution.
|
/// Executes after the handler's main execution logic.
|
||||||
/// Implement this interface to add cross-cutting concerns like logging, cleanup, or metrics collection.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IPostProcessor
|
/// <param name="container">The handler container containing the current update and context.</param>
|
||||||
{
|
/// <param name="cancellationToken"></param>
|
||||||
/// <summary>
|
/// <returns>A <see cref="Result"/> indicating the final execution result.</returns>
|
||||||
/// Executes after the handler's main execution logic.
|
public Task<Result> AfterExecution(IHandlerContainer container, CancellationToken cancellationToken);
|
||||||
/// </summary>
|
|
||||||
/// <param name="container">The handler container containing the current update and context.</param>
|
|
||||||
/// <param name="cancellationToken"></param>
|
|
||||||
/// <returns>A <see cref="Result"/> indicating the final execution result.</returns>
|
|
||||||
public Task<Result> AfterExecution(IHandlerContainer container, CancellationToken cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
using Telegrator.Core.Handlers;
|
using Telegrator.Core.Handlers;
|
||||||
|
|
||||||
namespace Telegrator.Aspects
|
namespace Telegrator.Aspects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for pre-execution processors that are executed before handler execution.
|
||||||
|
/// Implement this interface to add cross-cutting concerns like validation, logging, or authorization.
|
||||||
|
/// </summary>
|
||||||
|
public interface IPreProcessor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interface for pre-execution processors that are executed before handler execution.
|
/// Executes before the handler's main execution logic.
|
||||||
/// Implement this interface to add cross-cutting concerns like validation, logging, or authorization.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IPreProcessor
|
/// <param name="container">The handler container containing the current update and context.</param>
|
||||||
{
|
/// <param name="cancellationToken"></param>
|
||||||
/// <summary>
|
/// <returns>A <see cref="Result"/> indicating whether execution should continue or be stopped.</returns>
|
||||||
/// Executes before the handler's main execution logic.
|
public Task<Result> BeforeExecution(IHandlerContainer container, CancellationToken cancellationToken = default);
|
||||||
/// </summary>
|
|
||||||
/// <param name="container">The handler container containing the current update and context.</param>
|
|
||||||
/// <param name="cancellationToken"></param>
|
|
||||||
/// <returns>A <see cref="Result"/> indicating whether execution should continue or be stopped.</returns>
|
|
||||||
public Task<Result> BeforeExecution(IHandlerContainer container, CancellationToken cancellationToken = default);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,37 +3,36 @@ using Telegram.Bot.Types.Enums;
|
|||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
using Telegrator.Filters;
|
using Telegrator.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Attributes
|
namespace Telegrator.Attributes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reactive way to implement a new <see cref="UpdateFilterAttribute{T}"/> of type <typeparamref name="T"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
public abstract class FilterAnnotation<T> : UpdateFilterAttribute<T>, IFilter<T>, INamedFilter where T : class
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public virtual bool IsCollectible { get; } = false;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override UpdateType[] AllowedTypes { get; } = typeof(T).GetAllowedUpdateTypes();
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public string Name => GetType().Name;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reactive way to implement a new <see cref="UpdateFilterAttribute{T}"/> of type <typeparamref name="T"/>
|
/// Initializes new instance of <see cref="FilterAnnotation{T}"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
public FilterAnnotation() : base()
|
||||||
public abstract class FilterAnnotation<T> : UpdateFilterAttribute<T>, IFilter<T>, INamedFilter where T : class
|
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
UpdateFilter = Filter<T>.If(CanPass);
|
||||||
public virtual bool IsCollectible { get; } = false;
|
AnonymousFilter = AnonymousTypeFilter.Compile(UpdateFilter, GetFilterringTarget);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override UpdateType[] AllowedTypes { get; } = typeof(T).GetAllowedUpdateTypes();
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public string Name => GetType().Name;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes new instance of <see cref="FilterAnnotation{T}"/>
|
|
||||||
/// </summary>
|
|
||||||
public FilterAnnotation() : base()
|
|
||||||
{
|
|
||||||
UpdateFilter = Filter<T>.If(CanPass);
|
|
||||||
AnonymousFilter = AnonymousTypeFilter.Compile(UpdateFilter, GetFilterringTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override T? GetFilterringTarget(Update update)
|
|
||||||
=> update.GetActualUpdateObject<T>();
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public abstract bool CanPass(FilterExecutionContext<T> context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override T? GetFilterringTarget(Update update)
|
||||||
|
=> update.GetActualUpdateObject<T>();
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public abstract bool CanPass(FilterExecutionContext<T> context);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,24 @@
|
|||||||
namespace Telegrator.Attributes
|
namespace Telegrator.Attributes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enumeration of filter modifiers that can be applied to update filters.
|
||||||
|
/// Defines how filters should be combined and applied in filter chains.
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum FilterModifier
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enumeration of filter modifiers that can be applied to update filters.
|
/// No modifier applied. Filter is applied as-is.
|
||||||
/// Defines how filters should be combined and applied in filter chains.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Flags]
|
None = 1,
|
||||||
public enum FilterModifier
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// No modifier applied. Filter is applied as-is.
|
|
||||||
/// </summary>
|
|
||||||
None = 1,
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// OR modifier. This filter or the next filter in the chain should match.
|
/// OR modifier. This filter or the next filter in the chain should match.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
OrNext = 2,
|
OrNext = 2,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// NOT modifier. The inverse of this filter should match.
|
/// NOT modifier. The inverse of this filter should match.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Not = 4,
|
Not = 4,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,83 +3,82 @@ using Telegrator.Core.Attributes;
|
|||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
using Telegrator.Filters;
|
using Telegrator.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Attributes
|
namespace Telegrator.Attributes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract base attribute for defining update filters for a specific type of update target.
|
||||||
|
/// Provides logic for filter composition, modifier processing, and target extraction.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the update target to filter (e.g., Message, Update).</typeparam>
|
||||||
|
public abstract class UpdateFilterAttribute<T> : UpdateFilterAttributeBase where T : class
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstract base attribute for defining update filters for a specific type of update target.
|
/// Gets the compiled anonymous filter for this attribute.
|
||||||
/// Provides logic for filter composition, modifier processing, and target extraction.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the update target to filter (e.g., Message, Update).</typeparam>
|
public override IFilter<Update> AnonymousFilter { get; protected set; }
|
||||||
public abstract class UpdateFilterAttribute<T> : UpdateFilterAttributeBase where T : class
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the compiled filter logic for the update target.
|
||||||
|
/// </summary>
|
||||||
|
public IFilter<T> UpdateFilter { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Empty constructor for internal using
|
||||||
|
/// </summary>
|
||||||
|
internal UpdateFilterAttribute()
|
||||||
{
|
{
|
||||||
/// <summary>
|
AnonymousFilter = null!;
|
||||||
/// Gets the compiled anonymous filter for this attribute.
|
UpdateFilter = null!;
|
||||||
/// </summary>
|
_ = 0xBAD + 0xC0DE;
|
||||||
public override IFilter<Update> AnonymousFilter { get; protected set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the compiled filter logic for the update target.
|
|
||||||
/// </summary>
|
|
||||||
public IFilter<T> UpdateFilter { get; protected set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Empty constructor for internal using
|
|
||||||
/// </summary>
|
|
||||||
internal UpdateFilterAttribute()
|
|
||||||
{
|
|
||||||
AnonymousFilter = null!;
|
|
||||||
UpdateFilter = null!;
|
|
||||||
_ = 0xBAD + 0xC0DE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the attribute with one or more filters for the update target.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filters">The filters to compose</param>
|
|
||||||
protected UpdateFilterAttribute(params IFilter<T>[] filters)
|
|
||||||
{
|
|
||||||
string name = GetType().Name;
|
|
||||||
UpdateFilter = new CompiledFilter<T>(name, filters);
|
|
||||||
AnonymousFilter = AnonymousTypeFilter.Compile(name, UpdateFilter, GetFilterringTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the attribute with a precompiled filter for the update target.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="updateFilter">The compiled filter</param>
|
|
||||||
protected UpdateFilterAttribute(IFilter<T> updateFilter)
|
|
||||||
{
|
|
||||||
string name = GetType().Name;
|
|
||||||
UpdateFilter = updateFilter;
|
|
||||||
AnonymousFilter = AnonymousTypeFilter.Compile(name, UpdateFilter, GetFilterringTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Processes filter modifiers and combines this filter with the previous one if needed.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="previous">The previous filter attribute in the chain</param>
|
|
||||||
/// <returns>True if the OrNext modifier is set; otherwise, false.</returns>
|
|
||||||
public override sealed bool ProcessModifiers(UpdateFilterAttributeBase? previous)
|
|
||||||
{
|
|
||||||
if (Modifiers.HasFlag(FilterModifier.Not))
|
|
||||||
AnonymousFilter = Filter<T>.Not(AnonymousFilter);
|
|
||||||
|
|
||||||
if (previous is not null)
|
|
||||||
{
|
|
||||||
if (previous.Modifiers.HasFlag(FilterModifier.OrNext))
|
|
||||||
{
|
|
||||||
AnonymousFilter = Filter<Update>.Or(previous.AnonymousFilter, AnonymousFilter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Modifiers.HasFlag(FilterModifier.OrNext);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Extracts the filtering target of type <typeparamref name="T"/> from the given update.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="update">The Telegram update</param>
|
|
||||||
/// <returns>The target object to filter, or null if not applicable</returns>
|
|
||||||
public abstract T? GetFilterringTarget(Update update);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the attribute with one or more filters for the update target.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filters">The filters to compose</param>
|
||||||
|
protected UpdateFilterAttribute(params IFilter<T>[] filters)
|
||||||
|
{
|
||||||
|
string name = GetType().Name;
|
||||||
|
UpdateFilter = new CompiledFilter<T>(name, filters);
|
||||||
|
AnonymousFilter = AnonymousTypeFilter.Compile(name, UpdateFilter, GetFilterringTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the attribute with a precompiled filter for the update target.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="updateFilter">The compiled filter</param>
|
||||||
|
protected UpdateFilterAttribute(IFilter<T> updateFilter)
|
||||||
|
{
|
||||||
|
string name = GetType().Name;
|
||||||
|
UpdateFilter = updateFilter;
|
||||||
|
AnonymousFilter = AnonymousTypeFilter.Compile(name, UpdateFilter, GetFilterringTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processes filter modifiers and combines this filter with the previous one if needed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="previous">The previous filter attribute in the chain</param>
|
||||||
|
/// <returns>True if the OrNext modifier is set; otherwise, false.</returns>
|
||||||
|
public override sealed bool ProcessModifiers(UpdateFilterAttributeBase? previous)
|
||||||
|
{
|
||||||
|
if (Modifiers.HasFlag(FilterModifier.Not))
|
||||||
|
AnonymousFilter = Filter<T>.Not(AnonymousFilter);
|
||||||
|
|
||||||
|
if (previous is not null)
|
||||||
|
{
|
||||||
|
if (previous.Modifiers.HasFlag(FilterModifier.OrNext))
|
||||||
|
{
|
||||||
|
AnonymousFilter = Filter<Update>.Or(previous.AnonymousFilter, AnonymousFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Modifiers.HasFlag(FilterModifier.OrNext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extracts the filtering target of type <typeparamref name="T"/> from the given update.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="update">The Telegram update</param>
|
||||||
|
/// <returns>The target object to filter, or null if not applicable</returns>
|
||||||
|
public abstract T? GetFilterringTarget(Update update);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,45 +2,44 @@
|
|||||||
using Telegrator.Core.Attributes;
|
using Telegrator.Core.Attributes;
|
||||||
using Telegrator.Core.Handlers;
|
using Telegrator.Core.Handlers;
|
||||||
|
|
||||||
namespace Telegrator.Attributes
|
namespace Telegrator.Attributes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract base attribute for marking update handler classes.
|
||||||
|
/// Provides a type-safe way to associate handler types with specific update types and importance settings.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the update handler that this attribute is applied to.</typeparam>
|
||||||
|
public abstract class UpdateHandlerAttribute<T> : UpdateHandlerAttributeBase where T : UpdateHandlerBase
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstract base attribute for marking update handler classes.
|
/// Initializes new instance of <see cref="UpdateHandlerAttribute{T}"/>
|
||||||
/// Provides a type-safe way to associate handler types with specific update types and importance settings.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the update handler that this attribute is applied to.</typeparam>
|
/// <param name="updateType">The type of update that this handler can process.</param>
|
||||||
public abstract class UpdateHandlerAttribute<T> : UpdateHandlerAttributeBase where T : UpdateHandlerBase
|
protected UpdateHandlerAttribute(UpdateType updateType)
|
||||||
{
|
: base([typeof(T)], updateType, 0) { }
|
||||||
/// <summary>
|
|
||||||
/// Initializes new instance of <see cref="UpdateHandlerAttribute{T}"/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="updateType">The type of update that this handler can process.</param>
|
|
||||||
protected UpdateHandlerAttribute(UpdateType updateType)
|
|
||||||
: base([typeof(T)], updateType, 0) { }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes new instance of <see cref="UpdateHandlerAttribute{T}"/>
|
/// Initializes new instance of <see cref="UpdateHandlerAttribute{T}"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="updateType">The type of update that this handler can process.</param>
|
/// <param name="updateType">The type of update that this handler can process.</param>
|
||||||
/// <param name="importance">The importance level for this handler</param>
|
/// <param name="importance">The importance level for this handler</param>
|
||||||
protected UpdateHandlerAttribute(UpdateType updateType, int importance)
|
protected UpdateHandlerAttribute(UpdateType updateType, int importance)
|
||||||
: base([typeof(T)], updateType, importance) { }
|
: base([typeof(T)], updateType, importance) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes new instance of <see cref="UpdateHandlerAttribute{T}"/>
|
/// Initializes new instance of <see cref="UpdateHandlerAttribute{T}"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="types">Additional suported types.</param>
|
/// <param name="types">Additional suported types.</param>
|
||||||
/// <param name="updateType">The type of update that this handler can process.</param>
|
/// <param name="updateType">The type of update that this handler can process.</param>
|
||||||
protected UpdateHandlerAttribute(Type[] types, UpdateType updateType)
|
protected UpdateHandlerAttribute(Type[] types, UpdateType updateType)
|
||||||
: base([..types, typeof(T)], updateType, 0) { }
|
: base([..types, typeof(T)], updateType, 0) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes new instance of <see cref="UpdateHandlerAttribute{T}"/>
|
/// Initializes new instance of <see cref="UpdateHandlerAttribute{T}"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="types">Additional suported types.</param>
|
/// <param name="types">Additional suported types.</param>
|
||||||
/// <param name="updateType">The type of update that this handler can process.</param>
|
/// <param name="updateType">The type of update that this handler can process.</param>
|
||||||
/// <param name="importance">The importance level for this handler</param>
|
/// <param name="importance">The importance level for this handler</param>
|
||||||
protected UpdateHandlerAttribute(Type[] types, UpdateType updateType, int importance)
|
protected UpdateHandlerAttribute(Type[] types, UpdateType updateType, int importance)
|
||||||
: base([.. types, typeof(T)], updateType, importance) { }
|
: base([.. types, typeof(T)], updateType, importance) { }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,43 +5,42 @@ using Telegrator.Core.Filters;
|
|||||||
using Telegrator.Core.Handlers;
|
using Telegrator.Core.Handlers;
|
||||||
using Telegrator.Filters;
|
using Telegrator.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Core.Attributes
|
namespace Telegrator.Core.Attributes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="IFilter{T}"/> to <see cref="Update"/> validation for entry into execution of the <see cref="UpdateHandlerBase"/>
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
||||||
|
public abstract class UpdateFilterAttributeBase : Attribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the <see cref="IFilter{T}"/> to <see cref="Update"/> validation for entry into execution of the <see cref="UpdateHandlerBase"/>
|
/// Gets the <see cref="UpdateType"/>'s that <see cref="UpdateHandlerBase"/> processing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
public abstract UpdateType[] AllowedTypes { get; }
|
||||||
public abstract class UpdateFilterAttributeBase : Attribute
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="IFilter{T}"/> that <see cref="UpdateHandlerBase"/> processing
|
||||||
|
/// </summary>
|
||||||
|
public abstract IFilter<Update> AnonymousFilter { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the filter modifiers that affect how this filter is combined with others.
|
||||||
|
/// </summary>
|
||||||
|
public FilterModifier Modifiers { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of <see cref="UpdateHandlerAttributeBase"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="ArgumentException"></exception>
|
||||||
|
protected internal UpdateFilterAttributeBase()
|
||||||
{
|
{
|
||||||
/// <summary>
|
if (AllowedTypes.Length == 0)
|
||||||
/// Gets the <see cref="UpdateType"/>'s that <see cref="UpdateHandlerBase"/> processing
|
throw new ArgumentException();
|
||||||
/// </summary>
|
|
||||||
public abstract UpdateType[] AllowedTypes { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="IFilter{T}"/> that <see cref="UpdateHandlerBase"/> processing
|
|
||||||
/// </summary>
|
|
||||||
public abstract IFilter<Update> AnonymousFilter { get; protected set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the filter modifiers that affect how this filter is combined with others.
|
|
||||||
/// </summary>
|
|
||||||
public FilterModifier Modifiers { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of <see cref="UpdateHandlerAttributeBase"/>
|
|
||||||
/// </summary>
|
|
||||||
/// <exception cref="ArgumentException"></exception>
|
|
||||||
protected internal UpdateFilterAttributeBase()
|
|
||||||
{
|
|
||||||
if (AllowedTypes.Length == 0)
|
|
||||||
throw new ArgumentException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines the logic of filter modifiers. Exceptionally internal implementation</summary>
|
|
||||||
/// <param name="previous"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public abstract bool ProcessModifiers(UpdateFilterAttributeBase? previous);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the logic of filter modifiers. Exceptionally internal implementation</summary>
|
||||||
|
/// <param name="previous"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public abstract bool ProcessModifiers(UpdateFilterAttributeBase? previous);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,79 +4,78 @@ using Telegrator.Core.Descriptors;
|
|||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
using Telegrator.Core.Handlers;
|
using Telegrator.Core.Handlers;
|
||||||
|
|
||||||
namespace Telegrator.Core.Attributes
|
namespace Telegrator.Core.Attributes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the <see cref="UpdateType"/>'s and validator (<see cref="IFilter{T}"/>) of the <see cref="Update"/> that <see cref="UpdateHandlerBase"/> will process
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||||
|
public abstract class UpdateHandlerAttributeBase : Attribute, IFilter<Update>
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool IsCollectible => GetType().HasPublicProperties();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the <see cref="UpdateType"/>'s and validator (<see cref="IFilter{T}"/>) of the <see cref="Update"/> that <see cref="UpdateHandlerBase"/> will process
|
/// Gets an array of <see cref="UpdateHandlerBase"/> that this attribute can be attached to
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
public Type[] ExpectingHandlerType { get; private set; }
|
||||||
public abstract class UpdateHandlerAttributeBase : Attribute, IFilter<Update>
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an <see cref="UpdateType"/> that handlers processes
|
||||||
|
/// </summary>
|
||||||
|
public UpdateType Type { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets importance of this <see cref="UpdateHandlerBase"/> in same <see cref="UpdateType"/> pool
|
||||||
|
/// </summary>
|
||||||
|
public int Importance { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets priority of this <see cref="UpdateHandlerBase"/> in same type handlers pool
|
||||||
|
/// </summary>
|
||||||
|
public int Priority { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether to form a fallback report.
|
||||||
|
/// </summary>
|
||||||
|
public bool FormReport { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of <see cref="UpdateHandlerAttributeBase"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="expectingHandlerType">The types of handlers that this attribute can be applied to.</param>
|
||||||
|
/// <param name="updateType">The type of update that this handler processes.</param>
|
||||||
|
/// <param name="importance">The importance level of this handler (default: 0).</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="expectingHandlerType"/> is null.</exception>
|
||||||
|
/// <exception cref="ArgumentException">Thrown when one of the handler types is not a valid handler type.</exception>
|
||||||
|
/// <exception cref="Exception">Thrown when <paramref name="updateType"/> is <see cref="UpdateType.Unknown"/>.</exception>
|
||||||
|
protected internal UpdateHandlerAttributeBase(Type[] expectingHandlerType, UpdateType updateType, int importance = 0)
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
if (expectingHandlerType == null)
|
||||||
public bool IsCollectible => GetType().HasPublicProperties();
|
throw new ArgumentNullException(nameof(expectingHandlerType));
|
||||||
|
|
||||||
/// <summary>
|
if (expectingHandlerType.Any(type => !type.IsHandlerAbstract()))
|
||||||
/// Gets an array of <see cref="UpdateHandlerBase"/> that this attribute can be attached to
|
throw new ArgumentException("One of expectingHandlerType is not a handler type", nameof(expectingHandlerType));
|
||||||
/// </summary>
|
|
||||||
public Type[] ExpectingHandlerType { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
if (updateType == UpdateType.Unknown)
|
||||||
/// Gets an <see cref="UpdateType"/> that handlers processes
|
throw new Exception();
|
||||||
/// </summary>
|
|
||||||
public UpdateType Type { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
ExpectingHandlerType = expectingHandlerType;
|
||||||
/// Gets or sets importance of this <see cref="UpdateHandlerBase"/> in same <see cref="UpdateType"/> pool
|
Type = updateType;
|
||||||
/// </summary>
|
Importance = importance;
|
||||||
public int Importance { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets priority of this <see cref="UpdateHandlerBase"/> in same type handlers pool
|
|
||||||
/// </summary>
|
|
||||||
public int Priority { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether to form a fallback report.
|
|
||||||
/// </summary>
|
|
||||||
public bool FormReport { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of <see cref="UpdateHandlerAttributeBase"/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="expectingHandlerType">The types of handlers that this attribute can be applied to.</param>
|
|
||||||
/// <param name="updateType">The type of update that this handler processes.</param>
|
|
||||||
/// <param name="importance">The importance level of this handler (default: 0).</param>
|
|
||||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="expectingHandlerType"/> is null.</exception>
|
|
||||||
/// <exception cref="ArgumentException">Thrown when one of the handler types is not a valid handler type.</exception>
|
|
||||||
/// <exception cref="Exception">Thrown when <paramref name="updateType"/> is <see cref="UpdateType.Unknown"/>.</exception>
|
|
||||||
protected internal UpdateHandlerAttributeBase(Type[] expectingHandlerType, UpdateType updateType, int importance = 0)
|
|
||||||
{
|
|
||||||
if (expectingHandlerType == null)
|
|
||||||
throw new ArgumentNullException(nameof(expectingHandlerType));
|
|
||||||
|
|
||||||
if (expectingHandlerType.Any(type => !type.IsHandlerAbstract()))
|
|
||||||
throw new ArgumentException("One of expectingHandlerType is not a handler type", nameof(expectingHandlerType));
|
|
||||||
|
|
||||||
if (updateType == UpdateType.Unknown)
|
|
||||||
throw new Exception();
|
|
||||||
|
|
||||||
ExpectingHandlerType = expectingHandlerType;
|
|
||||||
Type = updateType;
|
|
||||||
Importance = importance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets an <see cref="DescriptorIndexer"/> of this <see cref="UpdateHandlerAttributeBase"/> from <see cref="Importance"/> and <see cref="Priority"/>
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A descriptor indexer for this handler attribute.</returns>
|
|
||||||
public DescriptorIndexer GetIndexer()
|
|
||||||
=> new DescriptorIndexer(0, this);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Validator (<see cref="IFilter{T}"/>) of the <see cref="Update"/> that <see cref="UpdateHandlerBase"/> will process
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The filter execution context containing the update to validate.</param>
|
|
||||||
/// <returns>True if the update passes validation; otherwise, false.</returns>
|
|
||||||
public abstract bool CanPass(FilterExecutionContext<Update> context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an <see cref="DescriptorIndexer"/> of this <see cref="UpdateHandlerAttributeBase"/> from <see cref="Importance"/> and <see cref="Priority"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A descriptor indexer for this handler attribute.</returns>
|
||||||
|
public DescriptorIndexer GetIndexer()
|
||||||
|
=> new DescriptorIndexer(0, this);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Validator (<see cref="IFilter{T}"/>) of the <see cref="Update"/> that <see cref="UpdateHandlerBase"/> will process
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The filter execution context containing the update to validate.</param>
|
||||||
|
/// <returns>True if the update passes validation; otherwise, false.</returns>
|
||||||
|
public abstract bool CanPass(FilterExecutionContext<Update> context);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,63 +7,62 @@ using Telegrator.Core.Handlers;
|
|||||||
using Telegrator.Handlers;
|
using Telegrator.Handlers;
|
||||||
using Telegrator.Handlers.Building;
|
using Telegrator.Handlers.Building;
|
||||||
|
|
||||||
namespace Telegrator.Core.Descriptors
|
namespace Telegrator.Core.Descriptors;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Descriptor for creating handlers from methods
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TUpdate"></typeparam>
|
||||||
|
public class MethodHandlerDescriptor<TUpdate> : HandlerDescriptor where TUpdate : class
|
||||||
{
|
{
|
||||||
|
private readonly MethodInfo Method;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Descriptor for creating handlers from methods
|
/// Initializes new instance of <see cref="MethodHandlerDescriptor{TUpdate}"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TUpdate"></typeparam>
|
/// <param name="action"></param>
|
||||||
public class MethodHandlerDescriptor<TUpdate> : HandlerDescriptor where TUpdate : class
|
public MethodHandlerDescriptor(AbstractHandlerAction<TUpdate> action) : base(DescriptorType.General, typeof(MethodHandler), true)
|
||||||
{
|
{
|
||||||
private readonly MethodInfo Method;
|
UpdateHandlerAttributeBase handlerAttribute = HandlerInspector.GetHandlerAttribute(action.Method);
|
||||||
|
IFilter<Update>? stateKeeperAttribute = HandlerInspector.GetStateKeeperAttribute(action.Method);
|
||||||
|
IFilter<Update>[] filters = HandlerInspector.GetFilterAttributes(action.Method, handlerAttribute.Type).ToArray();
|
||||||
|
|
||||||
/// <summary>
|
UpdateType = handlerAttribute.Type;
|
||||||
/// Initializes new instance of <see cref="MethodHandlerDescriptor{TUpdate}"/>
|
Indexer = handlerAttribute.GetIndexer();
|
||||||
/// </summary>
|
Filters = new DescriptorFiltersSet(handlerAttribute, stateKeeperAttribute, filters);
|
||||||
/// <param name="action"></param>
|
DisplayString = HandlerInspector.GetDisplayName(action.Method) ?? action.Method.Name;
|
||||||
public MethodHandlerDescriptor(AbstractHandlerAction<TUpdate> action) : base(DescriptorType.General, typeof(MethodHandler), true)
|
Method = action.Method;
|
||||||
|
InstanceFactory = () => new MethodHandler(UpdateType);
|
||||||
|
LazyInitialization = handler =>
|
||||||
{
|
{
|
||||||
UpdateHandlerAttributeBase handlerAttribute = HandlerInspector.GetHandlerAttribute(action.Method);
|
if (handler is not MethodHandler methodHandler)
|
||||||
IFilter<Update>? stateKeeperAttribute = HandlerInspector.GetStateKeeperAttribute(action.Method);
|
throw new InvalidDataException();
|
||||||
IFilter<Update>[] filters = HandlerInspector.GetFilterAttributes(action.Method, handlerAttribute.Type).ToArray();
|
|
||||||
|
|
||||||
UpdateType = handlerAttribute.Type;
|
methodHandler.Method = Method;
|
||||||
Indexer = handlerAttribute.GetIndexer();
|
};
|
||||||
Filters = new DescriptorFiltersSet(handlerAttribute, stateKeeperAttribute, filters);
|
}
|
||||||
DisplayString = HandlerInspector.GetDisplayName(action.Method) ?? action.Method.Name;
|
|
||||||
Method = action.Method;
|
|
||||||
InstanceFactory = () => new MethodHandler(UpdateType);
|
|
||||||
LazyInitialization = handler =>
|
|
||||||
{
|
|
||||||
if (handler is not MethodHandler methodHandler)
|
|
||||||
throw new InvalidDataException();
|
|
||||||
|
|
||||||
methodHandler.Method = Method;
|
private class MethodHandler(UpdateType updateType) : AbstractUpdateHandler<TUpdate>(updateType)
|
||||||
};
|
{
|
||||||
}
|
internal MethodInfo Method = null!;
|
||||||
|
|
||||||
private class MethodHandler(UpdateType updateType) : AbstractUpdateHandler<TUpdate>(updateType)
|
public override async Task<Result> Execute(IHandlerContainer<TUpdate> container, CancellationToken cancellation)
|
||||||
{
|
{
|
||||||
internal MethodInfo Method = null!;
|
if (Method is null)
|
||||||
|
throw new Exception();
|
||||||
|
|
||||||
public override async Task<Result> Execute(IHandlerContainer<TUpdate> container, CancellationToken cancellation)
|
if (Method.ReturnType == typeof(void))
|
||||||
{
|
{
|
||||||
if (Method is null)
|
Method.Invoke(this, [container, cancellation]);
|
||||||
throw new Exception();
|
return Result.Ok();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
object branchReturn = Method.Invoke(this, [container, cancellation]);
|
||||||
|
if (branchReturn is not Task<Result> branchTask)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
if (Method.ReturnType == typeof(void))
|
return await branchTask;
|
||||||
{
|
|
||||||
Method.Invoke(this, [container, cancellation]);
|
|
||||||
return Result.Ok();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
object branchReturn = Method.Invoke(this, [container, cancellation]);
|
|
||||||
if (branchReturn is not Task<Result> branchTask)
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
|
|
||||||
return await branchTask;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,134 +4,133 @@ using Telegrator.Core.Filters;
|
|||||||
using Telegrator.Core.Handlers;
|
using Telegrator.Core.Handlers;
|
||||||
using Telegrator.Core.States;
|
using Telegrator.Core.States;
|
||||||
|
|
||||||
namespace Telegrator.Core.Descriptors
|
namespace Telegrator.Core.Descriptors;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains information about a described handler, including its context, client, and execution logic.
|
||||||
|
/// </summary>
|
||||||
|
public class DescribedHandlerDescriptor
|
||||||
{
|
{
|
||||||
|
private readonly ManualResetEventSlim ResetEvent = new ManualResetEventSlim(false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains information about a described handler, including its context, client, and execution logic.
|
/// Descriptor from that handler was described from.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DescribedHandlerDescriptor
|
public HandlerDescriptor From { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The update router associated with this handler.
|
||||||
|
/// </summary>
|
||||||
|
public IUpdateRouter UpdateRouter { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The awaiting provider to fetch new updates inside handler
|
||||||
|
/// </summary>
|
||||||
|
public IAwaitingProvider AwaitingProvider { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The state storage to handling state machines
|
||||||
|
/// </summary>
|
||||||
|
public IStateStorage StateStorage { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Telegram bot client used for this handler.
|
||||||
|
/// </summary>
|
||||||
|
public ITelegramBotClient Client { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The handler instance being described.
|
||||||
|
/// </summary>
|
||||||
|
public UpdateHandlerBase HandlerInstance { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extra data associated with the handler execution.
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<string, object> ExtraData { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of completed filters for this handler.
|
||||||
|
/// </summary>
|
||||||
|
public CompletedFiltersList CompletedFilters { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The update being handled.
|
||||||
|
/// </summary>
|
||||||
|
public Update HandlingUpdate { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lifetime token for the handler instance.
|
||||||
|
/// </summary>
|
||||||
|
public HandlerLifetimeToken HandlerLifetime => HandlerInstance.LifetimeToken;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Display string for the handler (for debugging or logging).
|
||||||
|
/// </summary>
|
||||||
|
public string DisplayString { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The final execution result.
|
||||||
|
/// </summary>
|
||||||
|
public Result? Result { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DescribedHandlerDescriptor"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromDescriptor">The descriptor from which this handler was described.</param>
|
||||||
|
/// <param name="updateRouter">The update router.</param>
|
||||||
|
/// <param name="awaitingProvider">The awaiting provider.</param>
|
||||||
|
/// <param name="stateStorage">The state storage.</param>
|
||||||
|
/// <param name="client">The Telegram bot client.</param>
|
||||||
|
/// <param name="handlerInstance">The handler instance.</param>
|
||||||
|
/// <param name="filterContext">The filter execution context.</param>
|
||||||
|
/// <param name="displayString">Optional display string.</param>
|
||||||
|
public DescribedHandlerDescriptor(
|
||||||
|
HandlerDescriptor fromDescriptor,
|
||||||
|
IUpdateRouter updateRouter,
|
||||||
|
IAwaitingProvider awaitingProvider,
|
||||||
|
IStateStorage stateStorage,
|
||||||
|
ITelegramBotClient client,
|
||||||
|
UpdateHandlerBase handlerInstance,
|
||||||
|
FilterExecutionContext<Update> filterContext,
|
||||||
|
string? displayString)
|
||||||
{
|
{
|
||||||
private readonly ManualResetEventSlim ResetEvent = new ManualResetEventSlim(false);
|
From = fromDescriptor;
|
||||||
|
UpdateRouter = updateRouter;
|
||||||
/// <summary>
|
AwaitingProvider = awaitingProvider;
|
||||||
/// Descriptor from that handler was described from.
|
StateStorage = stateStorage;
|
||||||
/// </summary>
|
Client = client;
|
||||||
public HandlerDescriptor From { get; }
|
HandlerInstance = handlerInstance;
|
||||||
|
ExtraData = filterContext.Data;
|
||||||
/// <summary>
|
CompletedFilters = filterContext.CompletedFilters;
|
||||||
/// The update router associated with this handler.
|
HandlingUpdate = filterContext.Update;
|
||||||
/// </summary>
|
DisplayString = displayString ?? fromDescriptor.HandlerType.Name;
|
||||||
public IUpdateRouter UpdateRouter { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The awaiting provider to fetch new updates inside handler
|
|
||||||
/// </summary>
|
|
||||||
public IAwaitingProvider AwaitingProvider { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The state storage to handling state machines
|
|
||||||
/// </summary>
|
|
||||||
public IStateStorage StateStorage { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The Telegram bot client used for this handler.
|
|
||||||
/// </summary>
|
|
||||||
public ITelegramBotClient Client { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The handler instance being described.
|
|
||||||
/// </summary>
|
|
||||||
public UpdateHandlerBase HandlerInstance { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Extra data associated with the handler execution.
|
|
||||||
/// </summary>
|
|
||||||
public Dictionary<string, object> ExtraData { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// List of completed filters for this handler.
|
|
||||||
/// </summary>
|
|
||||||
public CompletedFiltersList CompletedFilters { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The update being handled.
|
|
||||||
/// </summary>
|
|
||||||
public Update HandlingUpdate { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Lifetime token for the handler instance.
|
|
||||||
/// </summary>
|
|
||||||
public HandlerLifetimeToken HandlerLifetime => HandlerInstance.LifetimeToken;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Display string for the handler (for debugging or logging).
|
|
||||||
/// </summary>
|
|
||||||
public string DisplayString { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The final execution result.
|
|
||||||
/// </summary>
|
|
||||||
public Result? Result { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="DescribedHandlerDescriptor"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fromDescriptor">The descriptor from which this handler was described.</param>
|
|
||||||
/// <param name="updateRouter">The update router.</param>
|
|
||||||
/// <param name="awaitingProvider">The awaiting provider.</param>
|
|
||||||
/// <param name="stateStorage">The state storage.</param>
|
|
||||||
/// <param name="client">The Telegram bot client.</param>
|
|
||||||
/// <param name="handlerInstance">The handler instance.</param>
|
|
||||||
/// <param name="filterContext">The filter execution context.</param>
|
|
||||||
/// <param name="displayString">Optional display string.</param>
|
|
||||||
public DescribedHandlerDescriptor(
|
|
||||||
HandlerDescriptor fromDescriptor,
|
|
||||||
IUpdateRouter updateRouter,
|
|
||||||
IAwaitingProvider awaitingProvider,
|
|
||||||
IStateStorage stateStorage,
|
|
||||||
ITelegramBotClient client,
|
|
||||||
UpdateHandlerBase handlerInstance,
|
|
||||||
FilterExecutionContext<Update> filterContext,
|
|
||||||
string? displayString)
|
|
||||||
{
|
|
||||||
From = fromDescriptor;
|
|
||||||
UpdateRouter = updateRouter;
|
|
||||||
AwaitingProvider = awaitingProvider;
|
|
||||||
StateStorage = stateStorage;
|
|
||||||
Client = client;
|
|
||||||
HandlerInstance = handlerInstance;
|
|
||||||
ExtraData = filterContext.Data;
|
|
||||||
CompletedFilters = filterContext.CompletedFilters;
|
|
||||||
HandlingUpdate = filterContext.Update;
|
|
||||||
DisplayString = displayString ?? fromDescriptor.HandlerType.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Waits for the handler execution result.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
|
||||||
public async Task AwaitResult(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
await Task.Yield();
|
|
||||||
ResetEvent.Reset();
|
|
||||||
ResetEvent.Wait(cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reports the execution result and signals completion.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="result">The execution result.</param>
|
|
||||||
public void ReportResult(Result? result)
|
|
||||||
{
|
|
||||||
if (Result != null)
|
|
||||||
throw new InvalidOperationException("Result already reported");
|
|
||||||
|
|
||||||
Result = result;
|
|
||||||
ResetEvent.Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override string ToString()
|
|
||||||
=> DisplayString ?? From.HandlerType.Name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Waits for the handler execution result.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
public async Task AwaitResult(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await Task.Yield();
|
||||||
|
ResetEvent.Reset();
|
||||||
|
ResetEvent.Wait(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reports the execution result and signals completion.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result">The execution result.</param>
|
||||||
|
public void ReportResult(Result? result)
|
||||||
|
{
|
||||||
|
if (Result != null)
|
||||||
|
throw new InvalidOperationException("Result already reported");
|
||||||
|
|
||||||
|
Result = result;
|
||||||
|
ResetEvent.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string ToString()
|
||||||
|
=> DisplayString ?? From.HandlerType.Name;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,80 +1,79 @@
|
|||||||
using Telegrator.Aspects;
|
using Telegrator.Aspects;
|
||||||
using Telegrator.Core.Handlers;
|
using Telegrator.Core.Handlers;
|
||||||
|
|
||||||
namespace Telegrator.Core.Descriptors
|
namespace Telegrator.Core.Descriptors;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Manages the execution of pre and post-execution aspects for a handler.
|
||||||
|
/// This class coordinates between self-processing (handler implements interfaces)
|
||||||
|
/// and typed processing (external processor classes).
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DescriptorAspectsSet
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Manages the execution of pre and post-execution aspects for a handler.
|
/// Gets the type of the external pre-processor, if specified via <see cref="BeforeExecutionAttribute{T}"/>.
|
||||||
/// This class coordinates between self-processing (handler implements interfaces)
|
|
||||||
/// and typed processing (external processor classes).
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class DescriptorAspectsSet
|
public Type? TypedPre { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type of the external post-processor, if specified via <see cref="AfterExecutionAttribute{T}"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Type? TypedPost { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DescriptorAspectsSet"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="typedPre">The type of external pre-processor, if any.</param>
|
||||||
|
/// <param name="typedPost">The type of external post-processor, if any.</param>
|
||||||
|
public DescriptorAspectsSet(Type? typedPre, Type? typedPost)
|
||||||
{
|
{
|
||||||
/// <summary>
|
TypedPre = typedPre;
|
||||||
/// Gets the type of the external pre-processor, if specified via <see cref="BeforeExecutionAttribute{T}"/>.
|
TypedPost = typedPost;
|
||||||
/// </summary>
|
}
|
||||||
public Type? TypedPre { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the type of the external post-processor, if specified via <see cref="AfterExecutionAttribute{T}"/>.
|
/// Executes the pre-execution aspect for the handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Type? TypedPost { get; private set; }
|
/// <param name="handler">The handler instance.</param>
|
||||||
|
/// <param name="container">The handler container with update context.</param>
|
||||||
/// <summary>
|
/// <param name="cancellationToken"></param>
|
||||||
/// Initializes a new instance of the <see cref="DescriptorAspectsSet"/> class.
|
/// <returns>A <see cref="Result"/> indicating whether execution should continue.</returns>
|
||||||
/// </summary>
|
/// <exception cref="InvalidOperationException">Thrown when handler claims to implement <see cref="IPreProcessor"/> but doesn't.</exception>
|
||||||
/// <param name="typedPre">The type of external pre-processor, if any.</param>
|
public async Task<Result> ExecutePre(UpdateHandlerBase handler, IHandlerContainer container, CancellationToken cancellationToken)
|
||||||
/// <param name="typedPost">The type of external post-processor, if any.</param>
|
{
|
||||||
public DescriptorAspectsSet(Type? typedPre, Type? typedPost)
|
if (handler is IPreProcessor preProcessor)
|
||||||
{
|
{
|
||||||
TypedPre = typedPre;
|
return await preProcessor.BeforeExecution(container, cancellationToken).ConfigureAwait(false);
|
||||||
TypedPost = typedPost;
|
}
|
||||||
|
else if (TypedPre != null)
|
||||||
|
{
|
||||||
|
preProcessor = (IPreProcessor)Activator.CreateInstance(TypedPre);
|
||||||
|
return await preProcessor.BeforeExecution(container, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
return Result.Ok();
|
||||||
/// Executes the pre-execution aspect for the handler.
|
}
|
||||||
/// </summary>
|
|
||||||
/// <param name="handler">The handler instance.</param>
|
|
||||||
/// <param name="container">The handler container with update context.</param>
|
|
||||||
/// <param name="cancellationToken"></param>
|
|
||||||
/// <returns>A <see cref="Result"/> indicating whether execution should continue.</returns>
|
|
||||||
/// <exception cref="InvalidOperationException">Thrown when handler claims to implement <see cref="IPreProcessor"/> but doesn't.</exception>
|
|
||||||
public async Task<Result> ExecutePre(UpdateHandlerBase handler, IHandlerContainer container, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
if (handler is IPreProcessor preProcessor)
|
|
||||||
{
|
|
||||||
return await preProcessor.BeforeExecution(container, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
else if (TypedPre != null)
|
|
||||||
{
|
|
||||||
preProcessor = (IPreProcessor)Activator.CreateInstance(TypedPre);
|
|
||||||
return await preProcessor.BeforeExecution(container, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.Ok();
|
/// <summary>
|
||||||
|
/// Executes the post-execution aspect for the handler.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handler">The handler instance.</param>
|
||||||
|
/// <param name="container">The handler container with update context.</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns>A <see cref="Result"/> indicating the final execution result.</returns>
|
||||||
|
/// <exception cref="InvalidOperationException">Thrown when handler claims to implement <see cref="IPostProcessor"/> but doesn't.</exception>
|
||||||
|
public async Task<Result> ExecutePost(UpdateHandlerBase handler, IHandlerContainer container, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (handler is IPostProcessor postProcessor)
|
||||||
|
{
|
||||||
|
return await postProcessor.AfterExecution(container, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else if (TypedPost != null)
|
||||||
|
{
|
||||||
|
postProcessor = (IPostProcessor)Activator.CreateInstance(TypedPost);
|
||||||
|
return await postProcessor.AfterExecution(container, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
return Result.Ok();
|
||||||
/// Executes the post-execution aspect for the handler.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handler">The handler instance.</param>
|
|
||||||
/// <param name="container">The handler container with update context.</param>
|
|
||||||
/// <param name="cancellationToken"></param>
|
|
||||||
/// <returns>A <see cref="Result"/> indicating the final execution result.</returns>
|
|
||||||
/// <exception cref="InvalidOperationException">Thrown when handler claims to implement <see cref="IPostProcessor"/> but doesn't.</exception>
|
|
||||||
public async Task<Result> ExecutePost(UpdateHandlerBase handler, IHandlerContainer container, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
if (handler is IPostProcessor postProcessor)
|
|
||||||
{
|
|
||||||
return await postProcessor.AfterExecution(container, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
else if (TypedPost != null)
|
|
||||||
{
|
|
||||||
postProcessor = (IPostProcessor)Activator.CreateInstance(TypedPost);
|
|
||||||
return await postProcessor.AfterExecution(container, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.Ok();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,143 +3,142 @@ using Telegrator.Core.Filters;
|
|||||||
using Telegrator.Handlers.Diagnostics;
|
using Telegrator.Handlers.Diagnostics;
|
||||||
using Telegrator.Logging;
|
using Telegrator.Logging;
|
||||||
|
|
||||||
namespace Telegrator.Core.Descriptors
|
namespace Telegrator.Core.Descriptors;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a set of filters for a handler descriptor, including update and state keeper validators.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DescriptorFiltersSet
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a set of filters for a handler descriptor, including update and state keeper validators.
|
/// Validator for the update object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class DescriptorFiltersSet
|
public IFilter<Update>? UpdateValidator { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Validator for the state keeper.
|
||||||
|
/// </summary>
|
||||||
|
public IFilter<Update>? StateKeeperValidator { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Array of update filters.
|
||||||
|
/// </summary>
|
||||||
|
public IFilter<Update>[]? UpdateFilters { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DescriptorFiltersSet"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="updateValidator">Validator for the update object.</param>
|
||||||
|
/// <param name="stateKeeperValidator">Validator for the state keeper.</param>
|
||||||
|
/// <param name="updateFilters">Array of update filters.</param>
|
||||||
|
public DescriptorFiltersSet(IFilter<Update>? updateValidator, IFilter<Update>? stateKeeperValidator, IFilter<Update>[]? updateFilters)
|
||||||
{
|
{
|
||||||
/// <summary>
|
UpdateValidator = updateValidator;
|
||||||
/// Validator for the update object.
|
StateKeeperValidator = stateKeeperValidator;
|
||||||
/// </summary>
|
UpdateFilters = updateFilters;
|
||||||
public IFilter<Update>? UpdateValidator { get; set; }
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Validator for the state keeper.
|
/// Validates the filter context using all filters in the set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IFilter<Update>? StateKeeperValidator { get; set; }
|
/// <param name="filterContext">The filter execution context.</param>
|
||||||
|
/// <param name="formReport"></param>
|
||||||
|
/// <param name="report"></param>
|
||||||
|
/// <returns>True if all filters pass; otherwise, false.</returns>
|
||||||
|
public Result Validate(FilterExecutionContext<Update> filterContext, bool formReport, ref FiltersFallbackReport report)
|
||||||
|
{
|
||||||
|
bool anyErrors = false;
|
||||||
|
|
||||||
/// <summary>
|
if (UpdateValidator != null)
|
||||||
/// Array of update filters.
|
|
||||||
/// </summary>
|
|
||||||
public IFilter<Update>[]? UpdateFilters { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="DescriptorFiltersSet"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="updateValidator">Validator for the update object.</param>
|
|
||||||
/// <param name="stateKeeperValidator">Validator for the state keeper.</param>
|
|
||||||
/// <param name="updateFilters">Array of update filters.</param>
|
|
||||||
public DescriptorFiltersSet(IFilter<Update>? updateValidator, IFilter<Update>? stateKeeperValidator, IFilter<Update>[]? updateFilters)
|
|
||||||
{
|
{
|
||||||
UpdateValidator = updateValidator;
|
bool result = ExecuteFilter(UpdateValidator, filterContext, out Exception? exc);
|
||||||
StateKeeperValidator = stateKeeperValidator;
|
|
||||||
UpdateFilters = updateFilters;
|
if (formReport)
|
||||||
|
{
|
||||||
|
report.UpdateValidator = new FilterFallbackInfo("Validator", UpdateValidator, !result, exc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
anyErrors = true;
|
||||||
|
TelegratorLogging.LogTrace("(E) UpdateValidator filter of '{0}' for Update ({1}) didnt pass!", filterContext.Data["handler_name"], filterContext.Update.Id);
|
||||||
|
|
||||||
|
if (!formReport)
|
||||||
|
return Result.Fault();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filterContext.CompletedFilters.Add(UpdateValidator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
if (StateKeeperValidator != null)
|
||||||
/// Validates the filter context using all filters in the set.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filterContext">The filter execution context.</param>
|
|
||||||
/// <param name="formReport"></param>
|
|
||||||
/// <param name="report"></param>
|
|
||||||
/// <returns>True if all filters pass; otherwise, false.</returns>
|
|
||||||
public Result Validate(FilterExecutionContext<Update> filterContext, bool formReport, ref FiltersFallbackReport report)
|
|
||||||
{
|
{
|
||||||
bool anyErrors = false;
|
bool result = ExecuteFilter(StateKeeperValidator, filterContext, out Exception? exc);
|
||||||
|
|
||||||
if (UpdateValidator != null)
|
if (formReport)
|
||||||
{
|
{
|
||||||
bool result = ExecuteFilter(UpdateValidator, filterContext, out Exception? exc);
|
report.StateKeeperValidator = new FilterFallbackInfo("State", StateKeeperValidator, !result, exc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
anyErrors = true;
|
||||||
|
TelegratorLogging.LogTrace("(E) StateKeeperValidator filter of '{0}' for Update ({1}) didnt pass!", filterContext.Data["handler_name"], filterContext.Update.Id);
|
||||||
|
|
||||||
|
if (!formReport)
|
||||||
|
return Result.Fault();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filterContext.CompletedFilters.Add(StateKeeperValidator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UpdateFilters != null)
|
||||||
|
{
|
||||||
|
foreach (IFilter<Update> filter in UpdateFilters)
|
||||||
|
{
|
||||||
|
bool result = ExecuteFilter(filter, filterContext, out Exception? exc);
|
||||||
|
string filterName = filter is INamedFilter named ? named.Name : filter.GetType().Name;
|
||||||
|
|
||||||
if (formReport)
|
if (formReport)
|
||||||
{
|
{
|
||||||
report.UpdateValidator = new FilterFallbackInfo("Validator", UpdateValidator, !result, exc);
|
report.UpdateFilters.Add(new FilterFallbackInfo(filterName, filter, !result, exc));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
anyErrors = true;
|
anyErrors = true;
|
||||||
TelegratorLogging.LogTrace("(E) UpdateValidator filter of '{0}' for Update ({1}) didnt pass!", filterContext.Data["handler_name"], filterContext.Update.Id);
|
TelegratorLogging.LogTrace("(E) '{0}' filter of '{1}' for Update ({2}) didnt pass!", filterName, filterContext.Data["handler_name"], filterContext.Update.Id);
|
||||||
|
|
||||||
if (!formReport)
|
if (!formReport)
|
||||||
return Result.Fault();
|
return Result.Fault();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
filterContext.CompletedFilters.Add(UpdateValidator);
|
filterContext.CompletedFilters.Add(filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StateKeeperValidator != null)
|
|
||||||
{
|
|
||||||
bool result = ExecuteFilter(StateKeeperValidator, filterContext, out Exception? exc);
|
|
||||||
|
|
||||||
if (formReport)
|
|
||||||
{
|
|
||||||
report.StateKeeperValidator = new FilterFallbackInfo("State", StateKeeperValidator, !result, exc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
anyErrors = true;
|
|
||||||
TelegratorLogging.LogTrace("(E) StateKeeperValidator filter of '{0}' for Update ({1}) didnt pass!", filterContext.Data["handler_name"], filterContext.Update.Id);
|
|
||||||
|
|
||||||
if (!formReport)
|
|
||||||
return Result.Fault();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filterContext.CompletedFilters.Add(StateKeeperValidator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UpdateFilters != null)
|
|
||||||
{
|
|
||||||
foreach (IFilter<Update> filter in UpdateFilters)
|
|
||||||
{
|
|
||||||
bool result = ExecuteFilter(filter, filterContext, out Exception? exc);
|
|
||||||
string filterName = filter is INamedFilter named ? named.Name : filter.GetType().Name;
|
|
||||||
|
|
||||||
if (formReport)
|
|
||||||
{
|
|
||||||
report.UpdateFilters.Add(new FilterFallbackInfo(filterName, filter, !result, exc));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
anyErrors = true;
|
|
||||||
TelegratorLogging.LogTrace("(E) '{0}' filter of '{1}' for Update ({2}) didnt pass!", filterName, filterContext.Data["handler_name"], filterContext.Update.Id);
|
|
||||||
|
|
||||||
if (!formReport)
|
|
||||||
return Result.Fault();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filterContext.CompletedFilters.Add(filter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!anyErrors)
|
|
||||||
return Result.Ok();
|
|
||||||
|
|
||||||
return formReport ? Result.Next() : Result.Fault();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool ExecuteFilter<T>(IFilter<T> filter, FilterExecutionContext<T> context, out Exception? exception) where T : class
|
if (!anyErrors)
|
||||||
|
return Result.Ok();
|
||||||
|
|
||||||
|
return formReport ? Result.Next() : Result.Fault();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ExecuteFilter<T>(IFilter<T> filter, FilterExecutionContext<T> context, out Exception? exception) where T : class
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
exception = null;
|
||||||
{
|
return filter.CanPass(context);
|
||||||
exception = null;
|
}
|
||||||
return filter.CanPass(context);
|
catch (Exception ex)
|
||||||
}
|
{
|
||||||
catch (Exception ex)
|
exception = ex;
|
||||||
{
|
return false;
|
||||||
exception = ex;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,88 +1,87 @@
|
|||||||
using Telegrator.Core.Attributes;
|
using Telegrator.Core.Attributes;
|
||||||
|
|
||||||
namespace Telegrator.Core.Descriptors
|
namespace Telegrator.Core.Descriptors;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an indexer for handler descriptors, containing importance and priority information.
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct DescriptorIndexer(int routerIndex, int importance, int priority) : IComparable<DescriptorIndexer>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents an indexer for handler descriptors, containing importance and priority information.
|
/// Index of this descriptor when it was added to router
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly struct DescriptorIndexer(int routerIndex, int importance, int priority) : IComparable<DescriptorIndexer>
|
public readonly int RouterIndex = routerIndex;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Of this handlert type
|
||||||
|
/// </summary>
|
||||||
|
public readonly int Importance = importance;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The priority of the handler.
|
||||||
|
/// </summary>
|
||||||
|
public readonly int Priority = priority;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DescriptorIndexer"/> struct from a handler attribute.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="routerIndex"></param>
|
||||||
|
/// <param name="pollingHandler">The handler attribute.</param>
|
||||||
|
public DescriptorIndexer(int routerIndex, UpdateHandlerAttributeBase pollingHandler)
|
||||||
|
: this(routerIndex, pollingHandler.Importance, pollingHandler.Priority) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a new <see cref="DescriptorIndexer"/> with updated priority.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="priority">The new priority value.</param>
|
||||||
|
/// <returns>A new <see cref="DescriptorIndexer"/> instance.</returns>
|
||||||
|
public DescriptorIndexer UpdatePriority(int priority)
|
||||||
|
=> new DescriptorIndexer(RouterIndex, Importance, priority);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a new <see cref="DescriptorIndexer"/> with updated importance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="importance">The new importance value.</param>
|
||||||
|
/// <returns>A new <see cref="DescriptorIndexer"/> instance.</returns>
|
||||||
|
public DescriptorIndexer UpdateImportance(int importance)
|
||||||
|
=> new DescriptorIndexer(RouterIndex, importance, Priority);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a new <see cref="DescriptorIndexer"/> with updated RouterIndex.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="routerIndex"></param>
|
||||||
|
/// <returns>A new <see cref="DescriptorIndexer"/> instance.</returns>
|
||||||
|
public DescriptorIndexer UpdateIndex(int routerIndex)
|
||||||
|
=> new DescriptorIndexer(routerIndex, Importance, Priority);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares this instance to another <see cref="DescriptorIndexer"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other indexer to compare to.</param>
|
||||||
|
/// <returns>An integer indicating the relative order.</returns>
|
||||||
|
public int CompareTo(DescriptorIndexer other)
|
||||||
{
|
{
|
||||||
/// <summary>
|
int importanceCmp = Importance.CompareTo(other.Importance);
|
||||||
/// Index of this descriptor when it was added to router
|
if (importanceCmp != 0)
|
||||||
/// </summary>
|
return importanceCmp;
|
||||||
public readonly int RouterIndex = routerIndex;
|
|
||||||
|
|
||||||
/// <summary>
|
int priorityCmp = Priority.CompareTo(other.Priority);
|
||||||
/// Of this handlert type
|
if (priorityCmp != 0)
|
||||||
/// </summary>
|
return priorityCmp;
|
||||||
public readonly int Importance = importance;
|
|
||||||
|
|
||||||
/// <summary>
|
int routerIndexCmp = RouterIndex.CompareTo(other.RouterIndex);
|
||||||
/// The priority of the handler.
|
if (routerIndexCmp != 0)
|
||||||
/// </summary>
|
return routerIndexCmp;
|
||||||
public readonly int Priority = priority;
|
|
||||||
|
|
||||||
/// <summary>
|
return 0;
|
||||||
/// Initializes a new instance of the <see cref="DescriptorIndexer"/> struct from a handler attribute.
|
}
|
||||||
/// </summary>
|
|
||||||
/// <param name="routerIndex"></param>
|
|
||||||
/// <param name="pollingHandler">The handler attribute.</param>
|
|
||||||
public DescriptorIndexer(int routerIndex, UpdateHandlerAttributeBase pollingHandler)
|
|
||||||
: this(routerIndex, pollingHandler.Importance, pollingHandler.Priority) { }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a new <see cref="DescriptorIndexer"/> with updated priority.
|
/// Returns a string representation of the indexer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="priority">The new priority value.</param>
|
/// <returns>A string in the format (C:importance, P:priority).</returns>
|
||||||
/// <returns>A new <see cref="DescriptorIndexer"/> instance.</returns>
|
public override string ToString()
|
||||||
public DescriptorIndexer UpdatePriority(int priority)
|
{
|
||||||
=> new DescriptorIndexer(RouterIndex, Importance, priority);
|
return string.Format("(Ix: {0,2}, Im: {1,2}, Pr: {2,2})", RouterIndex, Importance, Priority);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a new <see cref="DescriptorIndexer"/> with updated importance.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="importance">The new importance value.</param>
|
|
||||||
/// <returns>A new <see cref="DescriptorIndexer"/> instance.</returns>
|
|
||||||
public DescriptorIndexer UpdateImportance(int importance)
|
|
||||||
=> new DescriptorIndexer(RouterIndex, importance, Priority);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a new <see cref="DescriptorIndexer"/> with updated RouterIndex.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="routerIndex"></param>
|
|
||||||
/// <returns>A new <see cref="DescriptorIndexer"/> instance.</returns>
|
|
||||||
public DescriptorIndexer UpdateIndex(int routerIndex)
|
|
||||||
=> new DescriptorIndexer(routerIndex, Importance, Priority);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compares this instance to another <see cref="DescriptorIndexer"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="other">The other indexer to compare to.</param>
|
|
||||||
/// <returns>An integer indicating the relative order.</returns>
|
|
||||||
public int CompareTo(DescriptorIndexer other)
|
|
||||||
{
|
|
||||||
int importanceCmp = Importance.CompareTo(other.Importance);
|
|
||||||
if (importanceCmp != 0)
|
|
||||||
return importanceCmp;
|
|
||||||
|
|
||||||
int priorityCmp = Priority.CompareTo(other.Priority);
|
|
||||||
if (priorityCmp != 0)
|
|
||||||
return priorityCmp;
|
|
||||||
|
|
||||||
int routerIndexCmp = RouterIndex.CompareTo(other.RouterIndex);
|
|
||||||
if (routerIndexCmp != 0)
|
|
||||||
return routerIndexCmp;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a string representation of the indexer.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A string in the format (C:importance, P:priority).</returns>
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return string.Format("(Ix: {0,2}, Im: {1,2}, Pr: {2,2})", RouterIndex, Importance, Priority);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,472 +4,471 @@ using Telegrator.Core.Attributes;
|
|||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
using Telegrator.Core.Handlers;
|
using Telegrator.Core.Handlers;
|
||||||
|
|
||||||
namespace Telegrator.Core.Descriptors
|
namespace Telegrator.Core.Descriptors;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the type of handler descriptor.
|
||||||
|
/// </summary>
|
||||||
|
public enum DescriptorType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Specifies the type of handler descriptor.
|
/// General handler descriptor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum DescriptorType
|
General,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Keyed handler descriptor (uses a service key).
|
||||||
|
/// </summary>
|
||||||
|
Keyed,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implicit handler descriptor.
|
||||||
|
/// </summary>
|
||||||
|
Implicit,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Singleton handler descriptor (single instance).
|
||||||
|
/// </summary>
|
||||||
|
Singleton
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Describes a handler, its type, filters, and instantiation logic.
|
||||||
|
/// </summary>
|
||||||
|
public class HandlerDescriptor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of the descriptor.
|
||||||
|
/// </summary>
|
||||||
|
public DescriptorType Type
|
||||||
{
|
{
|
||||||
/// <summary>
|
get;
|
||||||
/// General handler descriptor.
|
private set;
|
||||||
/// </summary>
|
|
||||||
General,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Keyed handler descriptor (uses a service key).
|
|
||||||
/// </summary>
|
|
||||||
Keyed,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Implicit handler descriptor.
|
|
||||||
/// </summary>
|
|
||||||
Implicit,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Singleton handler descriptor (single instance).
|
|
||||||
/// </summary>
|
|
||||||
Singleton
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Describes a handler, its type, filters, and instantiation logic.
|
/// The type of the handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class HandlerDescriptor
|
public Type HandlerType
|
||||||
{
|
{
|
||||||
/// <summary>
|
get;
|
||||||
/// The type of the descriptor.
|
private set;
|
||||||
/// </summary>
|
|
||||||
public DescriptorType Type
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The type of the handler.
|
|
||||||
/// </summary>
|
|
||||||
public Type HandlerType
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The update type handled by this handler.
|
|
||||||
/// </summary>
|
|
||||||
public UpdateType UpdateType
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
protected set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The indexer for handler concurrency and priority.
|
|
||||||
/// </summary>
|
|
||||||
public DescriptorIndexer Indexer
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether to form a fallback report.
|
|
||||||
/// </summary>
|
|
||||||
public bool FormReport
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The set of filters associated with this handler.
|
|
||||||
/// </summary>
|
|
||||||
public DescriptorFiltersSet? Filters
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
protected set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the aspects configuration for this handler.
|
|
||||||
/// Contains pre and post-execution processors if the handler uses the aspect system.
|
|
||||||
/// </summary>
|
|
||||||
public DescriptorAspectsSet? Aspects
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
protected set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The service key for keyed handlers.
|
|
||||||
/// </summary>
|
|
||||||
public object? ServiceKey
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
protected set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Factory for creating handler instances.
|
|
||||||
/// </summary>
|
|
||||||
public Func<UpdateHandlerBase>? InstanceFactory
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
protected set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Singleton instance of the handler, if applicable.
|
|
||||||
/// </summary>
|
|
||||||
public UpdateHandlerBase? SingletonInstance
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
protected set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Display string for the handler (for debugging or logging).
|
|
||||||
/// </summary>
|
|
||||||
public string? DisplayString
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a function for 'lazy' handlers initialization
|
|
||||||
/// </summary>
|
|
||||||
public Action<UpdateHandlerBase>? LazyInitialization
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with the specified descriptor type and handler type.
|
|
||||||
/// Automatically inspects the handler type to extract attributes, filters, and configuration.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="descriptorType">The type of the descriptor</param>
|
|
||||||
/// <param name="handlerType">The type of the handler to describe</param>
|
|
||||||
/// <param name="dontInspect"></param>
|
|
||||||
/// <exception cref="ArgumentException">Thrown when the handler type is not compatible with the expected handler type</exception>
|
|
||||||
public HandlerDescriptor(DescriptorType descriptorType, Type handlerType, bool dontInspect = false)
|
|
||||||
{
|
|
||||||
Type = descriptorType;
|
|
||||||
HandlerType = handlerType;
|
|
||||||
Filters = new DescriptorFiltersSet(null, null, null);
|
|
||||||
|
|
||||||
if (dontInspect)
|
|
||||||
return;
|
|
||||||
|
|
||||||
UpdateHandlerAttributeBase handlerAttribute = HandlerInspector.GetHandlerAttribute(handlerType);
|
|
||||||
if (handlerAttribute.ExpectingHandlerType != null && !handlerAttribute.ExpectingHandlerType.Contains(handlerType.BaseType))
|
|
||||||
throw new ArgumentException(string.Format("This handler attribute cannot be attached to this class. Attribute can be attached on next handlers : {0}", string.Join(", ", handlerAttribute.ExpectingHandlerType.AsEnumerable())));
|
|
||||||
|
|
||||||
IFilter<Update>? stateKeeperAttribute = HandlerInspector.GetStateKeeperAttribute(handlerType);
|
|
||||||
IFilter<Update>[] filters = HandlerInspector.GetFilterAttributes(handlerType, handlerAttribute.Type).ToArray();
|
|
||||||
|
|
||||||
UpdateType = handlerAttribute.Type;
|
|
||||||
Indexer = handlerAttribute.GetIndexer();
|
|
||||||
FormReport = handlerAttribute.FormReport;
|
|
||||||
Filters = new DescriptorFiltersSet(handlerAttribute, stateKeeperAttribute, filters);
|
|
||||||
Aspects = HandlerInspector.GetAspects(handlerType);
|
|
||||||
DisplayString = HandlerInspector.GetDisplayName(handlerType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class as a keyed handler with the specified service key.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handlerType">The type of the handler to describe</param>
|
|
||||||
/// <param name="serviceKey">The service key for dependency injection</param>
|
|
||||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="serviceKey"/> is null</exception>
|
|
||||||
public HandlerDescriptor(Type handlerType, object serviceKey) : this(DescriptorType.Keyed, handlerType)
|
|
||||||
{
|
|
||||||
ServiceKey = serviceKey ?? throw new ArgumentNullException(nameof(serviceKey));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with all basic properties.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The type of the descriptor</param>
|
|
||||||
/// <param name="handlerType">The type of the handler</param>
|
|
||||||
/// <param name="updateType">The type of update this handler processes</param>
|
|
||||||
/// <param name="indexer">The indexer for handler concurrency and priority</param>
|
|
||||||
/// <param name="filters">The set of filters associated with this handler</param>
|
|
||||||
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateType updateType, DescriptorIndexer indexer, DescriptorFiltersSet filters)
|
|
||||||
{
|
|
||||||
Type = type;
|
|
||||||
HandlerType = handlerType;
|
|
||||||
UpdateType = updateType;
|
|
||||||
Indexer = indexer;
|
|
||||||
Filters = filters;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with singleton instance support.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The type of the descriptor</param>
|
|
||||||
/// <param name="handlerType">The type of the handler</param>
|
|
||||||
/// <param name="updateType">The type of update this handler processes</param>
|
|
||||||
/// <param name="indexer">The indexer for handler concurrency and priority</param>
|
|
||||||
/// <param name="filters">The set of filters associated with this handler</param>
|
|
||||||
/// <param name="serviceKey">The service key for dependency injection</param>
|
|
||||||
/// <param name="singletonInstance">The singleton instance of the handler</param>
|
|
||||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="serviceKey"/> or <paramref name="singletonInstance"/> is null</exception>
|
|
||||||
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateType updateType, DescriptorIndexer indexer, DescriptorFiltersSet filters, object serviceKey, UpdateHandlerBase singletonInstance)
|
|
||||||
{
|
|
||||||
Type = type;
|
|
||||||
HandlerType = handlerType;
|
|
||||||
UpdateType = updateType;
|
|
||||||
Indexer = indexer;
|
|
||||||
Filters = filters;
|
|
||||||
ServiceKey = serviceKey ?? throw new ArgumentNullException(nameof(serviceKey));
|
|
||||||
SingletonInstance = singletonInstance ?? throw new ArgumentNullException(nameof(singletonInstance));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with instance factory support.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The type of the descriptor</param>
|
|
||||||
/// <param name="handlerType">The type of the handler</param>
|
|
||||||
/// <param name="updateType">The type of update this handler processes</param>
|
|
||||||
/// <param name="indexer">The indexer for handler concurrency and priority</param>
|
|
||||||
/// <param name="filters">The set of filters associated with this handler</param>
|
|
||||||
/// <param name="instanceFactory">Factory for creating handler instances</param>
|
|
||||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="instanceFactory"/> is null</exception>
|
|
||||||
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateType updateType, DescriptorIndexer indexer, DescriptorFiltersSet filters, Func<UpdateHandlerBase> instanceFactory)
|
|
||||||
{
|
|
||||||
Type = type;
|
|
||||||
HandlerType = handlerType;
|
|
||||||
UpdateType = updateType;
|
|
||||||
Indexer = indexer;
|
|
||||||
Filters = filters;
|
|
||||||
InstanceFactory = instanceFactory ?? throw new ArgumentNullException(nameof(instanceFactory));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with service key and instance factory support.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The type of the descriptor</param>
|
|
||||||
/// <param name="handlerType">The type of the handler</param>
|
|
||||||
/// <param name="updateType">The type of update this handler processes</param>
|
|
||||||
/// <param name="indexer">The indexer for handler concurrency and priority</param>
|
|
||||||
/// <param name="filters">The set of filters associated with this handler</param>
|
|
||||||
/// <param name="serviceKey">The service key for dependency injection</param>
|
|
||||||
/// <param name="instanceFactory">Factory for creating handler instances</param>
|
|
||||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="serviceKey"/> or <paramref name="instanceFactory"/> is null</exception>
|
|
||||||
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateType updateType, DescriptorIndexer indexer, DescriptorFiltersSet filters, object serviceKey, Func<UpdateHandlerBase> instanceFactory)
|
|
||||||
{
|
|
||||||
Type = type;
|
|
||||||
HandlerType = handlerType;
|
|
||||||
UpdateType = updateType;
|
|
||||||
Indexer = indexer;
|
|
||||||
Filters = filters;
|
|
||||||
ServiceKey = serviceKey ?? throw new ArgumentNullException(nameof(serviceKey));
|
|
||||||
InstanceFactory = instanceFactory ?? throw new ArgumentNullException(nameof(instanceFactory));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with polling handler attribute and filters.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The type of the descriptor</param>
|
|
||||||
/// <param name="handlerType">The type of the handler</param>
|
|
||||||
/// <param name="pollingHandlerAttribute">The polling handler attribute containing configuration</param>
|
|
||||||
/// <param name="filters">Optional array of filters to apply</param>
|
|
||||||
/// <param name="stateKeepFilter">Optional state keeping filter</param>
|
|
||||||
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateHandlerAttributeBase pollingHandlerAttribute, IFilter<Update>[]? filters, IFilter<Update>? stateKeepFilter)
|
|
||||||
{
|
|
||||||
Type = type;
|
|
||||||
HandlerType = handlerType;
|
|
||||||
UpdateType = pollingHandlerAttribute.Type;
|
|
||||||
Indexer = pollingHandlerAttribute.GetIndexer();
|
|
||||||
Filters = new DescriptorFiltersSet(pollingHandlerAttribute, stateKeepFilter, filters);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with polling handler attribute, filters, and singleton instance.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The type of the descriptor</param>
|
|
||||||
/// <param name="handlerType">The type of the handler</param>
|
|
||||||
/// <param name="pollingHandlerAttribute">The polling handler attribute containing configuration</param>
|
|
||||||
/// <param name="filters">Optional array of filters to apply</param>
|
|
||||||
/// <param name="stateKeepFilter">Optional state keeping filter</param>
|
|
||||||
/// <param name="serviceKey">The service key for dependency injection</param>
|
|
||||||
/// <param name="singletonInstance">The singleton instance of the handler</param>
|
|
||||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="serviceKey"/> or <paramref name="singletonInstance"/> is null</exception>
|
|
||||||
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateHandlerAttributeBase pollingHandlerAttribute, IFilter<Update>[]? filters, IFilter<Update>? stateKeepFilter, object serviceKey, UpdateHandlerBase singletonInstance)
|
|
||||||
{
|
|
||||||
Type = type;
|
|
||||||
HandlerType = handlerType;
|
|
||||||
UpdateType = pollingHandlerAttribute.Type;
|
|
||||||
Indexer = pollingHandlerAttribute.GetIndexer();
|
|
||||||
Filters = new DescriptorFiltersSet(pollingHandlerAttribute, stateKeepFilter, filters);
|
|
||||||
ServiceKey = serviceKey ?? throw new ArgumentNullException(nameof(serviceKey));
|
|
||||||
SingletonInstance = singletonInstance ?? throw new ArgumentNullException(nameof(singletonInstance));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with polling handler attribute, filters, and instance factory.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The type of the descriptor</param>
|
|
||||||
/// <param name="handlerType">The type of the handler</param>
|
|
||||||
/// <param name="pollingHandlerAttribute">The polling handler attribute containing configuration</param>
|
|
||||||
/// <param name="filters">Optional array of filters to apply</param>
|
|
||||||
/// <param name="stateKeepFilter">Optional state keeping filter</param>
|
|
||||||
/// <param name="instanceFactory">Factory for creating handler instances</param>
|
|
||||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="instanceFactory"/> is null</exception>
|
|
||||||
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateHandlerAttributeBase pollingHandlerAttribute, IFilter<Update>[]? filters, IFilter<Update>? stateKeepFilter, Func<UpdateHandlerBase> instanceFactory)
|
|
||||||
{
|
|
||||||
Type = type;
|
|
||||||
HandlerType = handlerType;
|
|
||||||
UpdateType = pollingHandlerAttribute.Type;
|
|
||||||
Indexer = pollingHandlerAttribute.GetIndexer();
|
|
||||||
Filters = new DescriptorFiltersSet(pollingHandlerAttribute, stateKeepFilter, filters);
|
|
||||||
InstanceFactory = instanceFactory ?? throw new ArgumentNullException(nameof(instanceFactory));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with polling handler attribute, filters, service key, and instance factory.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The type of the descriptor</param>
|
|
||||||
/// <param name="handlerType">The type of the handler</param>
|
|
||||||
/// <param name="pollingHandlerAttribute">The polling handler attribute containing configuration</param>
|
|
||||||
/// <param name="filters">Optional array of filters to apply</param>
|
|
||||||
/// <param name="stateKeepFilter">Optional state keeping filter</param>
|
|
||||||
/// <param name="serviceKey">The service key for dependency injection</param>
|
|
||||||
/// <param name="instanceFactory">Factory for creating handler instances</param>
|
|
||||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="serviceKey"/> or <paramref name="instanceFactory"/> is null</exception>
|
|
||||||
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateHandlerAttributeBase pollingHandlerAttribute, IFilter<Update>[]? filters, IFilter<Update>? stateKeepFilter, object serviceKey, Func<UpdateHandlerBase> instanceFactory)
|
|
||||||
{
|
|
||||||
Type = type;
|
|
||||||
HandlerType = handlerType;
|
|
||||||
UpdateType = pollingHandlerAttribute.Type;
|
|
||||||
Indexer = pollingHandlerAttribute.GetIndexer();
|
|
||||||
Filters = new DescriptorFiltersSet(pollingHandlerAttribute, stateKeepFilter, filters);
|
|
||||||
ServiceKey = serviceKey ?? throw new ArgumentNullException(nameof(serviceKey));
|
|
||||||
InstanceFactory = instanceFactory ?? throw new ArgumentNullException(nameof(instanceFactory));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with validation filter support.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The type of the descriptor</param>
|
|
||||||
/// <param name="handlerType">The type of the handler</param>
|
|
||||||
/// <param name="updateType">The type of update this handler processes</param>
|
|
||||||
/// <param name="indexer">The indexer for handler concurrency and priority</param>
|
|
||||||
/// <param name="validateFilter">Optional validation filter</param>
|
|
||||||
/// <param name="filters">Optional array of filters to apply</param>
|
|
||||||
/// <param name="stateKeepFilter">Optional state keeping filter</param>
|
|
||||||
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateType updateType, DescriptorIndexer indexer, IFilter<Update>? validateFilter, IFilter<Update>[]? filters, IFilter<Update>? stateKeepFilter)
|
|
||||||
{
|
|
||||||
Type = type;
|
|
||||||
HandlerType = handlerType;
|
|
||||||
UpdateType = updateType;
|
|
||||||
Indexer = indexer;
|
|
||||||
Filters = new DescriptorFiltersSet(validateFilter, stateKeepFilter, filters);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with validation filter and singleton instance support.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The type of the descriptor</param>
|
|
||||||
/// <param name="handlerType">The type of the handler</param>
|
|
||||||
/// <param name="updateType">The type of update this handler processes</param>
|
|
||||||
/// <param name="indexer">The indexer for handler concurrency and priority</param>
|
|
||||||
/// <param name="validateFilter">Optional validation filter</param>
|
|
||||||
/// <param name="filters">Optional array of filters to apply</param>
|
|
||||||
/// <param name="stateKeepFilter">Optional state keeping filter</param>
|
|
||||||
/// <param name="serviceKey">The service key for dependency injection</param>
|
|
||||||
/// <param name="singletonInstance">The singleton instance of the handler</param>
|
|
||||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="serviceKey"/> or <paramref name="singletonInstance"/> is null</exception>
|
|
||||||
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateType updateType, DescriptorIndexer indexer, IFilter<Update>? validateFilter, IFilter<Update>[]? filters, IFilter<Update>? stateKeepFilter, object serviceKey, UpdateHandlerBase singletonInstance)
|
|
||||||
{
|
|
||||||
Type = type;
|
|
||||||
HandlerType = handlerType;
|
|
||||||
UpdateType = updateType;
|
|
||||||
Indexer = indexer;
|
|
||||||
Filters = new DescriptorFiltersSet(validateFilter, stateKeepFilter, filters);
|
|
||||||
ServiceKey = serviceKey ?? throw new ArgumentNullException(nameof(serviceKey));
|
|
||||||
SingletonInstance = singletonInstance ?? throw new ArgumentNullException(nameof(singletonInstance));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with validation filter and instance factory support.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The type of the descriptor</param>
|
|
||||||
/// <param name="handlerType">The type of the handler</param>
|
|
||||||
/// <param name="updateType">The type of update this handler processes</param>
|
|
||||||
/// <param name="indexer">The indexer for handler concurrency and priority</param>
|
|
||||||
/// <param name="validateFilter">Optional validation filter</param>
|
|
||||||
/// <param name="filters">Optional array of filters to apply</param>
|
|
||||||
/// <param name="stateKeepFilter">Optional state keeping filter</param>
|
|
||||||
/// <param name="instanceFactory">Factory for creating handler instances</param>
|
|
||||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="instanceFactory"/> is null</exception>
|
|
||||||
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateType updateType, DescriptorIndexer indexer, IFilter<Update>? validateFilter, IFilter<Update>[]? filters, IFilter<Update>? stateKeepFilter, Func<UpdateHandlerBase> instanceFactory)
|
|
||||||
{
|
|
||||||
Type = type;
|
|
||||||
HandlerType = handlerType;
|
|
||||||
UpdateType = updateType;
|
|
||||||
Indexer = indexer;
|
|
||||||
Filters = new DescriptorFiltersSet(validateFilter, stateKeepFilter, filters);
|
|
||||||
InstanceFactory = instanceFactory ?? throw new ArgumentNullException(nameof(instanceFactory));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with validation filter, service key, and instance factory support.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The type of the descriptor</param>
|
|
||||||
/// <param name="handlerType">The type of the handler</param>
|
|
||||||
/// <param name="updateType">The type of update this handler processes</param>
|
|
||||||
/// <param name="indexer">The indexer for handler concurrency and priority</param>
|
|
||||||
/// <param name="validateFilter">Optional validation filter</param>
|
|
||||||
/// <param name="filters">Optional array of filters to apply</param>
|
|
||||||
/// <param name="stateKeepFilter">Optional state keeping filter</param>
|
|
||||||
/// <param name="serviceKey">The service key for dependency injection</param>
|
|
||||||
/// <param name="instanceFactory">Factory for creating handler instances</param>
|
|
||||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="serviceKey"/> or <paramref name="instanceFactory"/> is null</exception>
|
|
||||||
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateType updateType, DescriptorIndexer indexer, IFilter<Update>? validateFilter, IFilter<Update>[]? filters, IFilter<Update>? stateKeepFilter, object serviceKey, Func<UpdateHandlerBase> instanceFactory)
|
|
||||||
{
|
|
||||||
Type = type;
|
|
||||||
HandlerType = handlerType;
|
|
||||||
UpdateType = updateType;
|
|
||||||
Indexer = indexer;
|
|
||||||
Filters = new DescriptorFiltersSet(validateFilter, stateKeepFilter, filters);
|
|
||||||
ServiceKey = serviceKey ?? throw new ArgumentNullException(nameof(serviceKey));
|
|
||||||
InstanceFactory = instanceFactory ?? throw new ArgumentNullException(nameof(instanceFactory));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets singleton instance of this descriptor
|
|
||||||
/// Throws exception if instance already set
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="instance"></param>
|
|
||||||
/// <exception cref="Exception"></exception>
|
|
||||||
public void SetInstance(UpdateHandlerBase instance)
|
|
||||||
{
|
|
||||||
if (SingletonInstance != null)
|
|
||||||
throw new Exception();
|
|
||||||
|
|
||||||
SingletonInstance = instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tries to set singleton instance of this descriptor
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="instance"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool TrySetInstance(UpdateHandlerBase instance)
|
|
||||||
{
|
|
||||||
if (SingletonInstance != null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SingletonInstance = instance;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override string ToString()
|
|
||||||
=> DisplayString ?? HandlerType.Name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The update type handled by this handler.
|
||||||
|
/// </summary>
|
||||||
|
public UpdateType UpdateType
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
protected set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The indexer for handler concurrency and priority.
|
||||||
|
/// </summary>
|
||||||
|
public DescriptorIndexer Indexer
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether to form a fallback report.
|
||||||
|
/// </summary>
|
||||||
|
public bool FormReport
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The set of filters associated with this handler.
|
||||||
|
/// </summary>
|
||||||
|
public DescriptorFiltersSet? Filters
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
protected set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the aspects configuration for this handler.
|
||||||
|
/// Contains pre and post-execution processors if the handler uses the aspect system.
|
||||||
|
/// </summary>
|
||||||
|
public DescriptorAspectsSet? Aspects
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
protected set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The service key for keyed handlers.
|
||||||
|
/// </summary>
|
||||||
|
public object? ServiceKey
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
protected set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Factory for creating handler instances.
|
||||||
|
/// </summary>
|
||||||
|
public Func<UpdateHandlerBase>? InstanceFactory
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
protected set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Singleton instance of the handler, if applicable.
|
||||||
|
/// </summary>
|
||||||
|
public UpdateHandlerBase? SingletonInstance
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
protected set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Display string for the handler (for debugging or logging).
|
||||||
|
/// </summary>
|
||||||
|
public string? DisplayString
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a function for 'lazy' handlers initialization
|
||||||
|
/// </summary>
|
||||||
|
public Action<UpdateHandlerBase>? LazyInitialization
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with the specified descriptor type and handler type.
|
||||||
|
/// Automatically inspects the handler type to extract attributes, filters, and configuration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="descriptorType">The type of the descriptor</param>
|
||||||
|
/// <param name="handlerType">The type of the handler to describe</param>
|
||||||
|
/// <param name="dontInspect"></param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown when the handler type is not compatible with the expected handler type</exception>
|
||||||
|
public HandlerDescriptor(DescriptorType descriptorType, Type handlerType, bool dontInspect = false)
|
||||||
|
{
|
||||||
|
Type = descriptorType;
|
||||||
|
HandlerType = handlerType;
|
||||||
|
Filters = new DescriptorFiltersSet(null, null, null);
|
||||||
|
|
||||||
|
if (dontInspect)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UpdateHandlerAttributeBase handlerAttribute = HandlerInspector.GetHandlerAttribute(handlerType);
|
||||||
|
if (handlerAttribute.ExpectingHandlerType != null && !handlerAttribute.ExpectingHandlerType.Contains(handlerType.BaseType))
|
||||||
|
throw new ArgumentException(string.Format("This handler attribute cannot be attached to this class. Attribute can be attached on next handlers : {0}", string.Join(", ", handlerAttribute.ExpectingHandlerType.AsEnumerable())));
|
||||||
|
|
||||||
|
IFilter<Update>? stateKeeperAttribute = HandlerInspector.GetStateKeeperAttribute(handlerType);
|
||||||
|
IFilter<Update>[] filters = HandlerInspector.GetFilterAttributes(handlerType, handlerAttribute.Type).ToArray();
|
||||||
|
|
||||||
|
UpdateType = handlerAttribute.Type;
|
||||||
|
Indexer = handlerAttribute.GetIndexer();
|
||||||
|
FormReport = handlerAttribute.FormReport;
|
||||||
|
Filters = new DescriptorFiltersSet(handlerAttribute, stateKeeperAttribute, filters);
|
||||||
|
Aspects = HandlerInspector.GetAspects(handlerType);
|
||||||
|
DisplayString = HandlerInspector.GetDisplayName(handlerType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class as a keyed handler with the specified service key.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handlerType">The type of the handler to describe</param>
|
||||||
|
/// <param name="serviceKey">The service key for dependency injection</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="serviceKey"/> is null</exception>
|
||||||
|
public HandlerDescriptor(Type handlerType, object serviceKey) : this(DescriptorType.Keyed, handlerType)
|
||||||
|
{
|
||||||
|
ServiceKey = serviceKey ?? throw new ArgumentNullException(nameof(serviceKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with all basic properties.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type of the descriptor</param>
|
||||||
|
/// <param name="handlerType">The type of the handler</param>
|
||||||
|
/// <param name="updateType">The type of update this handler processes</param>
|
||||||
|
/// <param name="indexer">The indexer for handler concurrency and priority</param>
|
||||||
|
/// <param name="filters">The set of filters associated with this handler</param>
|
||||||
|
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateType updateType, DescriptorIndexer indexer, DescriptorFiltersSet filters)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
HandlerType = handlerType;
|
||||||
|
UpdateType = updateType;
|
||||||
|
Indexer = indexer;
|
||||||
|
Filters = filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with singleton instance support.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type of the descriptor</param>
|
||||||
|
/// <param name="handlerType">The type of the handler</param>
|
||||||
|
/// <param name="updateType">The type of update this handler processes</param>
|
||||||
|
/// <param name="indexer">The indexer for handler concurrency and priority</param>
|
||||||
|
/// <param name="filters">The set of filters associated with this handler</param>
|
||||||
|
/// <param name="serviceKey">The service key for dependency injection</param>
|
||||||
|
/// <param name="singletonInstance">The singleton instance of the handler</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="serviceKey"/> or <paramref name="singletonInstance"/> is null</exception>
|
||||||
|
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateType updateType, DescriptorIndexer indexer, DescriptorFiltersSet filters, object serviceKey, UpdateHandlerBase singletonInstance)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
HandlerType = handlerType;
|
||||||
|
UpdateType = updateType;
|
||||||
|
Indexer = indexer;
|
||||||
|
Filters = filters;
|
||||||
|
ServiceKey = serviceKey ?? throw new ArgumentNullException(nameof(serviceKey));
|
||||||
|
SingletonInstance = singletonInstance ?? throw new ArgumentNullException(nameof(singletonInstance));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with instance factory support.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type of the descriptor</param>
|
||||||
|
/// <param name="handlerType">The type of the handler</param>
|
||||||
|
/// <param name="updateType">The type of update this handler processes</param>
|
||||||
|
/// <param name="indexer">The indexer for handler concurrency and priority</param>
|
||||||
|
/// <param name="filters">The set of filters associated with this handler</param>
|
||||||
|
/// <param name="instanceFactory">Factory for creating handler instances</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="instanceFactory"/> is null</exception>
|
||||||
|
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateType updateType, DescriptorIndexer indexer, DescriptorFiltersSet filters, Func<UpdateHandlerBase> instanceFactory)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
HandlerType = handlerType;
|
||||||
|
UpdateType = updateType;
|
||||||
|
Indexer = indexer;
|
||||||
|
Filters = filters;
|
||||||
|
InstanceFactory = instanceFactory ?? throw new ArgumentNullException(nameof(instanceFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with service key and instance factory support.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type of the descriptor</param>
|
||||||
|
/// <param name="handlerType">The type of the handler</param>
|
||||||
|
/// <param name="updateType">The type of update this handler processes</param>
|
||||||
|
/// <param name="indexer">The indexer for handler concurrency and priority</param>
|
||||||
|
/// <param name="filters">The set of filters associated with this handler</param>
|
||||||
|
/// <param name="serviceKey">The service key for dependency injection</param>
|
||||||
|
/// <param name="instanceFactory">Factory for creating handler instances</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="serviceKey"/> or <paramref name="instanceFactory"/> is null</exception>
|
||||||
|
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateType updateType, DescriptorIndexer indexer, DescriptorFiltersSet filters, object serviceKey, Func<UpdateHandlerBase> instanceFactory)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
HandlerType = handlerType;
|
||||||
|
UpdateType = updateType;
|
||||||
|
Indexer = indexer;
|
||||||
|
Filters = filters;
|
||||||
|
ServiceKey = serviceKey ?? throw new ArgumentNullException(nameof(serviceKey));
|
||||||
|
InstanceFactory = instanceFactory ?? throw new ArgumentNullException(nameof(instanceFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with polling handler attribute and filters.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type of the descriptor</param>
|
||||||
|
/// <param name="handlerType">The type of the handler</param>
|
||||||
|
/// <param name="pollingHandlerAttribute">The polling handler attribute containing configuration</param>
|
||||||
|
/// <param name="filters">Optional array of filters to apply</param>
|
||||||
|
/// <param name="stateKeepFilter">Optional state keeping filter</param>
|
||||||
|
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateHandlerAttributeBase pollingHandlerAttribute, IFilter<Update>[]? filters, IFilter<Update>? stateKeepFilter)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
HandlerType = handlerType;
|
||||||
|
UpdateType = pollingHandlerAttribute.Type;
|
||||||
|
Indexer = pollingHandlerAttribute.GetIndexer();
|
||||||
|
Filters = new DescriptorFiltersSet(pollingHandlerAttribute, stateKeepFilter, filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with polling handler attribute, filters, and singleton instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type of the descriptor</param>
|
||||||
|
/// <param name="handlerType">The type of the handler</param>
|
||||||
|
/// <param name="pollingHandlerAttribute">The polling handler attribute containing configuration</param>
|
||||||
|
/// <param name="filters">Optional array of filters to apply</param>
|
||||||
|
/// <param name="stateKeepFilter">Optional state keeping filter</param>
|
||||||
|
/// <param name="serviceKey">The service key for dependency injection</param>
|
||||||
|
/// <param name="singletonInstance">The singleton instance of the handler</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="serviceKey"/> or <paramref name="singletonInstance"/> is null</exception>
|
||||||
|
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateHandlerAttributeBase pollingHandlerAttribute, IFilter<Update>[]? filters, IFilter<Update>? stateKeepFilter, object serviceKey, UpdateHandlerBase singletonInstance)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
HandlerType = handlerType;
|
||||||
|
UpdateType = pollingHandlerAttribute.Type;
|
||||||
|
Indexer = pollingHandlerAttribute.GetIndexer();
|
||||||
|
Filters = new DescriptorFiltersSet(pollingHandlerAttribute, stateKeepFilter, filters);
|
||||||
|
ServiceKey = serviceKey ?? throw new ArgumentNullException(nameof(serviceKey));
|
||||||
|
SingletonInstance = singletonInstance ?? throw new ArgumentNullException(nameof(singletonInstance));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with polling handler attribute, filters, and instance factory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type of the descriptor</param>
|
||||||
|
/// <param name="handlerType">The type of the handler</param>
|
||||||
|
/// <param name="pollingHandlerAttribute">The polling handler attribute containing configuration</param>
|
||||||
|
/// <param name="filters">Optional array of filters to apply</param>
|
||||||
|
/// <param name="stateKeepFilter">Optional state keeping filter</param>
|
||||||
|
/// <param name="instanceFactory">Factory for creating handler instances</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="instanceFactory"/> is null</exception>
|
||||||
|
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateHandlerAttributeBase pollingHandlerAttribute, IFilter<Update>[]? filters, IFilter<Update>? stateKeepFilter, Func<UpdateHandlerBase> instanceFactory)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
HandlerType = handlerType;
|
||||||
|
UpdateType = pollingHandlerAttribute.Type;
|
||||||
|
Indexer = pollingHandlerAttribute.GetIndexer();
|
||||||
|
Filters = new DescriptorFiltersSet(pollingHandlerAttribute, stateKeepFilter, filters);
|
||||||
|
InstanceFactory = instanceFactory ?? throw new ArgumentNullException(nameof(instanceFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with polling handler attribute, filters, service key, and instance factory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type of the descriptor</param>
|
||||||
|
/// <param name="handlerType">The type of the handler</param>
|
||||||
|
/// <param name="pollingHandlerAttribute">The polling handler attribute containing configuration</param>
|
||||||
|
/// <param name="filters">Optional array of filters to apply</param>
|
||||||
|
/// <param name="stateKeepFilter">Optional state keeping filter</param>
|
||||||
|
/// <param name="serviceKey">The service key for dependency injection</param>
|
||||||
|
/// <param name="instanceFactory">Factory for creating handler instances</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="serviceKey"/> or <paramref name="instanceFactory"/> is null</exception>
|
||||||
|
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateHandlerAttributeBase pollingHandlerAttribute, IFilter<Update>[]? filters, IFilter<Update>? stateKeepFilter, object serviceKey, Func<UpdateHandlerBase> instanceFactory)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
HandlerType = handlerType;
|
||||||
|
UpdateType = pollingHandlerAttribute.Type;
|
||||||
|
Indexer = pollingHandlerAttribute.GetIndexer();
|
||||||
|
Filters = new DescriptorFiltersSet(pollingHandlerAttribute, stateKeepFilter, filters);
|
||||||
|
ServiceKey = serviceKey ?? throw new ArgumentNullException(nameof(serviceKey));
|
||||||
|
InstanceFactory = instanceFactory ?? throw new ArgumentNullException(nameof(instanceFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with validation filter support.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type of the descriptor</param>
|
||||||
|
/// <param name="handlerType">The type of the handler</param>
|
||||||
|
/// <param name="updateType">The type of update this handler processes</param>
|
||||||
|
/// <param name="indexer">The indexer for handler concurrency and priority</param>
|
||||||
|
/// <param name="validateFilter">Optional validation filter</param>
|
||||||
|
/// <param name="filters">Optional array of filters to apply</param>
|
||||||
|
/// <param name="stateKeepFilter">Optional state keeping filter</param>
|
||||||
|
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateType updateType, DescriptorIndexer indexer, IFilter<Update>? validateFilter, IFilter<Update>[]? filters, IFilter<Update>? stateKeepFilter)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
HandlerType = handlerType;
|
||||||
|
UpdateType = updateType;
|
||||||
|
Indexer = indexer;
|
||||||
|
Filters = new DescriptorFiltersSet(validateFilter, stateKeepFilter, filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with validation filter and singleton instance support.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type of the descriptor</param>
|
||||||
|
/// <param name="handlerType">The type of the handler</param>
|
||||||
|
/// <param name="updateType">The type of update this handler processes</param>
|
||||||
|
/// <param name="indexer">The indexer for handler concurrency and priority</param>
|
||||||
|
/// <param name="validateFilter">Optional validation filter</param>
|
||||||
|
/// <param name="filters">Optional array of filters to apply</param>
|
||||||
|
/// <param name="stateKeepFilter">Optional state keeping filter</param>
|
||||||
|
/// <param name="serviceKey">The service key for dependency injection</param>
|
||||||
|
/// <param name="singletonInstance">The singleton instance of the handler</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="serviceKey"/> or <paramref name="singletonInstance"/> is null</exception>
|
||||||
|
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateType updateType, DescriptorIndexer indexer, IFilter<Update>? validateFilter, IFilter<Update>[]? filters, IFilter<Update>? stateKeepFilter, object serviceKey, UpdateHandlerBase singletonInstance)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
HandlerType = handlerType;
|
||||||
|
UpdateType = updateType;
|
||||||
|
Indexer = indexer;
|
||||||
|
Filters = new DescriptorFiltersSet(validateFilter, stateKeepFilter, filters);
|
||||||
|
ServiceKey = serviceKey ?? throw new ArgumentNullException(nameof(serviceKey));
|
||||||
|
SingletonInstance = singletonInstance ?? throw new ArgumentNullException(nameof(singletonInstance));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with validation filter and instance factory support.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type of the descriptor</param>
|
||||||
|
/// <param name="handlerType">The type of the handler</param>
|
||||||
|
/// <param name="updateType">The type of update this handler processes</param>
|
||||||
|
/// <param name="indexer">The indexer for handler concurrency and priority</param>
|
||||||
|
/// <param name="validateFilter">Optional validation filter</param>
|
||||||
|
/// <param name="filters">Optional array of filters to apply</param>
|
||||||
|
/// <param name="stateKeepFilter">Optional state keeping filter</param>
|
||||||
|
/// <param name="instanceFactory">Factory for creating handler instances</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="instanceFactory"/> is null</exception>
|
||||||
|
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateType updateType, DescriptorIndexer indexer, IFilter<Update>? validateFilter, IFilter<Update>[]? filters, IFilter<Update>? stateKeepFilter, Func<UpdateHandlerBase> instanceFactory)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
HandlerType = handlerType;
|
||||||
|
UpdateType = updateType;
|
||||||
|
Indexer = indexer;
|
||||||
|
Filters = new DescriptorFiltersSet(validateFilter, stateKeepFilter, filters);
|
||||||
|
InstanceFactory = instanceFactory ?? throw new ArgumentNullException(nameof(instanceFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HandlerDescriptor"/> class with validation filter, service key, and instance factory support.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type of the descriptor</param>
|
||||||
|
/// <param name="handlerType">The type of the handler</param>
|
||||||
|
/// <param name="updateType">The type of update this handler processes</param>
|
||||||
|
/// <param name="indexer">The indexer for handler concurrency and priority</param>
|
||||||
|
/// <param name="validateFilter">Optional validation filter</param>
|
||||||
|
/// <param name="filters">Optional array of filters to apply</param>
|
||||||
|
/// <param name="stateKeepFilter">Optional state keeping filter</param>
|
||||||
|
/// <param name="serviceKey">The service key for dependency injection</param>
|
||||||
|
/// <param name="instanceFactory">Factory for creating handler instances</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="serviceKey"/> or <paramref name="instanceFactory"/> is null</exception>
|
||||||
|
public HandlerDescriptor(DescriptorType type, Type handlerType, UpdateType updateType, DescriptorIndexer indexer, IFilter<Update>? validateFilter, IFilter<Update>[]? filters, IFilter<Update>? stateKeepFilter, object serviceKey, Func<UpdateHandlerBase> instanceFactory)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
HandlerType = handlerType;
|
||||||
|
UpdateType = updateType;
|
||||||
|
Indexer = indexer;
|
||||||
|
Filters = new DescriptorFiltersSet(validateFilter, stateKeepFilter, filters);
|
||||||
|
ServiceKey = serviceKey ?? throw new ArgumentNullException(nameof(serviceKey));
|
||||||
|
InstanceFactory = instanceFactory ?? throw new ArgumentNullException(nameof(instanceFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets singleton instance of this descriptor
|
||||||
|
/// Throws exception if instance already set
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="instance"></param>
|
||||||
|
/// <exception cref="Exception"></exception>
|
||||||
|
public void SetInstance(UpdateHandlerBase instance)
|
||||||
|
{
|
||||||
|
if (SingletonInstance != null)
|
||||||
|
throw new Exception();
|
||||||
|
|
||||||
|
SingletonInstance = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to set singleton instance of this descriptor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="instance"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool TrySetInstance(UpdateHandlerBase instance)
|
||||||
|
{
|
||||||
|
if (SingletonInstance != null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SingletonInstance = instance;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string ToString()
|
||||||
|
=> DisplayString ?? HandlerType.Name;
|
||||||
}
|
}
|
||||||
@@ -2,158 +2,157 @@
|
|||||||
using Telegram.Bot.Types;
|
using Telegram.Bot.Types;
|
||||||
using Telegram.Bot.Types.Enums;
|
using Telegram.Bot.Types.Enums;
|
||||||
|
|
||||||
namespace Telegrator.Core.Descriptors
|
namespace Telegrator.Core.Descriptors;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The collection containing the <see cref="HandlerDescriptor"/>'s. Used to route <see cref="Update"/>'s in <see cref="IHandlersProvider"/>
|
||||||
|
/// </summary>
|
||||||
|
public sealed class HandlerDescriptorList : IEnumerable<HandlerDescriptor>
|
||||||
{
|
{
|
||||||
|
private readonly object _lock = new object();
|
||||||
|
private readonly SortedList<DescriptorIndexer, HandlerDescriptor> _innerCollection;
|
||||||
|
private readonly TelegratorOptions? _options;
|
||||||
|
private readonly UpdateType _handlingType;
|
||||||
|
|
||||||
|
private int count;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The collection containing the <see cref="HandlerDescriptor"/>'s. Used to route <see cref="Update"/>'s in <see cref="IHandlersProvider"/>
|
/// Gets a value indicating whether the collection is read-only.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class HandlerDescriptorList : IEnumerable<HandlerDescriptor>
|
public bool IsReadOnly { get; private set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="UpdateType"/> of handlers in this collection.
|
||||||
|
/// </summary>
|
||||||
|
public UpdateType HandlingType => _handlingType;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets count of registered handlers in list
|
||||||
|
/// </summary>
|
||||||
|
public int Count => _innerCollection.Count;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="HandlerDescriptor"/> at the specified index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public HandlerDescriptor this[int index]
|
||||||
{
|
{
|
||||||
private readonly object _lock = new object();
|
get => _innerCollection.Values[index];
|
||||||
private readonly SortedList<DescriptorIndexer, HandlerDescriptor> _innerCollection;
|
set => _innerCollection.Values[index] = value;
|
||||||
private readonly TelegratorOptions? _options;
|
}
|
||||||
private readonly UpdateType _handlingType;
|
|
||||||
|
|
||||||
private int count;
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HandlerDescriptorList"/> class without a specific <see cref="UpdateType"/>.
|
||||||
|
/// </summary>
|
||||||
|
public HandlerDescriptorList()
|
||||||
|
: this(UpdateType.Unknown, default) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the collection is read-only.
|
/// Initializes a new instance of the <see cref="HandlerDescriptorList"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsReadOnly { get; private set; } = false;
|
/// <param name="updateType">The update type for the handlers.</param>
|
||||||
|
/// <param name="options">The collecting options.</param>
|
||||||
|
public HandlerDescriptorList(UpdateType updateType, TelegratorOptions? options)
|
||||||
|
{
|
||||||
|
_innerCollection = [];
|
||||||
|
_handlingType = updateType;
|
||||||
|
_options = options;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="UpdateType"/> of handlers in this collection.
|
/// Adds a new <see cref="HandlerDescriptor"/> to the collection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public UpdateType HandlingType => _handlingType;
|
/// <param name="descriptor">The handler descriptor to add.</param>
|
||||||
|
/// <exception cref="CollectionFrozenException">Thrown if the collection is frozen.</exception>
|
||||||
/// <summary>
|
/// <exception cref="InvalidOperationException">Thrown if the update type does not match.</exception>
|
||||||
/// Gets count of registered handlers in list
|
public void Add(HandlerDescriptor descriptor)
|
||||||
/// </summary>
|
{
|
||||||
public int Count => _innerCollection.Count;
|
lock (_lock)
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the <see cref="HandlerDescriptor"/> at the specified index.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="index"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public HandlerDescriptor this[int index]
|
|
||||||
{
|
{
|
||||||
get => _innerCollection.Values[index];
|
if (IsReadOnly)
|
||||||
set => _innerCollection.Values[index] = value;
|
throw new CollectionFrozenException();
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
if (_handlingType != UpdateType.Unknown && descriptor.UpdateType != _handlingType)
|
||||||
/// Initializes a new instance of the <see cref="HandlerDescriptorList"/> class without a specific <see cref="UpdateType"/>.
|
throw new InvalidOperationException();
|
||||||
/// </summary>
|
|
||||||
public HandlerDescriptorList()
|
|
||||||
: this(UpdateType.Unknown, default) { }
|
|
||||||
|
|
||||||
/// <summary>
|
descriptor.Indexer = descriptor.Indexer.UpdateIndex(count++);
|
||||||
/// Initializes a new instance of the <see cref="HandlerDescriptorList"/> class.
|
_innerCollection.Add(descriptor.Indexer, descriptor);
|
||||||
/// </summary>
|
|
||||||
/// <param name="updateType">The update type for the handlers.</param>
|
|
||||||
/// <param name="options">The collecting options.</param>
|
|
||||||
public HandlerDescriptorList(UpdateType updateType, TelegratorOptions? options)
|
|
||||||
{
|
|
||||||
_innerCollection = [];
|
|
||||||
_handlingType = updateType;
|
|
||||||
_options = options;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
if (_handlingType == UpdateType.InlineQuery)
|
||||||
/// Adds a new <see cref="HandlerDescriptor"/> to the collection.
|
IsReadOnly = true;
|
||||||
/// </summary>
|
|
||||||
/// <param name="descriptor">The handler descriptor to add.</param>
|
|
||||||
/// <exception cref="CollectionFrozenException">Thrown if the collection is frozen.</exception>
|
|
||||||
/// <exception cref="InvalidOperationException">Thrown if the update type does not match.</exception>
|
|
||||||
public void Add(HandlerDescriptor descriptor)
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
if (IsReadOnly)
|
|
||||||
throw new CollectionFrozenException();
|
|
||||||
|
|
||||||
if (_handlingType != UpdateType.Unknown && descriptor.UpdateType != _handlingType)
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
|
|
||||||
descriptor.Indexer = descriptor.Indexer.UpdateIndex(count++);
|
|
||||||
_innerCollection.Add(descriptor.Indexer, descriptor);
|
|
||||||
|
|
||||||
if (_handlingType == UpdateType.InlineQuery)
|
|
||||||
IsReadOnly = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the collection contains a <see cref="HandlerDescriptor"/> with the specified <see cref="DescriptorIndexer"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="indexer">The descriptor indexer.</param>
|
|
||||||
/// <returns>True if the descriptor exists; otherwise, false.</returns>
|
|
||||||
public bool ContainsKey(DescriptorIndexer indexer)
|
|
||||||
{
|
|
||||||
return _innerCollection.ContainsKey(indexer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the <see cref="HandlerDescriptor"/> with the specified <see cref="DescriptorIndexer"/> from the collection.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="indexer">The descriptor indexer.</param>
|
|
||||||
/// <returns>True if the descriptor was removed; otherwise, false.</returns>
|
|
||||||
public bool Remove(DescriptorIndexer indexer)
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
return _innerCollection.Remove(indexer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the <see cref="HandlerDescriptor"/> from the collection.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="descriptor"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool Remove(HandlerDescriptor descriptor)
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
int index = _innerCollection.IndexOfValue(descriptor);
|
|
||||||
if (index == -1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
_innerCollection.RemoveAt(index);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes all descriptos from the <see cref="HandlerDescriptorList"/>
|
|
||||||
/// </summary>
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
_innerCollection.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Freezes the <see cref="HandlerDescriptorList"/> and prohibits adding new elements to it.
|
|
||||||
/// </summary>
|
|
||||||
public void Freeze()
|
|
||||||
{
|
|
||||||
IsReadOnly = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public IEnumerator<HandlerDescriptor> GetEnumerator()
|
|
||||||
{
|
|
||||||
return _innerCollection.Values.GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return _innerCollection.Values.GetEnumerator();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the collection contains a <see cref="HandlerDescriptor"/> with the specified <see cref="DescriptorIndexer"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="indexer">The descriptor indexer.</param>
|
||||||
|
/// <returns>True if the descriptor exists; otherwise, false.</returns>
|
||||||
|
public bool ContainsKey(DescriptorIndexer indexer)
|
||||||
|
{
|
||||||
|
return _innerCollection.ContainsKey(indexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the <see cref="HandlerDescriptor"/> with the specified <see cref="DescriptorIndexer"/> from the collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="indexer">The descriptor indexer.</param>
|
||||||
|
/// <returns>True if the descriptor was removed; otherwise, false.</returns>
|
||||||
|
public bool Remove(DescriptorIndexer indexer)
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
return _innerCollection.Remove(indexer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the <see cref="HandlerDescriptor"/> from the collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="descriptor"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool Remove(HandlerDescriptor descriptor)
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
int index = _innerCollection.IndexOfValue(descriptor);
|
||||||
|
if (index == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_innerCollection.RemoveAt(index);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes all descriptos from the <see cref="HandlerDescriptorList"/>
|
||||||
|
/// </summary>
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
_innerCollection.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Freezes the <see cref="HandlerDescriptorList"/> and prohibits adding new elements to it.
|
||||||
|
/// </summary>
|
||||||
|
public void Freeze()
|
||||||
|
{
|
||||||
|
IsReadOnly = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IEnumerator<HandlerDescriptor> GetEnumerator()
|
||||||
|
{
|
||||||
|
return _innerCollection.Values.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return _innerCollection.Values.GetEnumerator();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,93 +7,92 @@ using Telegrator.Aspects;
|
|||||||
using Telegrator.Core.Attributes;
|
using Telegrator.Core.Attributes;
|
||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Core.Descriptors
|
namespace Telegrator.Core.Descriptors;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides methods for inspecting handler types and retrieving their attributes and filters.
|
||||||
|
/// </summary>
|
||||||
|
public static class HandlerInspector
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides methods for inspecting handler types and retrieving their attributes and filters.
|
/// Gets handler's display name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class HandlerInspector
|
/// <param name="handlerType"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string? GetDisplayName(MemberInfo handlerType)
|
||||||
{
|
{
|
||||||
/// <summary>
|
return handlerType.GetCustomAttribute<DisplayNameAttribute>()?.DisplayName;
|
||||||
/// Gets handler's display name
|
}
|
||||||
/// </summary>
|
|
||||||
/// <param name="handlerType"></param>
|
/// <summary>
|
||||||
/// <returns></returns>
|
/// Gets the handler attribute from the specified member info.
|
||||||
public static string? GetDisplayName(MemberInfo handlerType)
|
/// </summary>
|
||||||
|
/// <param name="handlerType">The member info representing the handler type.</param>
|
||||||
|
/// <returns>The handler attribute.</returns>
|
||||||
|
public static UpdateHandlerAttributeBase GetHandlerAttribute(MemberInfo handlerType)
|
||||||
|
{
|
||||||
|
// Getting polling handler attribute
|
||||||
|
IEnumerable<UpdateHandlerAttributeBase> handlerAttrs = handlerType.GetCustomAttributes<UpdateHandlerAttributeBase>();
|
||||||
|
|
||||||
|
//
|
||||||
|
return handlerAttrs.Single();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the state keeper attribute from the specified member info, if present.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handlerType">The member info representing the handler type.</param>
|
||||||
|
/// <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<,>));
|
||||||
|
|
||||||
|
//
|
||||||
|
return stateAttr as IFilter<Update>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all filter attributes for the specified handler type and update type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handlerType">The member info representing the handler type.</param>
|
||||||
|
/// <param name="validUpdType">The valid update type.</param>
|
||||||
|
/// <returns>An enumerable of filter attributes.</returns>
|
||||||
|
public static IEnumerable<IFilter<Update>> GetFilterAttributes(MemberInfo handlerType, UpdateType validUpdType)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
IEnumerable<UpdateFilterAttributeBase> filters = handlerType.GetCustomAttributes<UpdateFilterAttributeBase>();
|
||||||
|
|
||||||
|
//
|
||||||
|
if (filters.Any(filterAttr => !filterAttr.AllowedTypes.Contains(validUpdType)))
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
UpdateFilterAttributeBase? lastFilterAttribute = null;
|
||||||
|
foreach (UpdateFilterAttributeBase filterAttribute in filters)
|
||||||
{
|
{
|
||||||
return handlerType.GetCustomAttribute<DisplayNameAttribute>()?.DisplayName;
|
if (!filterAttribute.ProcessModifiers(lastFilterAttribute))
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the handler attribute from the specified member info.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handlerType">The member info representing the handler type.</param>
|
|
||||||
/// <returns>The handler attribute.</returns>
|
|
||||||
public static UpdateHandlerAttributeBase GetHandlerAttribute(MemberInfo handlerType)
|
|
||||||
{
|
|
||||||
// Getting polling handler attribute
|
|
||||||
IEnumerable<UpdateHandlerAttributeBase> handlerAttrs = handlerType.GetCustomAttributes<UpdateHandlerAttributeBase>();
|
|
||||||
|
|
||||||
//
|
|
||||||
return handlerAttrs.Single();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the state keeper attribute from the specified member info, if present.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handlerType">The member info representing the handler type.</param>
|
|
||||||
/// <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<,>));
|
|
||||||
|
|
||||||
//
|
|
||||||
return stateAttr as IFilter<Update>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets all filter attributes for the specified handler type and update type.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handlerType">The member info representing the handler type.</param>
|
|
||||||
/// <param name="validUpdType">The valid update type.</param>
|
|
||||||
/// <returns>An enumerable of filter attributes.</returns>
|
|
||||||
public static IEnumerable<IFilter<Update>> GetFilterAttributes(MemberInfo handlerType, UpdateType validUpdType)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
IEnumerable<UpdateFilterAttributeBase> filters = handlerType.GetCustomAttributes<UpdateFilterAttributeBase>();
|
|
||||||
|
|
||||||
//
|
|
||||||
if (filters.Any(filterAttr => !filterAttr.AllowedTypes.Contains(validUpdType)))
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
|
|
||||||
UpdateFilterAttributeBase? lastFilterAttribute = null;
|
|
||||||
foreach (UpdateFilterAttributeBase filterAttribute in filters)
|
|
||||||
{
|
{
|
||||||
if (!filterAttribute.ProcessModifiers(lastFilterAttribute))
|
lastFilterAttribute = null;
|
||||||
{
|
yield return filterAttribute.AnonymousFilter;
|
||||||
lastFilterAttribute = null;
|
}
|
||||||
yield return filterAttribute.AnonymousFilter;
|
else
|
||||||
}
|
{
|
||||||
else
|
lastFilterAttribute = filterAttribute;
|
||||||
{
|
continue;
|
||||||
lastFilterAttribute = filterAttribute;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the aspects configuration for the specified handler type.
|
/// Gets the aspects configuration for the specified handler type.
|
||||||
/// Inspects the handler for both self-processing (implements interfaces) and typed processing (uses attributes).
|
/// Inspects the handler for both self-processing (implements interfaces) and typed processing (uses attributes).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="handlerType">The type of the handler to inspect.</param>
|
/// <param name="handlerType">The type of the handler to inspect.</param>
|
||||||
/// <returns>A <see cref="DescriptorAspectsSet"/> containing the aspects configuration.</returns>
|
/// <returns>A <see cref="DescriptorAspectsSet"/> containing the aspects configuration.</returns>
|
||||||
public static DescriptorAspectsSet GetAspects(Type handlerType)
|
public static DescriptorAspectsSet GetAspects(Type handlerType)
|
||||||
{
|
{
|
||||||
Type? typedPre = handlerType.GetCustomAttribute(typeof(BeforeExecutionAttribute<>))?.GetType().GetGenericArguments()[0];
|
Type? typedPre = handlerType.GetCustomAttribute(typeof(BeforeExecutionAttribute<>))?.GetType().GetGenericArguments()[0];
|
||||||
Type? typedPost = handlerType.GetCustomAttribute(typeof(AfterExecutionAttribute<>))?.GetType().GetGenericArguments()[0];
|
Type? typedPost = handlerType.GetCustomAttribute(typeof(AfterExecutionAttribute<>))?.GetType().GetGenericArguments()[0];
|
||||||
return new DescriptorAspectsSet(typedPre, typedPost);
|
return new DescriptorAspectsSet(typedPre, typedPost);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,108 +2,107 @@
|
|||||||
using Telegrator.Filters;
|
using Telegrator.Filters;
|
||||||
using Telegrator.Logging;
|
using Telegrator.Logging;
|
||||||
|
|
||||||
namespace Telegrator.Core.Filters
|
namespace Telegrator.Core.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a compiled filter that applies a set of filters to an anonymous target type.
|
||||||
|
/// </summary>
|
||||||
|
public class AnonymousCompiledFilter : Filter<Update>, INamedFilter
|
||||||
{
|
{
|
||||||
|
private readonly Func<FilterExecutionContext<Update>, object, bool> FilterAction;
|
||||||
|
private readonly Func<Update, object?> GetFilterringTarget;
|
||||||
|
private readonly string _name;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a compiled filter that applies a set of filters to an anonymous target type.
|
/// Gets the name of this compiled filter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AnonymousCompiledFilter : Filter<Update>, INamedFilter
|
public virtual string Name => _name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AnonymousCompiledFilter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the compiled filter.</param>
|
||||||
|
/// <param name="filterAction">The filter action delegate.</param>
|
||||||
|
/// <param name="getFilterringTarget">The function to get the filtering target from an update.</param>
|
||||||
|
private AnonymousCompiledFilter(string name, Func<Update, object?> getFilterringTarget, Func<FilterExecutionContext<Update>, object, bool> filterAction)
|
||||||
{
|
{
|
||||||
private readonly Func<FilterExecutionContext<Update>, object, bool> FilterAction;
|
FilterAction = filterAction;
|
||||||
private readonly Func<Update, object?> GetFilterringTarget;
|
GetFilterringTarget = getFilterringTarget;
|
||||||
private readonly string _name;
|
_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the name of this compiled filter.
|
/// Compiles a set of filters into an <see cref="AnonymousCompiledFilter"/> for a specific target type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual string Name => _name;
|
/// <typeparam name="T">The type of the filtering target.</typeparam>
|
||||||
|
/// <param name="filters">The list of filters to compile.</param>
|
||||||
|
/// <param name="getFilterringTarget">The function to get the filtering target from an update.</param>
|
||||||
|
/// <returns>The compiled filter.</returns>
|
||||||
|
public static AnonymousCompiledFilter Compile<T>(IEnumerable<IFilter<T>> filters, Func<Update, object?> getFilterringTarget) where T : class
|
||||||
|
{
|
||||||
|
return new AnonymousCompiledFilter(
|
||||||
|
string.Join("+", filters.Select(fltr => fltr.GetType().Name)),
|
||||||
|
getFilterringTarget,
|
||||||
|
(context, filterringTarget) => CanPassInternal(context, filters, filterringTarget));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="AnonymousCompiledFilter"/> class.
|
/// Compiles a set of filters into an <see cref="AnonymousCompiledFilter"/> for a specific target type with a custom name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The name of the compiled filter.</param>
|
/// <typeparam name="T">The type of the filtering target.</typeparam>
|
||||||
/// <param name="filterAction">The filter action delegate.</param>
|
/// <param name="name">The custom name for the compiled filter.</param>
|
||||||
/// <param name="getFilterringTarget">The function to get the filtering target from an update.</param>
|
/// <param name="filters">The list of filters to compile.</param>
|
||||||
private AnonymousCompiledFilter(string name, Func<Update, object?> getFilterringTarget, Func<FilterExecutionContext<Update>, object, bool> filterAction)
|
/// <param name="getFilterringTarget">The function to get the filtering target from an update.</param>
|
||||||
|
/// <returns>The compiled filter.</returns>
|
||||||
|
public static AnonymousCompiledFilter Compile<T>(string name, IEnumerable<IFilter<T>> filters, Func<Update, object?> getFilterringTarget) where T : class
|
||||||
|
{
|
||||||
|
return new AnonymousCompiledFilter(
|
||||||
|
name,
|
||||||
|
getFilterringTarget,
|
||||||
|
(context, filterringTarget) => CanPassInternal(context, filters, filterringTarget));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether all filters can pass for the given context and filtering target.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the filtering target.</typeparam>
|
||||||
|
/// <param name="filters">The list of filters.</param>
|
||||||
|
/// <param name="updateContext">The filter execution context.</param>
|
||||||
|
/// <param name="filterringTarget">The filtering target.</param>
|
||||||
|
/// <returns>True if all filters pass; otherwise, false.</returns>
|
||||||
|
private static bool CanPassInternal<T>(FilterExecutionContext<Update> updateContext, IEnumerable<IFilter<T>> filters, object filterringTarget) where T : class
|
||||||
|
{
|
||||||
|
FilterExecutionContext<T> context = updateContext.CreateChild((T)filterringTarget);
|
||||||
|
foreach (IFilter<T> filter in filters)
|
||||||
{
|
{
|
||||||
FilterAction = filterAction;
|
if (!filter.CanPass(context))
|
||||||
GetFilterringTarget = getFilterringTarget;
|
|
||||||
_name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compiles a set of filters into an <see cref="AnonymousCompiledFilter"/> for a specific target type.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the filtering target.</typeparam>
|
|
||||||
/// <param name="filters">The list of filters to compile.</param>
|
|
||||||
/// <param name="getFilterringTarget">The function to get the filtering target from an update.</param>
|
|
||||||
/// <returns>The compiled filter.</returns>
|
|
||||||
public static AnonymousCompiledFilter Compile<T>(IEnumerable<IFilter<T>> filters, Func<Update, object?> getFilterringTarget) where T : class
|
|
||||||
{
|
|
||||||
return new AnonymousCompiledFilter(
|
|
||||||
string.Join("+", filters.Select(fltr => fltr.GetType().Name)),
|
|
||||||
getFilterringTarget,
|
|
||||||
(context, filterringTarget) => CanPassInternal(context, filters, filterringTarget));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compiles a set of filters into an <see cref="AnonymousCompiledFilter"/> for a specific target type with a custom name.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the filtering target.</typeparam>
|
|
||||||
/// <param name="name">The custom name for the compiled filter.</param>
|
|
||||||
/// <param name="filters">The list of filters to compile.</param>
|
|
||||||
/// <param name="getFilterringTarget">The function to get the filtering target from an update.</param>
|
|
||||||
/// <returns>The compiled filter.</returns>
|
|
||||||
public static AnonymousCompiledFilter Compile<T>(string name, IEnumerable<IFilter<T>> filters, Func<Update, object?> getFilterringTarget) where T : class
|
|
||||||
{
|
|
||||||
return new AnonymousCompiledFilter(
|
|
||||||
name,
|
|
||||||
getFilterringTarget,
|
|
||||||
(context, filterringTarget) => CanPassInternal(context, filters, filterringTarget));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether all filters can pass for the given context and filtering target.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the filtering target.</typeparam>
|
|
||||||
/// <param name="filters">The list of filters.</param>
|
|
||||||
/// <param name="updateContext">The filter execution context.</param>
|
|
||||||
/// <param name="filterringTarget">The filtering target.</param>
|
|
||||||
/// <returns>True if all filters pass; otherwise, false.</returns>
|
|
||||||
private static bool CanPassInternal<T>(FilterExecutionContext<Update> updateContext, IEnumerable<IFilter<T>> filters, object filterringTarget) where T : class
|
|
||||||
{
|
|
||||||
FilterExecutionContext<T> context = updateContext.CreateChild((T)filterringTarget);
|
|
||||||
foreach (IFilter<T> filter in filters)
|
|
||||||
{
|
{
|
||||||
if (!filter.CanPass(context))
|
if (filter is not AnonymousCompiledFilter && filter is not AnonymousTypeFilter)
|
||||||
{
|
TelegratorLogging.LogDebug("{0} filter of {1} didnt pass! (Compiled anonymous)", filter.GetType().Name, context.Data["handler_name"]);
|
||||||
if (filter is not AnonymousCompiledFilter && filter is not AnonymousTypeFilter)
|
|
||||||
TelegratorLogging.LogDebug("{0} filter of {1} didnt pass! (Compiled anonymous)", filter.GetType().Name, context.Data["handler_name"]);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
context.CompletedFilters.Add(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override bool CanPass(FilterExecutionContext<Update> context)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
object? filterringTarget = GetFilterringTarget.Invoke(context.Input);
|
|
||||||
if (filterringTarget == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return FilterAction.Invoke(context, filterringTarget);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.CompletedFilters.Add(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool CanPass(FilterExecutionContext<Update> context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
object? filterringTarget = GetFilterringTarget.Invoke(context.Input);
|
||||||
|
if (filterringTarget == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return FilterAction.Invoke(context, filterringTarget);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,109 +2,108 @@
|
|||||||
using Telegrator.Filters;
|
using Telegrator.Filters;
|
||||||
using Telegrator.Logging;
|
using Telegrator.Logging;
|
||||||
|
|
||||||
namespace Telegrator.Core.Filters
|
namespace Telegrator.Core.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a filter that applies a filter action to an anonymous target type extracted from an update.
|
||||||
|
/// </summary>
|
||||||
|
public class AnonymousTypeFilter : Filter<Update>, INamedFilter
|
||||||
{
|
{
|
||||||
|
private static readonly Type[] IgnoreLog = [typeof(CompiledFilter<>), typeof(AnonymousCompiledFilter), typeof(AnonymousTypeFilter)];
|
||||||
|
|
||||||
|
private readonly Func<FilterExecutionContext<Update>, object, bool> FilterAction;
|
||||||
|
private readonly Func<Update, object?> GetFilterringTarget;
|
||||||
|
private readonly string _name;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a filter that applies a filter action to an anonymous target type extracted from an update.
|
/// Gets the name of this filter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AnonymousTypeFilter : Filter<Update>, INamedFilter
|
public virtual string Name => _name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AnonymousTypeFilter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the filter.</param>
|
||||||
|
/// <param name="filterAction">The filter action delegate.</param>
|
||||||
|
/// <param name="getFilterringTarget">The function to get the filtering target from an update.</param>
|
||||||
|
public AnonymousTypeFilter(string name, Func<Update, object?> getFilterringTarget, Func<FilterExecutionContext<Update>, object, bool> filterAction)
|
||||||
{
|
{
|
||||||
private static readonly Type[] IgnoreLog = [typeof(CompiledFilter<>), typeof(AnonymousCompiledFilter), typeof(AnonymousTypeFilter)];
|
FilterAction = filterAction;
|
||||||
|
GetFilterringTarget = getFilterringTarget;
|
||||||
|
_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
private readonly Func<FilterExecutionContext<Update>, object, bool> FilterAction;
|
/// <summary>
|
||||||
private readonly Func<Update, object?> GetFilterringTarget;
|
/// Compiles a filter for a specific target type.
|
||||||
private readonly string _name;
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the filtering target.</typeparam>
|
||||||
|
/// <param name="filter">The filter to apply.</param>
|
||||||
|
/// <param name="getFilterringTarget">The function to get the filtering target from an update.</param>
|
||||||
|
/// <returns>The compiled filter.</returns>
|
||||||
|
public static AnonymousTypeFilter Compile<T>(IFilter<T> filter, Func<Update, T?> getFilterringTarget) where T : class
|
||||||
|
{
|
||||||
|
return new AnonymousTypeFilter(
|
||||||
|
filter.GetType().Name, getFilterringTarget,
|
||||||
|
(context, filterringTarget) => CanPassInternal(context, filter, filterringTarget));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the name of this filter.
|
/// Compiles a filter for a specific target type with a custom name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual string Name => _name;
|
/// <typeparam name="T">The type of the filtering target.</typeparam>
|
||||||
|
/// <param name="name">The custom name for the compiled filter.</param>
|
||||||
|
/// <param name="filter">The filter to apply.</param>
|
||||||
|
/// <param name="getFilterringTarget">The function to get the filtering target from an update.</param>
|
||||||
|
/// <returns>The compiled filter.</returns>
|
||||||
|
public static AnonymousTypeFilter Compile<T>(string name, IFilter<T> filter, Func<Update, T?> getFilterringTarget) where T : class
|
||||||
|
{
|
||||||
|
return new AnonymousTypeFilter(
|
||||||
|
name,
|
||||||
|
getFilterringTarget,
|
||||||
|
(context, filterringTarget) => CanPassInternal(context, filter, filterringTarget));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="AnonymousTypeFilter"/> class.
|
/// Determines whether the filter can pass for the given context and filtering target.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The name of the filter.</param>
|
/// <typeparam name="T">The type of the filtering target.</typeparam>
|
||||||
/// <param name="filterAction">The filter action delegate.</param>
|
/// <param name="updateContext">The filter execution context.</param>
|
||||||
/// <param name="getFilterringTarget">The function to get the filtering target from an update.</param>
|
/// <param name="filter">The filter to apply.</param>
|
||||||
public AnonymousTypeFilter(string name, Func<Update, object?> getFilterringTarget, Func<FilterExecutionContext<Update>, object, bool> filterAction)
|
/// <param name="filterringTarget">The filtering target.</param>
|
||||||
|
/// <returns>True if the filter passes; otherwise, false.</returns>
|
||||||
|
private static bool CanPassInternal<T>(FilterExecutionContext<Update> updateContext, IFilter<T> filter, object filterringTarget) where T : class
|
||||||
|
{
|
||||||
|
FilterExecutionContext<T> context = updateContext.CreateChild((T)filterringTarget);
|
||||||
|
if (!filter.CanPass(context))
|
||||||
{
|
{
|
||||||
FilterAction = filterAction;
|
if (IgnoreLog.Contains(filter.GetType().MakeGenericType()))
|
||||||
GetFilterringTarget = getFilterringTarget;
|
TelegratorLogging.LogDebug("{0} filter of {1} didnt pass!", filter.GetType().Name, context.Data["handler_name"]);
|
||||||
_name = name;
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
context.CompletedFilters.Add(filter);
|
||||||
/// Compiles a filter for a specific target type.
|
return true;
|
||||||
/// </summary>
|
}
|
||||||
/// <typeparam name="T">The type of the filtering target.</typeparam>
|
|
||||||
/// <param name="filter">The filter to apply.</param>
|
|
||||||
/// <param name="getFilterringTarget">The function to get the filtering target from an update.</param>
|
|
||||||
/// <returns>The compiled filter.</returns>
|
|
||||||
public static AnonymousTypeFilter Compile<T>(IFilter<T> filter, Func<Update, T?> getFilterringTarget) where T : class
|
|
||||||
{
|
|
||||||
return new AnonymousTypeFilter(
|
|
||||||
filter.GetType().Name, getFilterringTarget,
|
|
||||||
(context, filterringTarget) => CanPassInternal(context, filter, filterringTarget));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compiles a filter for a specific target type with a custom name.
|
/// Determines whether the filter can pass for the given context by extracting the filtering target and applying the filter action.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the filtering target.</typeparam>
|
/// <param name="context">The filter execution context.</param>
|
||||||
/// <param name="name">The custom name for the compiled filter.</param>
|
/// <returns>True if the filter passes; otherwise, false.</returns>
|
||||||
/// <param name="filter">The filter to apply.</param>
|
public override bool CanPass(FilterExecutionContext<Update> context)
|
||||||
/// <param name="getFilterringTarget">The function to get the filtering target from an update.</param>
|
{
|
||||||
/// <returns>The compiled filter.</returns>
|
try
|
||||||
public static AnonymousTypeFilter Compile<T>(string name, IFilter<T> filter, Func<Update, T?> getFilterringTarget) where T : class
|
|
||||||
{
|
{
|
||||||
return new AnonymousTypeFilter(
|
object? filterringTarget = GetFilterringTarget.Invoke(context.Input);
|
||||||
name,
|
if (filterringTarget == null)
|
||||||
getFilterringTarget,
|
|
||||||
(context, filterringTarget) => CanPassInternal(context, filter, filterringTarget));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether the filter can pass for the given context and filtering target.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the filtering target.</typeparam>
|
|
||||||
/// <param name="updateContext">The filter execution context.</param>
|
|
||||||
/// <param name="filter">The filter to apply.</param>
|
|
||||||
/// <param name="filterringTarget">The filtering target.</param>
|
|
||||||
/// <returns>True if the filter passes; otherwise, false.</returns>
|
|
||||||
private static bool CanPassInternal<T>(FilterExecutionContext<Update> updateContext, IFilter<T> filter, object filterringTarget) where T : class
|
|
||||||
{
|
|
||||||
FilterExecutionContext<T> context = updateContext.CreateChild((T)filterringTarget);
|
|
||||||
if (!filter.CanPass(context))
|
|
||||||
{
|
|
||||||
if (IgnoreLog.Contains(filter.GetType().MakeGenericType()))
|
|
||||||
TelegratorLogging.LogDebug("{0} filter of {1} didnt pass!", filter.GetType().Name, context.Data["handler_name"]);
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
context.CompletedFilters.Add(filter);
|
return FilterAction.Invoke(context, filterringTarget);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
/// <summary>
|
|
||||||
/// Determines whether the filter can pass for the given context by extracting the filtering target and applying the filter action.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The filter execution context.</param>
|
|
||||||
/// <returns>True if the filter passes; otherwise, false.</returns>
|
|
||||||
public override bool CanPass(FilterExecutionContext<Update> context)
|
|
||||||
{
|
{
|
||||||
try
|
return false;
|
||||||
{
|
|
||||||
object? filterringTarget = GetFilterringTarget.Invoke(context.Input);
|
|
||||||
if (filterringTarget == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return FilterAction.Invoke(context, filterringTarget);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,64 +1,63 @@
|
|||||||
using Telegrator.Filters;
|
using Telegrator.Filters;
|
||||||
using Telegrator.Logging;
|
using Telegrator.Logging;
|
||||||
|
|
||||||
namespace Telegrator.Core.Filters
|
namespace Telegrator.Core.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a filter that composes multiple filters and passes only if all of them pass.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
||||||
|
public class CompiledFilter<T> : Filter<T>, INamedFilter where T : class
|
||||||
{
|
{
|
||||||
|
private readonly IFilter<T>[] Filters;
|
||||||
|
private readonly string _name;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a filter that composes multiple filters and passes only if all of them pass.
|
/// Gets the name of this compiled filter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
public virtual string Name => _name;
|
||||||
public class CompiledFilter<T> : Filter<T>, INamedFilter where T : class
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CompiledFilter{T}"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filters">The filters to compose.</param>
|
||||||
|
public CompiledFilter(params IFilter<T>[] filters)
|
||||||
{
|
{
|
||||||
private readonly IFilter<T>[] Filters;
|
_name = string.Join("+", filters.Select(fltr => fltr.GetType().Name));
|
||||||
private readonly string _name;
|
Filters = filters;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the name of this compiled filter.
|
/// Initializes a new instance of the <see cref="CompiledFilter{T}"/> class with a custom name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual string Name => _name;
|
/// <param name="name">The custom name for the compiled filter.</param>
|
||||||
|
/// <param name="filters">The filters to compose.</param>
|
||||||
|
public CompiledFilter(string name, params IFilter<T>[] filters)
|
||||||
|
{
|
||||||
|
_name = name;
|
||||||
|
Filters = filters;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="CompiledFilter{T}"/> class.
|
/// Determines whether all composed filters pass for the given context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filters">The filters to compose.</param>
|
/// <param name="context">The filter execution context.</param>
|
||||||
public CompiledFilter(params IFilter<T>[] filters)
|
/// <returns>True if all filters pass; otherwise, false.</returns>
|
||||||
|
public override bool CanPass(FilterExecutionContext<T> context)
|
||||||
|
{
|
||||||
|
foreach (IFilter<T> filter in Filters)
|
||||||
{
|
{
|
||||||
_name = string.Join("+", filters.Select(fltr => fltr.GetType().Name));
|
if (!filter.CanPass(context))
|
||||||
Filters = filters;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="CompiledFilter{T}"/> class with a custom name.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The custom name for the compiled filter.</param>
|
|
||||||
/// <param name="filters">The filters to compose.</param>
|
|
||||||
public CompiledFilter(string name, params IFilter<T>[] filters)
|
|
||||||
{
|
|
||||||
_name = name;
|
|
||||||
Filters = filters;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether all composed filters pass for the given context.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The filter execution context.</param>
|
|
||||||
/// <returns>True if all filters pass; otherwise, false.</returns>
|
|
||||||
public override bool CanPass(FilterExecutionContext<T> context)
|
|
||||||
{
|
|
||||||
foreach (IFilter<T> filter in Filters)
|
|
||||||
{
|
{
|
||||||
if (!filter.CanPass(context))
|
if (filter is not AnonymousCompiledFilter && filter is not AnonymousTypeFilter)
|
||||||
{
|
TelegratorLogging.LogTrace("{0} filter of {1} didnt pass! (Compiled)", filter.GetType().Name, context.Data["handler_name"]);
|
||||||
if (filter is not AnonymousCompiledFilter && filter is not AnonymousTypeFilter)
|
|
||||||
TelegratorLogging.LogTrace("{0} filter of {1} didnt pass! (Compiled)", filter.GetType().Name, context.Data["handler_name"]);
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
context.CompletedFilters.Add(filter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
context.CompletedFilters.Add(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,86 +1,85 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
|
||||||
namespace Telegrator.Core.Filters
|
namespace Telegrator.Core.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The list containing filters worked out during Polling to further obtain additional filtering information
|
||||||
|
/// </summary>
|
||||||
|
public class CompletedFiltersList : IEnumerable<IFilterCollectable>
|
||||||
{
|
{
|
||||||
|
private readonly List<IFilterCollectable> CompletedFilters = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The list containing filters worked out during Polling to further obtain additional filtering information
|
/// Adds the completed filter to the list.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CompletedFiltersList : IEnumerable<IFilterCollectable>
|
/// <typeparam name="TUpdate">The type of update.</typeparam>
|
||||||
|
/// <param name="filter">The filter to add.</param>
|
||||||
|
public void Add<TUpdate>(IFilter<TUpdate> filter) where TUpdate : class
|
||||||
{
|
{
|
||||||
private readonly List<IFilterCollectable> CompletedFilters = [];
|
if (filter is AnonymousTypeFilter | filter is AnonymousCompiledFilter)
|
||||||
|
return;
|
||||||
|
|
||||||
/// <summary>
|
if (!filter.IsCollectible)
|
||||||
/// Adds the completed filter to the list.
|
return;
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TUpdate">The type of update.</typeparam>
|
|
||||||
/// <param name="filter">The filter to add.</param>
|
|
||||||
public void Add<TUpdate>(IFilter<TUpdate> filter) where TUpdate : class
|
|
||||||
{
|
|
||||||
if (filter is AnonymousTypeFilter | filter is AnonymousCompiledFilter)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!filter.IsCollectible)
|
CompletedFilters.Add(filter);
|
||||||
return;
|
|
||||||
|
|
||||||
CompletedFilters.Add(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds many completed filters to the list.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TUpdate">The type of update.</typeparam>
|
|
||||||
/// <param name="filters">The filters to add.</param>
|
|
||||||
public void AddRange<TUpdate>(IEnumerable<IFilter<TUpdate>> filters) where TUpdate : class
|
|
||||||
{
|
|
||||||
foreach (IFilter<TUpdate> filter in filters)
|
|
||||||
Add(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks for filters of a given type in the list.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TFilter">The filter type to search for.</typeparam>
|
|
||||||
/// <returns>The enumerable containing filters of the given type.</returns>
|
|
||||||
/// <exception cref="NotFilterTypeException">Thrown if the type is not a filter type.</exception>
|
|
||||||
public IEnumerable<TFilter> Get<TFilter>() where TFilter : notnull, IFilterCollectable
|
|
||||||
{
|
|
||||||
if (!typeof(TFilter).IsFilterType())
|
|
||||||
throw new NotFilterTypeException(typeof(TFilter));
|
|
||||||
|
|
||||||
return CompletedFilters.OfType<TFilter>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks for a filter of a given type at the specified index in the list.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TFilter">The filter type to search for.</typeparam>
|
|
||||||
/// <param name="index">The index of the filter.</param>
|
|
||||||
/// <returns>The filter of the given type at the specified index.</returns>
|
|
||||||
/// <exception cref="NotFilterTypeException">Thrown if the type is not a filter type.</exception>
|
|
||||||
/// <exception cref="KeyNotFoundException">Thrown if no filter is found at the index.</exception>
|
|
||||||
public TFilter Get<TFilter>(int index) where TFilter : notnull, IFilterCollectable
|
|
||||||
{
|
|
||||||
IEnumerable<TFilter> filters = Get<TFilter>();
|
|
||||||
return filters.Any() ? filters.ElementAt(index) : throw new KeyNotFoundException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a filter of a given type at the specified index, or null if it does not exist.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TFilter">The filter type to search for.</typeparam>
|
|
||||||
/// <param name="index">The index of the filter.</param>
|
|
||||||
/// <returns>The filter at the specified index, or null if it does not exist.</returns>
|
|
||||||
/// <exception cref="NotFilterTypeException">Thrown if the type is not a filter type.</exception>
|
|
||||||
public TFilter? GetOrDefault<TFilter>(int index) where TFilter : IFilterCollectable
|
|
||||||
{
|
|
||||||
IEnumerable<TFilter> filters = Get<TFilter>();
|
|
||||||
return filters.Any() ? filters.ElementAt(index) : default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public IEnumerator<IFilterCollectable> GetEnumerator() => CompletedFilters.GetEnumerator();
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => CompletedFilters.GetEnumerator();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds many completed filters to the list.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TUpdate">The type of update.</typeparam>
|
||||||
|
/// <param name="filters">The filters to add.</param>
|
||||||
|
public void AddRange<TUpdate>(IEnumerable<IFilter<TUpdate>> filters) where TUpdate : class
|
||||||
|
{
|
||||||
|
foreach (IFilter<TUpdate> filter in filters)
|
||||||
|
Add(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks for filters of a given type in the list.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TFilter">The filter type to search for.</typeparam>
|
||||||
|
/// <returns>The enumerable containing filters of the given type.</returns>
|
||||||
|
/// <exception cref="NotFilterTypeException">Thrown if the type is not a filter type.</exception>
|
||||||
|
public IEnumerable<TFilter> Get<TFilter>() where TFilter : notnull, IFilterCollectable
|
||||||
|
{
|
||||||
|
if (!typeof(TFilter).IsFilterType())
|
||||||
|
throw new NotFilterTypeException(typeof(TFilter));
|
||||||
|
|
||||||
|
return CompletedFilters.OfType<TFilter>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks for a filter of a given type at the specified index in the list.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TFilter">The filter type to search for.</typeparam>
|
||||||
|
/// <param name="index">The index of the filter.</param>
|
||||||
|
/// <returns>The filter of the given type at the specified index.</returns>
|
||||||
|
/// <exception cref="NotFilterTypeException">Thrown if the type is not a filter type.</exception>
|
||||||
|
/// <exception cref="KeyNotFoundException">Thrown if no filter is found at the index.</exception>
|
||||||
|
public TFilter Get<TFilter>(int index) where TFilter : notnull, IFilterCollectable
|
||||||
|
{
|
||||||
|
IEnumerable<TFilter> filters = Get<TFilter>();
|
||||||
|
return filters.Any() ? filters.ElementAt(index) : throw new KeyNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a filter of a given type at the specified index, or null if it does not exist.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TFilter">The filter type to search for.</typeparam>
|
||||||
|
/// <param name="index">The index of the filter.</param>
|
||||||
|
/// <returns>The filter at the specified index, or null if it does not exist.</returns>
|
||||||
|
/// <exception cref="NotFilterTypeException">Thrown if the type is not a filter type.</exception>
|
||||||
|
public TFilter? GetOrDefault<TFilter>(int index) where TFilter : IFilterCollectable
|
||||||
|
{
|
||||||
|
IEnumerable<TFilter> filters = Get<TFilter>();
|
||||||
|
return filters.Any() ? filters.ElementAt(index) : default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IEnumerator<IFilterCollectable> GetEnumerator() => CompletedFilters.GetEnumerator();
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => CompletedFilters.GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,86 +1,85 @@
|
|||||||
using Telegram.Bot.Types;
|
using Telegram.Bot.Types;
|
||||||
using Telegram.Bot.Types.Enums;
|
using Telegram.Bot.Types.Enums;
|
||||||
|
|
||||||
namespace Telegrator.Core.Filters
|
namespace Telegrator.Core.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the context for filter execution, including update, input, and additional data.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
||||||
|
public class FilterExecutionContext<T> where T : class
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the context for filter execution, including update, input, and additional data.
|
/// Gets the <see cref="ITelegramBotInfo"/> for the current context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
public IUpdateRouter UpdateRouter { get; }
|
||||||
public class FilterExecutionContext<T> where T : class
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="ITelegramBotInfo"/> for the current context.
|
||||||
|
/// </summary>
|
||||||
|
public ITelegramBotInfo BotInfo { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the additional data dictionary for the context.
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<string, object> Data { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the list of completed filters for the context.
|
||||||
|
/// </summary>
|
||||||
|
public CompletedFiltersList CompletedFilters { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="Update"/> being processed.
|
||||||
|
/// </summary>
|
||||||
|
public Update Update { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="UpdateType"/> of the update.
|
||||||
|
/// </summary>
|
||||||
|
public UpdateType Type { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the input object for the filter.
|
||||||
|
/// </summary>
|
||||||
|
public T Input { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="FilterExecutionContext{T}"/> class with all parameters.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="router">The router, that invoked filter.</param>
|
||||||
|
/// <param name="botInfo">The bot info.</param>
|
||||||
|
/// <param name="update">The update.</param>
|
||||||
|
/// <param name="input">The input object.</param>
|
||||||
|
/// <param name="data">The additional data dictionary.</param>
|
||||||
|
/// <param name="completedFilters">The list of completed filters.</param>
|
||||||
|
public FilterExecutionContext(IUpdateRouter router, ITelegramBotInfo botInfo, Update update, T input, Dictionary<string, object> data, CompletedFiltersList completedFilters)
|
||||||
{
|
{
|
||||||
/// <summary>
|
UpdateRouter = router;
|
||||||
/// Gets the <see cref="ITelegramBotInfo"/> for the current context.
|
BotInfo = botInfo;
|
||||||
/// </summary>
|
Data = data;
|
||||||
public IUpdateRouter UpdateRouter { get; }
|
CompletedFilters = completedFilters;
|
||||||
|
Update = update;
|
||||||
/// <summary>
|
Type = update.Type;
|
||||||
/// Gets the <see cref="ITelegramBotInfo"/> for the current context.
|
Input = input;
|
||||||
/// </summary>
|
|
||||||
public ITelegramBotInfo BotInfo { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the additional data dictionary for the context.
|
|
||||||
/// </summary>
|
|
||||||
public Dictionary<string, object> Data { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the list of completed filters for the context.
|
|
||||||
/// </summary>
|
|
||||||
public CompletedFiltersList CompletedFilters { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="Update"/> being processed.
|
|
||||||
/// </summary>
|
|
||||||
public Update Update { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="UpdateType"/> of the update.
|
|
||||||
/// </summary>
|
|
||||||
public UpdateType Type { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the input object for the filter.
|
|
||||||
/// </summary>
|
|
||||||
public T Input { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="FilterExecutionContext{T}"/> class with all parameters.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="router">The router, that invoked filter.</param>
|
|
||||||
/// <param name="botInfo">The bot info.</param>
|
|
||||||
/// <param name="update">The update.</param>
|
|
||||||
/// <param name="input">The input object.</param>
|
|
||||||
/// <param name="data">The additional data dictionary.</param>
|
|
||||||
/// <param name="completedFilters">The list of completed filters.</param>
|
|
||||||
public FilterExecutionContext(IUpdateRouter router, ITelegramBotInfo botInfo, Update update, T input, Dictionary<string, object> data, CompletedFiltersList completedFilters)
|
|
||||||
{
|
|
||||||
UpdateRouter = router;
|
|
||||||
BotInfo = botInfo;
|
|
||||||
Data = data;
|
|
||||||
CompletedFilters = completedFilters;
|
|
||||||
Update = update;
|
|
||||||
Type = update.Type;
|
|
||||||
Input = input;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="FilterExecutionContext{T}"/> class with default data and filters.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="router">The router, that invoked filter.</param>
|
|
||||||
/// <param name="botInfo">The bot info.</param>
|
|
||||||
/// <param name="update">The update.</param>
|
|
||||||
/// <param name="input">The input object.</param>
|
|
||||||
public FilterExecutionContext(IUpdateRouter router, ITelegramBotInfo botInfo, Update update, T input)
|
|
||||||
: this(router, botInfo, update, input, [], []) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a child context for a different input type, sharing the same data and completed filters.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="C">The type of the new input.</typeparam>
|
|
||||||
/// <param name="input">The new input object.</param>
|
|
||||||
/// <returns>A new <see cref="FilterExecutionContext{C}"/> instance.</returns>
|
|
||||||
public FilterExecutionContext<C> CreateChild<C>(C input) where C : class
|
|
||||||
=> new FilterExecutionContext<C>(UpdateRouter, BotInfo, Update, input, Data, CompletedFilters);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="FilterExecutionContext{T}"/> class with default data and filters.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="router">The router, that invoked filter.</param>
|
||||||
|
/// <param name="botInfo">The bot info.</param>
|
||||||
|
/// <param name="update">The update.</param>
|
||||||
|
/// <param name="input">The input object.</param>
|
||||||
|
public FilterExecutionContext(IUpdateRouter router, ITelegramBotInfo botInfo, Update update, T input)
|
||||||
|
: this(router, botInfo, update, input, [], []) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a child context for a different input type, sharing the same data and completed filters.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="C">The type of the new input.</typeparam>
|
||||||
|
/// <param name="input">The new input object.</param>
|
||||||
|
/// <returns>A new <see cref="FilterExecutionContext{C}"/> instance.</returns>
|
||||||
|
public FilterExecutionContext<C> CreateChild<C>(C input) where C : class
|
||||||
|
=> new FilterExecutionContext<C>(UpdateRouter, BotInfo, Update, input, Data, CompletedFilters);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +1,50 @@
|
|||||||
namespace Telegrator.Core.Filters
|
namespace Telegrator.Core.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for filters that have a name for identification and debugging purposes.
|
||||||
|
/// </summary>
|
||||||
|
public interface INamedFilter
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interface for filters that have a name for identification and debugging purposes.
|
/// Gets the name of the filter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface INamedFilter
|
public string Name { get; }
|
||||||
{
|
}
|
||||||
/// <summary>
|
|
||||||
/// Gets the name of the filter.
|
/// <summary>
|
||||||
/// </summary>
|
/// Interface for filters that can be collected into a completed filters list.
|
||||||
public string Name { get; }
|
/// Provides information about whether a filter should be tracked during execution.
|
||||||
}
|
/// </summary>
|
||||||
|
public interface IFilterCollectable
|
||||||
/// <summary>
|
{
|
||||||
/// Interface for filters that can be collected into a completed filters list.
|
/// <summary>
|
||||||
/// Provides information about whether a filter should be tracked during execution.
|
/// Gets if filter can be collected to <see cref="CompletedFiltersList"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IFilterCollectable
|
public bool IsCollectible { get; }
|
||||||
{
|
}
|
||||||
/// <summary>
|
|
||||||
/// Gets if filter can be collected to <see cref="CompletedFiltersList"/>
|
/// <summary>
|
||||||
/// </summary>
|
/// Represents a filter for a specific update type.
|
||||||
public bool IsCollectible { get; }
|
/// </summary>
|
||||||
}
|
/// <typeparam name="T">The type of the update to filter.</typeparam>
|
||||||
|
public interface IFilter<T> : IFilterCollectable where T : class
|
||||||
/// <summary>
|
{
|
||||||
/// Represents a filter for a specific update type.
|
/// <summary>
|
||||||
/// </summary>
|
/// Determines whether the filter can pass for the given context.
|
||||||
/// <typeparam name="T">The type of the update to filter.</typeparam>
|
/// </summary>
|
||||||
public interface IFilter<T> : IFilterCollectable where T : class
|
/// <param name="info">The filter execution context.</param>
|
||||||
{
|
/// <returns>True if the filter passes; otherwise, false.</returns>
|
||||||
/// <summary>
|
public bool CanPass(FilterExecutionContext<T> info);
|
||||||
/// Determines whether the filter can pass for the given context.
|
}
|
||||||
/// </summary>
|
|
||||||
/// <param name="info">The filter execution context.</param>
|
/// <summary>
|
||||||
/// <returns>True if the filter passes; otherwise, false.</returns>
|
/// Represents a filter that joins multiple filters together.
|
||||||
public bool CanPass(FilterExecutionContext<T> info);
|
/// </summary>
|
||||||
}
|
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
||||||
|
public interface IJoinedFilter<T> : IFilter<T> where T : class
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the array of joined filters.
|
||||||
|
/// </summary>
|
||||||
|
public IFilter<T>[] Filters { get; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
namespace Telegrator.Core.Filters
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a filter that joins multiple filters together.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
|
||||||
public interface IJoinedFilter<T> : IFilter<T> where T : class
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the array of joined filters.
|
|
||||||
/// </summary>
|
|
||||||
public IFilter<T>[] Filters { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,91 +6,90 @@ using Telegrator.Core.Filters;
|
|||||||
using Telegrator.Core.States;
|
using Telegrator.Core.States;
|
||||||
using Telegrator.Handlers;
|
using Telegrator.Handlers;
|
||||||
|
|
||||||
namespace Telegrator.Core.Handlers
|
namespace Telegrator.Core.Handlers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract handler for Telegram updates of type <typeparamref name="TUpdate"/>.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class AbstractUpdateHandler<TUpdate> : UpdateHandlerBase, IHandlerContainerFactory, IAbstractUpdateHandler<TUpdate> where TUpdate : class
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstract handler for Telegram updates of type <typeparamref name="TUpdate"/>.
|
/// Handler container for the current update.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class AbstractUpdateHandler<TUpdate> : UpdateHandlerBase, IHandlerContainerFactory, IAbstractUpdateHandler<TUpdate> where TUpdate : class
|
public IHandlerContainer<TUpdate> Container { get; private set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Telegram Bot client associated with the current container.
|
||||||
|
/// </summary>
|
||||||
|
protected ITelegramBotClient Client => Container.Client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Incoming update of type <typeparamref name="TUpdate"/>.
|
||||||
|
/// </summary>
|
||||||
|
protected TUpdate Input => Container.ActualUpdate;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Telegram update being handled.
|
||||||
|
/// </summary>
|
||||||
|
protected Update HandlingUpdate => Container.HandlingUpdate;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Additional data associated with the handler execution.
|
||||||
|
/// </summary>
|
||||||
|
protected Dictionary<string, object> ExtraData => Container.ExtraData;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of successfully passed filters.
|
||||||
|
/// </summary>
|
||||||
|
protected CompletedFiltersList CompletedFilters => Container.CompletedFilters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provider for awaiting asynchronous operations.
|
||||||
|
/// </summary>
|
||||||
|
protected IAwaitingProvider AwaitingProvider => Container.AwaitingProvider;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Storage of bot states.
|
||||||
|
/// </summary>
|
||||||
|
protected IStateStorage StateStorage => Container.StateStorage;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance and checks that the update type matches <typeparamref name="TUpdate"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handlingUpdateType">The type of update to handle.</param>
|
||||||
|
protected AbstractUpdateHandler(UpdateType handlingUpdateType) : base(handlingUpdateType)
|
||||||
{
|
{
|
||||||
/// <summary>
|
if (!HandlingUpdateType.IsValidUpdateObject<TUpdate>())
|
||||||
/// Handler container for the current update.
|
throw new Exception();
|
||||||
/// </summary>
|
|
||||||
public IHandlerContainer<TUpdate> Container { get; private set; } = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Telegram Bot client associated with the current container.
|
|
||||||
/// </summary>
|
|
||||||
protected ITelegramBotClient Client => Container.Client;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Incoming update of type <typeparamref name="TUpdate"/>.
|
|
||||||
/// </summary>
|
|
||||||
protected TUpdate Input => Container.ActualUpdate;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The Telegram update being handled.
|
|
||||||
/// </summary>
|
|
||||||
protected Update HandlingUpdate => Container.HandlingUpdate;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Additional data associated with the handler execution.
|
|
||||||
/// </summary>
|
|
||||||
protected Dictionary<string, object> ExtraData => Container.ExtraData;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// List of successfully passed filters.
|
|
||||||
/// </summary>
|
|
||||||
protected CompletedFiltersList CompletedFilters => Container.CompletedFilters;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provider for awaiting asynchronous operations.
|
|
||||||
/// </summary>
|
|
||||||
protected IAwaitingProvider AwaitingProvider => Container.AwaitingProvider;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Storage of bot states.
|
|
||||||
/// </summary>
|
|
||||||
protected IStateStorage StateStorage => Container.StateStorage;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance and checks that the update type matches <typeparamref name="TUpdate"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handlingUpdateType">The type of update to handle.</param>
|
|
||||||
protected AbstractUpdateHandler(UpdateType handlingUpdateType) : base(handlingUpdateType)
|
|
||||||
{
|
|
||||||
if (!HandlingUpdateType.IsValidUpdateObject<TUpdate>())
|
|
||||||
throw new Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a handler container for the specified awaiting provider and handler info.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handlerInfo">The handler descriptor info.</param>
|
|
||||||
/// <returns>The created handler container.</returns>
|
|
||||||
public virtual IHandlerContainer CreateContainer(DescribedHandlerDescriptor handlerInfo)
|
|
||||||
{
|
|
||||||
return new HandlerContainer<TUpdate>(handlerInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Executes the handler logic using the specified container.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="container">The handler container.</param>
|
|
||||||
/// <param name="cancellationToken">Cancellation token.</param>
|
|
||||||
/// <returns>A task representing the asynchronous operation.</returns>
|
|
||||||
protected override sealed async Task<Result> ExecuteInternal(IHandlerContainer container, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
Container = (IHandlerContainer<TUpdate>)container;
|
|
||||||
return await Execute(Container, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Abstract method to execute the update handling logic.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="container">The handler container.</param>
|
|
||||||
/// <param name="cancellation">Cancellation token.</param>
|
|
||||||
/// <returns>A task representing the asynchronous operation.</returns>
|
|
||||||
public abstract Task<Result> Execute(IHandlerContainer<TUpdate> container, CancellationToken cancellation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a handler container for the specified awaiting provider and handler info.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handlerInfo">The handler descriptor info.</param>
|
||||||
|
/// <returns>The created handler container.</returns>
|
||||||
|
public virtual IHandlerContainer CreateContainer(DescribedHandlerDescriptor handlerInfo)
|
||||||
|
{
|
||||||
|
return new HandlerContainer<TUpdate>(handlerInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes the handler logic using the specified container.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="container">The handler container.</param>
|
||||||
|
/// <param name="cancellationToken">Cancellation token.</param>
|
||||||
|
/// <returns>A task representing the asynchronous operation.</returns>
|
||||||
|
protected override sealed async Task<Result> ExecuteInternal(IHandlerContainer container, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Container = (IHandlerContainer<TUpdate>)container;
|
||||||
|
return await Execute(Container, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract method to execute the update handling logic.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="container">The handler container.</param>
|
||||||
|
/// <param name="cancellation">Cancellation token.</param>
|
||||||
|
/// <returns>A task representing the asynchronous operation.</returns>
|
||||||
|
public abstract Task<Result> Execute(IHandlerContainer<TUpdate> container, CancellationToken cancellation);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,160 +6,159 @@ using Telegrator.Core.Descriptors;
|
|||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
using Telegrator.Handlers;
|
using Telegrator.Handlers;
|
||||||
|
|
||||||
namespace Telegrator.Core.Handlers
|
namespace Telegrator.Core.Handlers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract base class for handlers that support branching execution based on different methods.
|
||||||
|
/// Allows multiple handler methods to be defined in a single class, each with its own filters.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TUpdate">The type of update being handled.</typeparam>
|
||||||
|
public abstract class BranchingUpdateHandler<TUpdate> : AbstractUpdateHandler<TUpdate>, IHandlerContainerFactory, ICustomDescriptorsProvider where TUpdate : class
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstract base class for handlers that support branching execution based on different methods.
|
/// The method info for the current branch being executed.
|
||||||
/// Allows multiple handler methods to be defined in a single class, each with its own filters.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TUpdate">The type of update being handled.</typeparam>
|
private MethodInfo? branchMethodInfo = null;
|
||||||
public abstract class BranchingUpdateHandler<TUpdate> : AbstractUpdateHandler<TUpdate>, IHandlerContainerFactory, ICustomDescriptorsProvider where TUpdate : class
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the binding flags used to discover branch methods.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual BindingFlags BranchesBindingFlags => BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the allowed return types for branch methods.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual Type[] AllowedBranchReturnTypes => [typeof(void), typeof(Task<Result>)];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the cancellation token for the current execution.
|
||||||
|
/// </summary>
|
||||||
|
protected CancellationToken Cancellation { get; private set; } = default;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BranchingUpdateHandler{TUpdate}"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handlingUpdateType">The type of update this handler processes.</param>
|
||||||
|
protected BranchingUpdateHandler(UpdateType handlingUpdateType)
|
||||||
|
: base(handlingUpdateType) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Describes all handler branches in this class.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A collection of handler descriptors for each branch method.</returns>
|
||||||
|
/// <exception cref="Exception">Thrown when no branch methods are found.</exception>
|
||||||
|
public IEnumerable<HandlerDescriptor> DescribeHandlers()
|
||||||
{
|
{
|
||||||
/// <summary>
|
Type thisType = GetType();
|
||||||
/// The method info for the current branch being executed.
|
UpdateHandlerAttributeBase updateHandlerAttribute = HandlerInspector.GetHandlerAttribute(thisType);
|
||||||
/// </summary>
|
IEnumerable<IFilter<Update>> handlerFilters = HandlerInspector.GetFilterAttributes(thisType, HandlingUpdateType);
|
||||||
private MethodInfo? branchMethodInfo = null;
|
|
||||||
|
|
||||||
/// <summary>
|
MethodInfo[] handlerBranches = thisType.GetMethods().Where(branch => branch.DeclaringType == thisType).ToArray();
|
||||||
/// Gets the binding flags used to discover branch methods.
|
if (handlerBranches.Length == 0)
|
||||||
/// </summary>
|
throw new Exception();
|
||||||
protected virtual BindingFlags BranchesBindingFlags => BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public;
|
|
||||||
|
|
||||||
/// <summary>
|
foreach (MethodInfo branch in handlerBranches)
|
||||||
/// Gets the allowed return types for branch methods.
|
yield return DescribeBranch(branch, updateHandlerAttribute, handlerFilters);
|
||||||
/// </summary>
|
}
|
||||||
protected virtual Type[] AllowedBranchReturnTypes => [typeof(void), typeof(Task<Result>)];
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the cancellation token for the current execution.
|
/// Describes a specific branch method.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected CancellationToken Cancellation { get; private set; } = default;
|
/// <param name="branch">The branch method to describe.</param>
|
||||||
|
/// <param name="handlerAttribute">The handler attribute for the class.</param>
|
||||||
|
/// <param name="handlerFilters">The filters applied to the class.</param>
|
||||||
|
/// <returns>A handler descriptor for the branch method.</returns>
|
||||||
|
/// <exception cref="Exception">Thrown when the branch method has parameters or invalid return type.</exception>
|
||||||
|
protected virtual HandlerDescriptor DescribeBranch(MethodInfo branch, UpdateHandlerAttributeBase handlerAttribute, IEnumerable<IFilter<Update>> handlerFilters)
|
||||||
|
{
|
||||||
|
Type thisType = GetType();
|
||||||
|
|
||||||
/// <summary>
|
if (branch.GetParameters().Length != 0)
|
||||||
/// Initializes a new instance of the <see cref="BranchingUpdateHandler{TUpdate}"/> class.
|
throw new Exception("Branch method must have no parameters.");
|
||||||
/// </summary>
|
|
||||||
/// <param name="handlingUpdateType">The type of update this handler processes.</param>
|
|
||||||
protected BranchingUpdateHandler(UpdateType handlingUpdateType)
|
|
||||||
: base(handlingUpdateType) { }
|
|
||||||
|
|
||||||
/// <summary>
|
if (!AllowedBranchReturnTypes.Any(branch.ReturnType.Equals))
|
||||||
/// Describes all handler branches in this class.
|
throw new Exception("Branch method must have one of allowed return types. [void, Task<Result>]");
|
||||||
/// </summary>
|
|
||||||
/// <returns>A collection of handler descriptors for each branch method.</returns>
|
try
|
||||||
/// <exception cref="Exception">Thrown when no branch methods are found.</exception>
|
|
||||||
public IEnumerable<HandlerDescriptor> DescribeHandlers()
|
|
||||||
{
|
{
|
||||||
Type thisType = GetType();
|
handlerAttribute = HandlerInspector.GetHandlerAttribute(branch);
|
||||||
UpdateHandlerAttributeBase updateHandlerAttribute = HandlerInspector.GetHandlerAttribute(thisType);
|
}
|
||||||
IEnumerable<IFilter<Update>> handlerFilters = HandlerInspector.GetFilterAttributes(thisType, HandlingUpdateType);
|
catch
|
||||||
|
{
|
||||||
MethodInfo[] handlerBranches = thisType.GetMethods().Where(branch => branch.DeclaringType == thisType).ToArray();
|
_ = 0xBAD + 0xC0DE;
|
||||||
if (handlerBranches.Length == 0)
|
|
||||||
throw new Exception();
|
|
||||||
|
|
||||||
foreach (MethodInfo branch in handlerBranches)
|
|
||||||
yield return DescribeBranch(branch, updateHandlerAttribute, handlerFilters);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
List<IFilter<Update>> branchFiltersList = HandlerInspector.GetFilterAttributes(branch, HandlingUpdateType).ToList();
|
||||||
/// Describes a specific branch method.
|
branchFiltersList.AddRange(handlerFilters);
|
||||||
/// </summary>
|
|
||||||
/// <param name="branch">The branch method to describe.</param>
|
DescriptorFiltersSet filtersSet = new DescriptorFiltersSet(
|
||||||
/// <param name="handlerAttribute">The handler attribute for the class.</param>
|
handlerAttribute,
|
||||||
/// <param name="handlerFilters">The filters applied to the class.</param>
|
HandlerInspector.GetStateKeeperAttribute(branch),
|
||||||
/// <returns>A handler descriptor for the branch method.</returns>
|
branchFiltersList.ToArray());
|
||||||
/// <exception cref="Exception">Thrown when the branch method has parameters or invalid return type.</exception>
|
|
||||||
protected virtual HandlerDescriptor DescribeBranch(MethodInfo branch, UpdateHandlerAttributeBase handlerAttribute, IEnumerable<IFilter<Update>> handlerFilters)
|
return new HandlerBranchDescriptor(thisType, branch, HandlingUpdateType, handlerAttribute.GetIndexer(), filtersSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a handler container for this branching handler.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handlerInfo">The handler information.</param>
|
||||||
|
/// <returns>A handler container for this branching handler.</returns>
|
||||||
|
/// <exception cref="Exception">Thrown when the awaiting provider is not of the expected type.</exception>
|
||||||
|
public override IHandlerContainer CreateContainer(DescribedHandlerDescriptor handlerInfo)
|
||||||
|
{
|
||||||
|
return new HandlerContainer<TUpdate>(handlerInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes the current branch method.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="container">The handler container.</param>
|
||||||
|
/// <param name="cancellation">The cancellation token.</param>
|
||||||
|
/// <exception cref="Exception">Thrown when no branch method is set.</exception>
|
||||||
|
public override async Task<Result> Execute(IHandlerContainer<TUpdate> container, CancellationToken cancellation)
|
||||||
|
{
|
||||||
|
if (branchMethodInfo is null)
|
||||||
|
throw new Exception();
|
||||||
|
|
||||||
|
Cancellation = cancellation;
|
||||||
|
return await BranchExecuteWrapper(container, branchMethodInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wraps the execution of a branch method, handling both void and Task return types.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="container">The handler container.</param>
|
||||||
|
/// <param name="methodInfo">The method to execute.</param>
|
||||||
|
protected virtual async Task<Result> BranchExecuteWrapper(IHandlerContainer<TUpdate> container, MethodInfo methodInfo)
|
||||||
|
{
|
||||||
|
if (methodInfo.ReturnType == typeof(void))
|
||||||
{
|
{
|
||||||
Type thisType = GetType();
|
methodInfo.Invoke(this, []);
|
||||||
|
return Result.Ok();
|
||||||
if (branch.GetParameters().Length != 0)
|
|
||||||
throw new Exception("Branch method must have no parameters.");
|
|
||||||
|
|
||||||
if (!AllowedBranchReturnTypes.Any(branch.ReturnType.Equals))
|
|
||||||
throw new Exception("Branch method must have one of allowed return types. [void, Task<Result>]");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
handlerAttribute = HandlerInspector.GetHandlerAttribute(branch);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
_ = 0xBAD + 0xC0DE;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<IFilter<Update>> branchFiltersList = HandlerInspector.GetFilterAttributes(branch, HandlingUpdateType).ToList();
|
|
||||||
branchFiltersList.AddRange(handlerFilters);
|
|
||||||
|
|
||||||
DescriptorFiltersSet filtersSet = new DescriptorFiltersSet(
|
|
||||||
handlerAttribute,
|
|
||||||
HandlerInspector.GetStateKeeperAttribute(branch),
|
|
||||||
branchFiltersList.ToArray());
|
|
||||||
|
|
||||||
return new HandlerBranchDescriptor(thisType, branch, HandlingUpdateType, handlerAttribute.GetIndexer(), filtersSet);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
/// <summary>
|
|
||||||
/// Creates a handler container for this branching handler.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handlerInfo">The handler information.</param>
|
|
||||||
/// <returns>A handler container for this branching handler.</returns>
|
|
||||||
/// <exception cref="Exception">Thrown when the awaiting provider is not of the expected type.</exception>
|
|
||||||
public override IHandlerContainer CreateContainer(DescribedHandlerDescriptor handlerInfo)
|
|
||||||
{
|
{
|
||||||
return new HandlerContainer<TUpdate>(handlerInfo);
|
object branchReturn = methodInfo.Invoke(this, []);
|
||||||
|
if (branchReturn is not Task<Result> branchTask)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
return await branchTask;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
private class HandlerBranchDescriptor : HandlerDescriptor
|
||||||
/// Executes the current branch method.
|
{
|
||||||
/// </summary>
|
public HandlerBranchDescriptor(Type decalringType, MethodInfo method, UpdateType updateType, DescriptorIndexer indexer, DescriptorFiltersSet filters) : base(DescriptorType.General, decalringType, updateType, indexer, filters)
|
||||||
/// <param name="container">The handler container.</param>
|
|
||||||
/// <param name="cancellation">The cancellation token.</param>
|
|
||||||
/// <exception cref="Exception">Thrown when no branch method is set.</exception>
|
|
||||||
public override async Task<Result> Execute(IHandlerContainer<TUpdate> container, CancellationToken cancellation)
|
|
||||||
{
|
{
|
||||||
if (branchMethodInfo is null)
|
DisplayString = HandlerInspector.GetDisplayName(method) ?? string.Format("{0}+{1}", method.DeclaringType.Name, method.Name);
|
||||||
throw new Exception();
|
LazyInitialization = handler =>
|
||||||
|
|
||||||
Cancellation = cancellation;
|
|
||||||
return await BranchExecuteWrapper(container, branchMethodInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Wraps the execution of a branch method, handling both void and Task return types.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="container">The handler container.</param>
|
|
||||||
/// <param name="methodInfo">The method to execute.</param>
|
|
||||||
protected virtual async Task<Result> BranchExecuteWrapper(IHandlerContainer<TUpdate> container, MethodInfo methodInfo)
|
|
||||||
{
|
|
||||||
if (methodInfo.ReturnType == typeof(void))
|
|
||||||
{
|
{
|
||||||
methodInfo.Invoke(this, []);
|
if (handler is not BranchingUpdateHandler<TUpdate> brancher)
|
||||||
return Result.Ok();
|
throw new InvalidDataException();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
object branchReturn = methodInfo.Invoke(this, []);
|
|
||||||
if (branchReturn is not Task<Result> branchTask)
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
|
|
||||||
return await branchTask;
|
brancher.branchMethodInfo = method;
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
private class HandlerBranchDescriptor : HandlerDescriptor
|
|
||||||
{
|
|
||||||
public HandlerBranchDescriptor(Type decalringType, MethodInfo method, UpdateType updateType, DescriptorIndexer indexer, DescriptorFiltersSet filters) : base(DescriptorType.General, decalringType, updateType, indexer, filters)
|
|
||||||
{
|
|
||||||
DisplayString = HandlerInspector.GetDisplayName(method) ?? string.Format("{0}+{1}", method.DeclaringType.Name, method.Name);
|
|
||||||
LazyInitialization = handler =>
|
|
||||||
{
|
|
||||||
if (handler is not BranchingUpdateHandler<TUpdate> brancher)
|
|
||||||
throw new InvalidDataException();
|
|
||||||
|
|
||||||
brancher.branchMethodInfo = method;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,176 +5,175 @@ using Telegrator.Core.Filters;
|
|||||||
using Telegrator.Core.States;
|
using Telegrator.Core.States;
|
||||||
using Telegrator.Filters;
|
using Telegrator.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Core.Handlers.Building
|
namespace Telegrator.Core.Handlers.Building;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for building handler descriptors and managing handler filters.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class HandlerBuilderBase(Type buildingHandlerType, UpdateType updateType, IHandlersCollection? handlerCollection) : IHandlerBuilder
|
||||||
{
|
{
|
||||||
|
private static int HandlerServiceKeyIndex = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base class for building handler descriptors and managing handler filters.
|
/// <see cref="IHandlersCollection"/> to ehich new builded handlers is adding
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class HandlerBuilderBase(Type buildingHandlerType, UpdateType updateType, IHandlersCollection? handlerCollection) : IHandlerBuilder
|
protected readonly IHandlersCollection? HandlerCollection = handlerCollection;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="UpdateType"/> of building handler
|
||||||
|
/// </summary>
|
||||||
|
protected readonly UpdateType UpdateType = updateType;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type of handler to build
|
||||||
|
/// </summary>
|
||||||
|
protected readonly Type BuildingHandlerType = buildingHandlerType;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters applied to handler
|
||||||
|
/// </summary>
|
||||||
|
protected readonly List<IFilter<Update>> Filters = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="DescriptorIndexer"/> of building handler
|
||||||
|
/// </summary>
|
||||||
|
protected DescriptorIndexer Indexer = new DescriptorIndexer(0, 0, 0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update validation filter of building handler
|
||||||
|
/// </summary>
|
||||||
|
protected IFilter<Update>? ValidateFilter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// State keeper of building handler
|
||||||
|
/// </summary>
|
||||||
|
protected IFilter<Update>? StateKeeper;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds an implicit <see cref="HandlerDescriptor"/> for the specified handler instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="instance">The <see cref="UpdateHandlerBase"/> instance.</param>
|
||||||
|
/// <returns>The created <see cref="HandlerDescriptor"/>.</returns>
|
||||||
|
protected HandlerDescriptor BuildImplicitDescriptor(UpdateHandlerBase instance)
|
||||||
{
|
{
|
||||||
private static int HandlerServiceKeyIndex = 0;
|
object handlerServiceKey = GetImplicitHandlerServiceKey(BuildingHandlerType);
|
||||||
|
|
||||||
/// <summary>
|
HandlerDescriptor descriptor = new HandlerDescriptor(
|
||||||
/// <see cref="IHandlersCollection"/> to ehich new builded handlers is adding
|
DescriptorType.Implicit, BuildingHandlerType,
|
||||||
/// </summary>
|
UpdateType, Indexer, ValidateFilter,
|
||||||
protected readonly IHandlersCollection? HandlerCollection = handlerCollection;
|
Filters.ToArray(), StateKeeper,
|
||||||
|
handlerServiceKey, instance);
|
||||||
|
|
||||||
/// <summary>
|
HandlerCollection?.AddDescriptor(descriptor);
|
||||||
/// <see cref="UpdateType"/> of building handler
|
return descriptor;
|
||||||
/// </summary>
|
}
|
||||||
protected readonly UpdateType UpdateType = updateType;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Type of handler to build
|
/// Gets a unique service key for an implicit handler type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly Type BuildingHandlerType = buildingHandlerType;
|
/// <param name="BuildingHandlerType">The handler type.</param>
|
||||||
|
/// <returns>A unique service key string.</returns>
|
||||||
|
public static object GetImplicitHandlerServiceKey(Type BuildingHandlerType)
|
||||||
|
=> string.Format("ImplicitHandler_{0}+{1}", HandlerServiceKeyIndex++, BuildingHandlerType.Name);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filters applied to handler
|
/// Sets the update validating action for the handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly List<IFilter<Update>> Filters = [];
|
/// <param name="validateAction">The <see cref="UpdateValidateAction"/> to use.</param>
|
||||||
|
/// <returns>The builder instance.</returns>
|
||||||
|
public void SetUpdateValidating(UpdateValidateAction validateAction)
|
||||||
|
{
|
||||||
|
ValidateFilter = new UpdateValidateFilter(validateAction);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="DescriptorIndexer"/> of building handler
|
/// Sets the concurrency level for the handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected DescriptorIndexer Indexer = new DescriptorIndexer(0, 0, 0);
|
/// <param name="concurrency">The concurrency value.</param>
|
||||||
|
/// <returns>The builder instance.</returns>
|
||||||
|
public void SetConcurreny(int concurrency)
|
||||||
|
{
|
||||||
|
Indexer = Indexer.UpdateImportance(concurrency);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update validation filter of building handler
|
/// Sets the priority for the handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected IFilter<Update>? ValidateFilter;
|
/// <param name="priority">The priority value.</param>
|
||||||
|
/// <returns>The builder instance.</returns>
|
||||||
|
public void SetPriority(int priority)
|
||||||
|
{
|
||||||
|
Indexer = Indexer.UpdatePriority(priority);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// State keeper of building handler
|
/// Sets both concurrency and priority for the handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected IFilter<Update>? StateKeeper;
|
/// <param name="concurrency">The concurrency value.</param>
|
||||||
|
/// <param name="priority">The priority value.</param>
|
||||||
|
/// <returns>The builder instance.</returns>
|
||||||
|
public void SetIndexer(int concurrency, int priority)
|
||||||
|
{
|
||||||
|
Indexer = new DescriptorIndexer(0, concurrency, priority);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Builds an implicit <see cref="HandlerDescriptor"/> for the specified handler instance.
|
/// Adds a filter to the handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="instance">The <see cref="UpdateHandlerBase"/> instance.</param>
|
/// <param name="filter">The <see cref="IFilter{Update}"/> to add.</param>
|
||||||
/// <returns>The created <see cref="HandlerDescriptor"/>.</returns>
|
/// <returns>The builder instance.</returns>
|
||||||
protected HandlerDescriptor BuildImplicitDescriptor(UpdateHandlerBase instance)
|
public void AddFilter(IFilter<Update> filter)
|
||||||
{
|
{
|
||||||
object handlerServiceKey = GetImplicitHandlerServiceKey(BuildingHandlerType);
|
Filters.Add(filter);
|
||||||
|
}
|
||||||
|
|
||||||
HandlerDescriptor descriptor = new HandlerDescriptor(
|
/// <summary>
|
||||||
DescriptorType.Implicit, BuildingHandlerType,
|
/// Adds multiple filters to the handler.
|
||||||
UpdateType, Indexer, ValidateFilter,
|
/// </summary>
|
||||||
Filters.ToArray(), StateKeeper,
|
/// <param name="filters">The filters to add.</param>
|
||||||
handlerServiceKey, instance);
|
/// <returns>The builder instance.</returns>
|
||||||
|
public void AddFilters(params IFilter<Update>[] filters)
|
||||||
|
{
|
||||||
|
Filters.AddRange(filters);
|
||||||
|
}
|
||||||
|
|
||||||
HandlerCollection?.AddDescriptor(descriptor);
|
/// <summary>
|
||||||
return descriptor;
|
/// Sets a state keeper for the handler using a specific state and key resolver.
|
||||||
}
|
/// </summary>
|
||||||
|
/// <typeparam name="TKey">The key resolver.</typeparam>
|
||||||
|
/// <typeparam name="TValue">The state value.</typeparam>
|
||||||
|
/// <param name="state">The state value.</param>
|
||||||
|
/// <returns>The builder instance.</returns>
|
||||||
|
public void SetState<TKey, TValue>(TValue? state)
|
||||||
|
where TKey : IStateKeyResolver, new()
|
||||||
|
where TValue : IEquatable<TValue>
|
||||||
|
{
|
||||||
|
StateKeeper = new StateKeyFilter<TKey, TValue>(state);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a unique service key for an implicit handler type.
|
/// Adds a targeted filter for a specific filter target type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="BuildingHandlerType">The handler type.</param>
|
/// <typeparam name="TFilterTarget">The type of the filter target.</typeparam>
|
||||||
/// <returns>A unique service key string.</returns>
|
/// <param name="getFilterringTarget">Function to get the filter target from an update.</param>
|
||||||
public static object GetImplicitHandlerServiceKey(Type BuildingHandlerType)
|
/// <param name="filter">The filter to add.</param>
|
||||||
=> string.Format("ImplicitHandler_{0}+{1}", HandlerServiceKeyIndex++, BuildingHandlerType.Name);
|
/// <returns>The builder instance.</returns>
|
||||||
|
public void AddTargetedFilter<TFilterTarget>(Func<Update, TFilterTarget?> getFilterringTarget, IFilter<TFilterTarget> filter) where TFilterTarget : class
|
||||||
|
{
|
||||||
|
AnonymousTypeFilter anonymousTypeFilter = AnonymousTypeFilter.Compile(filter, getFilterringTarget);
|
||||||
|
Filters.Add(anonymousTypeFilter);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the update validating action for the handler.
|
/// Adds multiple targeted filters for a specific filter target type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="validateAction">The <see cref="UpdateValidateAction"/> to use.</param>
|
/// <typeparam name="TFilterTarget">The type of the filter target.</typeparam>
|
||||||
/// <returns>The builder instance.</returns>
|
/// <param name="getFilterringTarget">Function to get the filter target from an update.</param>
|
||||||
public void SetUpdateValidating(UpdateValidateAction validateAction)
|
/// <param name="filters">The filters to add.</param>
|
||||||
{
|
/// <returns>The builder instance.</returns>
|
||||||
ValidateFilter = new UpdateValidateFilter(validateAction);
|
public void AddTargetedFilters<TFilterTarget>(Func<Update, TFilterTarget?> getFilterringTarget, params IFilter<TFilterTarget>[] filters) where TFilterTarget : class
|
||||||
}
|
{
|
||||||
|
AnonymousCompiledFilter compiledPollingFilter = AnonymousCompiledFilter.Compile(filters, getFilterringTarget);
|
||||||
/// <summary>
|
Filters.Add(compiledPollingFilter);
|
||||||
/// Sets the concurrency level for the handler.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="concurrency">The concurrency value.</param>
|
|
||||||
/// <returns>The builder instance.</returns>
|
|
||||||
public void SetConcurreny(int concurrency)
|
|
||||||
{
|
|
||||||
Indexer = Indexer.UpdateImportance(concurrency);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the priority for the handler.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="priority">The priority value.</param>
|
|
||||||
/// <returns>The builder instance.</returns>
|
|
||||||
public void SetPriority(int priority)
|
|
||||||
{
|
|
||||||
Indexer = Indexer.UpdatePriority(priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets both concurrency and priority for the handler.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="concurrency">The concurrency value.</param>
|
|
||||||
/// <param name="priority">The priority value.</param>
|
|
||||||
/// <returns>The builder instance.</returns>
|
|
||||||
public void SetIndexer(int concurrency, int priority)
|
|
||||||
{
|
|
||||||
Indexer = new DescriptorIndexer(0, concurrency, priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a filter to the handler.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filter">The <see cref="IFilter{Update}"/> to add.</param>
|
|
||||||
/// <returns>The builder instance.</returns>
|
|
||||||
public void AddFilter(IFilter<Update> filter)
|
|
||||||
{
|
|
||||||
Filters.Add(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds multiple filters to the handler.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filters">The filters to add.</param>
|
|
||||||
/// <returns>The builder instance.</returns>
|
|
||||||
public void AddFilters(params IFilter<Update>[] filters)
|
|
||||||
{
|
|
||||||
Filters.AddRange(filters);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets a state keeper for the handler using a specific state and key resolver.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TKey">The key resolver.</typeparam>
|
|
||||||
/// <typeparam name="TValue">The state value.</typeparam>
|
|
||||||
/// <param name="state">The state value.</param>
|
|
||||||
/// <returns>The builder instance.</returns>
|
|
||||||
public void SetState<TKey, TValue>(TValue? state)
|
|
||||||
where TKey : IStateKeyResolver, new()
|
|
||||||
where TValue : IEquatable<TValue>
|
|
||||||
{
|
|
||||||
StateKeeper = new StateKeyFilter<TKey, TValue>(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a targeted filter for a specific filter target type.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TFilterTarget">The type of the filter target.</typeparam>
|
|
||||||
/// <param name="getFilterringTarget">Function to get the filter target from an update.</param>
|
|
||||||
/// <param name="filter">The filter to add.</param>
|
|
||||||
/// <returns>The builder instance.</returns>
|
|
||||||
public void AddTargetedFilter<TFilterTarget>(Func<Update, TFilterTarget?> getFilterringTarget, IFilter<TFilterTarget> filter) where TFilterTarget : class
|
|
||||||
{
|
|
||||||
AnonymousTypeFilter anonymousTypeFilter = AnonymousTypeFilter.Compile(filter, getFilterringTarget);
|
|
||||||
Filters.Add(anonymousTypeFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds multiple targeted filters for a specific filter target type.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TFilterTarget">The type of the filter target.</typeparam>
|
|
||||||
/// <param name="getFilterringTarget">Function to get the filter target from an update.</param>
|
|
||||||
/// <param name="filters">The filters to add.</param>
|
|
||||||
/// <returns>The builder instance.</returns>
|
|
||||||
public void AddTargetedFilters<TFilterTarget>(Func<Update, TFilterTarget?> getFilterringTarget, params IFilter<TFilterTarget>[] filters) where TFilterTarget : class
|
|
||||||
{
|
|
||||||
AnonymousCompiledFilter compiledPollingFilter = AnonymousCompiledFilter.Compile(filters, getFilterringTarget);
|
|
||||||
Filters.Add(compiledPollingFilter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
using Telegrator.Core.States;
|
using Telegrator.Core.States;
|
||||||
|
|
||||||
namespace Telegrator.Core.Handlers.Building
|
namespace Telegrator.Core.Handlers.Building;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a builder for awaiting handler logic for a specific update type.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TUpdate">The type of update to await.</typeparam>
|
||||||
|
public interface IAwaiterHandlerBuilder<TUpdate> : IHandlerBuilder where TUpdate : class
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines a builder for awaiting handler logic for a specific update type.
|
/// Awaits an update using the specified key resolver and cancellation token.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TUpdate">The type of update to await.</typeparam>
|
/// <param name="keyResolver">The <see cref="IStateKeyResolver"/> to resolve the key.</param>
|
||||||
public interface IAwaiterHandlerBuilder<TUpdate> : IHandlerBuilder where TUpdate : class
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
{
|
/// <returns>A <see cref="Task{TUpdate}"/> representing the awaited update.</returns>
|
||||||
/// <summary>
|
public Task<TUpdate> Await(IStateKeyResolver keyResolver, CancellationToken cancellationToken = default);
|
||||||
/// Awaits an update using the specified key resolver and cancellation token.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="keyResolver">The <see cref="IStateKeyResolver"/> to resolve the key.</param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
|
||||||
/// <returns>A <see cref="Task{TUpdate}"/> representing the awaited update.</returns>
|
|
||||||
public Task<TUpdate> Await(IStateKeyResolver keyResolver, CancellationToken cancellationToken = default);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,85 +2,84 @@
|
|||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
using Telegrator.Core.States;
|
using Telegrator.Core.States;
|
||||||
|
|
||||||
namespace Telegrator.Core.Handlers.Building
|
namespace Telegrator.Core.Handlers.Building;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines builder actions for configuring handler builders.
|
||||||
|
/// </summary>
|
||||||
|
public interface IHandlerBuilder
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines builder actions for configuring handler builders.
|
/// Sets the update validating action for the handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IHandlerBuilder
|
/// <param name="validateAction">The <see cref="UpdateValidateAction"/> to use.</param>
|
||||||
{
|
/// <returns>The builder instance.</returns>
|
||||||
/// <summary>
|
public void SetUpdateValidating(UpdateValidateAction validateAction);
|
||||||
/// Sets the update validating action for the handler.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="validateAction">The <see cref="UpdateValidateAction"/> to use.</param>
|
|
||||||
/// <returns>The builder instance.</returns>
|
|
||||||
public void SetUpdateValidating(UpdateValidateAction validateAction);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the concurrency level for the handler.
|
/// Sets the concurrency level for the handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="concurrency">The concurrency value.</param>
|
/// <param name="concurrency">The concurrency value.</param>
|
||||||
/// <returns>The builder instance.</returns>
|
/// <returns>The builder instance.</returns>
|
||||||
public void SetConcurreny(int concurrency);
|
public void SetConcurreny(int concurrency);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the priority for the handler.
|
/// Sets the priority for the handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="priority">The priority value.</param>
|
/// <param name="priority">The priority value.</param>
|
||||||
/// <returns>The builder instance.</returns>
|
/// <returns>The builder instance.</returns>
|
||||||
public void SetPriority(int priority);
|
public void SetPriority(int priority);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets both concurrency and priority for the handler.
|
/// Sets both concurrency and priority for the handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="concurrency">The concurrency value.</param>
|
/// <param name="concurrency">The concurrency value.</param>
|
||||||
/// <param name="priority">The priority value.</param>
|
/// <param name="priority">The priority value.</param>
|
||||||
/// <returns>The builder instance.</returns>
|
/// <returns>The builder instance.</returns>
|
||||||
public void SetIndexer(int concurrency, int priority);
|
public void SetIndexer(int concurrency, int priority);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a filter to the handler.
|
/// Adds a filter to the handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filter">The <see cref="IFilter{Update}"/> to add.</param>
|
/// <param name="filter">The <see cref="IFilter{Update}"/> to add.</param>
|
||||||
/// <returns>The builder instance.</returns>
|
/// <returns>The builder instance.</returns>
|
||||||
public void AddFilter(IFilter<Update> filter);
|
public void AddFilter(IFilter<Update> filter);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds multiple filters to the handler.
|
/// Adds multiple filters to the handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filters">The filters to add.</param>
|
/// <param name="filters">The filters to add.</param>
|
||||||
/// <returns>The builder instance.</returns>
|
/// <returns>The builder instance.</returns>
|
||||||
public void AddFilters(params IFilter<Update>[] filters);
|
public void AddFilters(params IFilter<Update>[] filters);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets a state keeper for the handler using a specific state and key resolver.
|
/// Sets a state keeper for the handler using a specific state and key resolver.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TKey">The key resolver.</typeparam>
|
/// <typeparam name="TKey">The key resolver.</typeparam>
|
||||||
/// <typeparam name="TValue">The state value.</typeparam>
|
/// <typeparam name="TValue">The state value.</typeparam>
|
||||||
/// <param name="state">The state value.</param>
|
/// <param name="state">The state value.</param>
|
||||||
/// <returns>The builder instance.</returns>
|
/// <returns>The builder instance.</returns>
|
||||||
public void SetState<TKey, TValue>(TValue? state)
|
public void SetState<TKey, TValue>(TValue? state)
|
||||||
where TKey : IStateKeyResolver, new()
|
where TKey : IStateKeyResolver, new()
|
||||||
where TValue : IEquatable<TValue>;
|
where TValue : IEquatable<TValue>;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a targeted filter for a specific filter target type.
|
/// Adds a targeted filter for a specific filter target type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TFilterTarget">The type of the filter target.</typeparam>
|
/// <typeparam name="TFilterTarget">The type of the filter target.</typeparam>
|
||||||
/// <param name="getFilterringTarget">Function to get the filter target from an update.</param>
|
/// <param name="getFilterringTarget">Function to get the filter target from an update.</param>
|
||||||
/// <param name="filter">The filter to add.</param>
|
/// <param name="filter">The filter to add.</param>
|
||||||
/// <returns>The builder instance.</returns>
|
/// <returns>The builder instance.</returns>
|
||||||
public void AddTargetedFilter<TFilterTarget>(Func<Update, TFilterTarget?> getFilterringTarget, IFilter<TFilterTarget> filter)
|
public void AddTargetedFilter<TFilterTarget>(Func<Update, TFilterTarget?> getFilterringTarget, IFilter<TFilterTarget> filter)
|
||||||
where TFilterTarget : class;
|
where TFilterTarget : class;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds multiple targeted filters for a specific filter target type.
|
/// Adds multiple targeted filters for a specific filter target type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TFilterTarget">The type of the filter target.</typeparam>
|
/// <typeparam name="TFilterTarget">The type of the filter target.</typeparam>
|
||||||
/// <param name="getFilterringTarget">Function to get the filter target from an update.</param>
|
/// <param name="getFilterringTarget">Function to get the filter target from an update.</param>
|
||||||
/// <param name="filters">The filters to add.</param>
|
/// <param name="filters">The filters to add.</param>
|
||||||
/// <returns>The builder instance.</returns>
|
/// <returns>The builder instance.</returns>
|
||||||
public void AddTargetedFilters<TFilterTarget>(Func<Update, TFilterTarget?> getFilterringTarget, params IFilter<TFilterTarget>[] filters)
|
public void AddTargetedFilters<TFilterTarget>(Func<Update, TFilterTarget?> getFilterringTarget, params IFilter<TFilterTarget>[] filters)
|
||||||
where TFilterTarget : class;
|
where TFilterTarget : class;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
using Telegrator.Handlers.Building;
|
using Telegrator.Handlers.Building;
|
||||||
|
|
||||||
namespace Telegrator.Core.Handlers.Building
|
namespace Telegrator.Core.Handlers.Building;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a builder for regular handler logic for a specific update type.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TUpdate">The type of update to handle.</typeparam>
|
||||||
|
public interface IRegularHandlerBuilder<TUpdate> : IHandlerBuilder where TUpdate : class
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines a builder for regular handler logic for a specific update type.
|
/// Builds the handler logic using the specified execution delegate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TUpdate">The type of update to handle.</typeparam>
|
/// <param name="executeHandler">The delegate to execute the handler logic.</param>
|
||||||
public interface IRegularHandlerBuilder<TUpdate> : IHandlerBuilder where TUpdate : class
|
public IHandlersCollection Build(AbstractHandlerAction<TUpdate> executeHandler);
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Builds the handler logic using the specified execution delegate.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="executeHandler">The delegate to execute the handler logic.</param>
|
|
||||||
public IHandlersCollection Build(AbstractHandlerAction<TUpdate> executeHandler);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,40 @@
|
|||||||
using Telegram.Bot.Types;
|
using Telegram.Bot.Types;
|
||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Core.Handlers.Building
|
namespace Telegrator.Core.Handlers.Building;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delegate for validating an update in a filter context.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The filter execution context.</param>
|
||||||
|
/// <returns>True if the update is valid; otherwise, false.</returns>
|
||||||
|
public delegate bool UpdateValidateAction(FilterExecutionContext<Update> context);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that uses a delegate to validate updates.
|
||||||
|
/// </summary>
|
||||||
|
public class UpdateValidateFilter : IFilter<Update>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delegate for validating an update in a filter context.
|
/// Gets a value indicating whether this filter is collectable. Always false for this filter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">The filter execution context.</param>
|
public bool IsCollectible => false;
|
||||||
/// <returns>True if the update is valid; otherwise, false.</returns>
|
private readonly UpdateValidateAction UpdateValidateAction;
|
||||||
public delegate bool UpdateValidateAction(FilterExecutionContext<Update> context);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filter that uses a delegate to validate updates.
|
/// Initializes a new instance of the <see cref="UpdateValidateFilter"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class UpdateValidateFilter : IFilter<Update>
|
/// <param name="updateValidateAction">The validation delegate to use.</param>
|
||||||
|
public UpdateValidateFilter(UpdateValidateAction updateValidateAction)
|
||||||
{
|
{
|
||||||
/// <summary>
|
UpdateValidateAction = updateValidateAction;
|
||||||
/// Gets a value indicating whether this filter is collectable. Always false for this filter.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsCollectible => false;
|
|
||||||
private readonly UpdateValidateAction UpdateValidateAction;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="UpdateValidateFilter"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="updateValidateAction">The validation delegate to use.</param>
|
|
||||||
public UpdateValidateFilter(UpdateValidateAction updateValidateAction)
|
|
||||||
{
|
|
||||||
UpdateValidateAction = updateValidateAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether the filter can pass for the given context using the validation delegate.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="info">The filter execution context.</param>
|
|
||||||
/// <returns>True if the filter passes; otherwise, false.</returns>
|
|
||||||
public bool CanPass(FilterExecutionContext<Update> info)
|
|
||||||
=> UpdateValidateAction.Invoke(info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the filter can pass for the given context using the validation delegate.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info">The filter execution context.</param>
|
||||||
|
/// <returns>True if the filter passes; otherwise, false.</returns>
|
||||||
|
public bool CanPass(FilterExecutionContext<Update> info)
|
||||||
|
=> UpdateValidateAction.Invoke(info);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,29 +3,28 @@ using Telegram.Bot.Types;
|
|||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
using Telegrator.Core.States;
|
using Telegrator.Core.States;
|
||||||
|
|
||||||
namespace Telegrator.Core.Handlers
|
namespace Telegrator.Core.Handlers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an empty handler container that throws <see cref="NotImplementedException"/> for all members.
|
||||||
|
/// </summary>
|
||||||
|
public class EmptyHandlerContainer : IHandlerContainer
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <inheritdoc/>
|
||||||
/// Represents an empty handler container that throws <see cref="NotImplementedException"/> for all members.
|
public Update HandlingUpdate => throw new NotImplementedException();
|
||||||
/// </summary>
|
|
||||||
public class EmptyHandlerContainer : IHandlerContainer
|
|
||||||
{
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public Update HandlingUpdate => throw new NotImplementedException();
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ITelegramBotClient Client => throw new NotImplementedException();
|
public ITelegramBotClient Client => throw new NotImplementedException();
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public Dictionary<string, object> ExtraData => throw new NotImplementedException();
|
public Dictionary<string, object> ExtraData => throw new NotImplementedException();
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public CompletedFiltersList CompletedFilters => throw new NotImplementedException();
|
public CompletedFiltersList CompletedFilters => throw new NotImplementedException();
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IAwaitingProvider AwaitingProvider => throw new NotImplementedException();
|
public IAwaitingProvider AwaitingProvider => throw new NotImplementedException();
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IStateStorage StateStorage => throw new NotImplementedException();
|
public IStateStorage StateStorage => throw new NotImplementedException();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,26 @@
|
|||||||
namespace Telegrator.Core.Handlers
|
namespace Telegrator.Core.Handlers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a token that tracks the lifetime of a handler instance.
|
||||||
|
/// </summary>
|
||||||
|
public class HandlerLifetimeToken
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a token that tracks the lifetime of a handler instance.
|
/// Event triggered when the handler's lifetime has ended.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class HandlerLifetimeToken
|
public event Action<HandlerLifetimeToken>? OnLifetimeEnded;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the handler's lifetime has ended.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsEnded { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks the handler's lifetime as ended and triggers the event.
|
||||||
|
/// </summary>
|
||||||
|
public void LifetimeEnded()
|
||||||
{
|
{
|
||||||
/// <summary>
|
IsEnded = true;
|
||||||
/// Event triggered when the handler's lifetime has ended.
|
OnLifetimeEnded?.Invoke(this);
|
||||||
/// </summary>
|
|
||||||
public event Action<HandlerLifetimeToken>? OnLifetimeEnded;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the handler's lifetime has ended.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsEnded { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Marks the handler's lifetime as ended and triggers the event.
|
|
||||||
/// </summary>
|
|
||||||
public void LifetimeEnded()
|
|
||||||
{
|
|
||||||
IsEnded = true;
|
|
||||||
OnLifetimeEnded?.Invoke(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,42 +3,41 @@ using Telegram.Bot.Types;
|
|||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
using Telegrator.Core.States;
|
using Telegrator.Core.States;
|
||||||
|
|
||||||
namespace Telegrator.Core.Handlers
|
namespace Telegrator.Core.Handlers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for handler containers that provide context and resources for update handlers.
|
||||||
|
/// Contains all necessary information and services that handlers need during execution.
|
||||||
|
/// </summary>
|
||||||
|
public interface IHandlerContainer
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interface for handler containers that provide context and resources for update handlers.
|
/// Gets the <see cref="Update"/> being handled.
|
||||||
/// Contains all necessary information and services that handlers need during execution.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IHandlerContainer
|
public Update HandlingUpdate { get; }
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="Update"/> being handled.
|
|
||||||
/// </summary>
|
|
||||||
public Update HandlingUpdate { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="ITelegramBotClient"/> used for this handler.
|
/// Gets the <see cref="ITelegramBotClient"/> used for this handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ITelegramBotClient Client { get; }
|
public ITelegramBotClient Client { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the extra data associated with the handler execution.
|
/// Gets the extra data associated with the handler execution.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<string, object> ExtraData { get; }
|
public Dictionary<string, object> ExtraData { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="CompletedFiltersList"/> for this handler.
|
/// Gets the <see cref="CompletedFiltersList"/> for this handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CompletedFiltersList CompletedFilters { get; }
|
public CompletedFiltersList CompletedFilters { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="IAwaitingProvider"/> for awaiting operations.
|
/// Gets the <see cref="IAwaitingProvider"/> for awaiting operations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IAwaitingProvider AwaitingProvider { get; }
|
public IAwaitingProvider AwaitingProvider { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="IStateStorage"/> for state managment.
|
/// Gets the <see cref="IStateStorage"/> for state managment.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IStateStorage StateStorage { get; }
|
public IStateStorage StateStorage { get; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
using Telegrator.Core.Descriptors;
|
using Telegrator.Core.Descriptors;
|
||||||
|
|
||||||
namespace Telegrator.Core.Handlers
|
namespace Telegrator.Core.Handlers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Factory interface for creating handler containers.
|
||||||
|
/// Provides a way to create handler containers with specific providers and handler information.
|
||||||
|
/// </summary>
|
||||||
|
public interface IHandlerContainerFactory
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Factory interface for creating handler containers.
|
/// Creates a new <see cref="IHandlerContainer"/> for the specified awaiting provider and handler info.
|
||||||
/// Provides a way to create handler containers with specific providers and handler information.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IHandlerContainerFactory
|
/// <param name="handlerInfo">The <see cref="DescribedHandlerDescriptor"/> for the handler.</param>
|
||||||
{
|
/// <returns>A new <see cref="IHandlerContainer"/> instance.</returns>
|
||||||
/// <summary>
|
public IHandlerContainer CreateContainer(DescribedHandlerDescriptor handlerInfo);
|
||||||
/// Creates a new <see cref="IHandlerContainer"/> for the specified awaiting provider and handler info.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handlerInfo">The <see cref="DescribedHandlerDescriptor"/> for the handler.</param>
|
|
||||||
/// <returns>A new <see cref="IHandlerContainer"/> instance.</returns>
|
|
||||||
public IHandlerContainer CreateContainer(DescribedHandlerDescriptor handlerInfo);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,179 +4,178 @@ using Telegram.Bot.Types.Enums;
|
|||||||
using Telegrator.Core.Descriptors;
|
using Telegrator.Core.Descriptors;
|
||||||
using Telegrator.Handlers.Diagnostics;
|
using Telegrator.Handlers.Diagnostics;
|
||||||
|
|
||||||
namespace Telegrator.Core.Handlers
|
namespace Telegrator.Core.Handlers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for update handlers, providing execution and lifetime management for Telegram updates.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class UpdateHandlerBase(UpdateType handlingUpdateType) : IUpdateHandlerBase
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base class for update handlers, providing execution and lifetime management for Telegram updates.
|
/// Gets the <see cref="UpdateType"/> that this handler processes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class UpdateHandlerBase(UpdateType handlingUpdateType) : IUpdateHandlerBase
|
public UpdateType HandlingUpdateType { get; } = handlingUpdateType;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="HandlerLifetimeToken"/> associated with this handler instance.
|
||||||
|
/// </summary>
|
||||||
|
public HandlerLifetimeToken LifetimeToken { get; } = new HandlerLifetimeToken();
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Result.Ok"/>
|
||||||
|
public static Result Ok => Result.Ok();
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Result.Fault"/>
|
||||||
|
public static Result Fault => Result.Fault();
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Result.Next"/>
|
||||||
|
public static Result Next => Result.Next();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes the handler logic and marks the lifetime as ended after execution.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="described"></param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||||
|
public async Task<Result> Execute(DescribedHandlerDescriptor described, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
/// <summary>
|
if (LifetimeToken.IsEnded)
|
||||||
/// Gets the <see cref="UpdateType"/> that this handler processes.
|
throw new Exception();
|
||||||
/// </summary>
|
|
||||||
public UpdateType HandlingUpdateType { get; } = handlingUpdateType;
|
|
||||||
|
|
||||||
/// <summary>
|
try
|
||||||
/// Gets the <see cref="HandlerLifetimeToken"/> associated with this handler instance.
|
|
||||||
/// </summary>
|
|
||||||
public HandlerLifetimeToken LifetimeToken { get; } = new HandlerLifetimeToken();
|
|
||||||
|
|
||||||
/// <inheritdoc cref="Result.Ok"/>
|
|
||||||
public static Result Ok => Result.Ok();
|
|
||||||
|
|
||||||
/// <inheritdoc cref="Result.Fault"/>
|
|
||||||
public static Result Fault => Result.Fault();
|
|
||||||
|
|
||||||
/// <inheritdoc cref="Result.Next"/>
|
|
||||||
public static Result Next => Result.Next();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Executes the handler logic and marks the lifetime as ended after execution.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="described"></param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
|
||||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
|
||||||
public async Task<Result> Execute(DescribedHandlerDescriptor described, CancellationToken cancellationToken = default)
|
|
||||||
{
|
{
|
||||||
if (LifetimeToken.IsEnded)
|
// Creating container
|
||||||
throw new Exception();
|
IHandlerContainer container = GetContainer(described);
|
||||||
|
DescriptorAspectsSet? aspects = described.From.Aspects;
|
||||||
|
|
||||||
|
// Executing pre processor
|
||||||
|
if (aspects != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Result? preResult = await aspects
|
||||||
|
.ExecutePre(this, container, cancellationToken)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (!preResult.Positive)
|
||||||
|
return preResult;
|
||||||
|
}
|
||||||
|
catch (NotImplementedException)
|
||||||
|
{
|
||||||
|
_ = 0xBAD + 0xC0DE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Creating container
|
// Executing handler
|
||||||
IHandlerContainer container = GetContainer(described);
|
Result execResult = await ExecuteInternal(container, cancellationToken).ConfigureAwait(false);
|
||||||
DescriptorAspectsSet? aspects = described.From.Aspects;
|
if (!execResult.Positive)
|
||||||
|
return execResult;
|
||||||
|
}
|
||||||
|
catch (NotImplementedException)
|
||||||
|
{
|
||||||
|
_ = 0xBAD + 0xC0DE;
|
||||||
|
}
|
||||||
|
|
||||||
// Executing pre processor
|
try
|
||||||
|
{
|
||||||
|
// Executing post processor
|
||||||
if (aspects != null)
|
if (aspects != null)
|
||||||
{
|
{
|
||||||
try
|
Result postResult = await aspects
|
||||||
{
|
.ExecutePost(this, container, cancellationToken)
|
||||||
Result? preResult = await aspects
|
|
||||||
.ExecutePre(this, container, cancellationToken)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!preResult.Positive)
|
|
||||||
return preResult;
|
|
||||||
}
|
|
||||||
catch (NotImplementedException)
|
|
||||||
{
|
|
||||||
_ = 0xBAD + 0xC0DE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Executing handler
|
|
||||||
Result execResult = await ExecuteInternal(container, cancellationToken).ConfigureAwait(false);
|
|
||||||
if (!execResult.Positive)
|
|
||||||
return execResult;
|
|
||||||
}
|
|
||||||
catch (NotImplementedException)
|
|
||||||
{
|
|
||||||
_ = 0xBAD + 0xC0DE;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Executing post processor
|
|
||||||
if (aspects != null)
|
|
||||||
{
|
|
||||||
Result postResult = await aspects
|
|
||||||
.ExecutePost(this, container, cancellationToken)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!postResult.Positive)
|
|
||||||
return postResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (NotImplementedException)
|
|
||||||
{
|
|
||||||
_ = 0xBAD + 0xC0DE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Success
|
|
||||||
return Result.Ok();
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
|
||||||
{
|
|
||||||
// Cancelled
|
|
||||||
_ = 0xBAD + 0xC0DE;
|
|
||||||
return Result.Ok();
|
|
||||||
}
|
|
||||||
catch (Exception exception)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await described.UpdateRouter
|
|
||||||
.HandleErrorAsync(described.Client, exception, HandleErrorSource.HandleUpdateError, cancellationToken)
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
|
||||||
catch (NotImplementedException)
|
|
||||||
{
|
|
||||||
_ = 0xBAD + 0xC0DE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.Fault();
|
if (!postResult.Positive)
|
||||||
|
return postResult;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally
|
catch (NotImplementedException)
|
||||||
{
|
{
|
||||||
LifetimeToken.LifetimeEnded();
|
_ = 0xBAD + 0xC0DE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Success
|
||||||
|
return Result.Ok();
|
||||||
}
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
private IHandlerContainer GetContainer(DescribedHandlerDescriptor handlerInfo)
|
|
||||||
{
|
{
|
||||||
if (this is IHandlerContainerFactory handlerDefainedContainerFactory)
|
// Cancelled
|
||||||
return handlerDefainedContainerFactory.CreateContainer(handlerInfo);
|
_ = 0xBAD + 0xC0DE;
|
||||||
|
return Result.Ok();
|
||||||
if (handlerInfo.UpdateRouter.DefaultContainerFactory is not null)
|
|
||||||
return handlerInfo.UpdateRouter.DefaultContainerFactory.CreateContainer(handlerInfo);
|
|
||||||
|
|
||||||
throw new Exception();
|
|
||||||
}
|
}
|
||||||
|
catch (Exception exception)
|
||||||
/// <summary>
|
|
||||||
/// Executes the handler logic for the given container and cancellation token.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="container">The <see cref="IHandlerContainer"/> for the update.</param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
|
||||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
|
||||||
protected abstract Task<Result> ExecuteInternal(IHandlerContainer container, CancellationToken cancellationToken);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dispose resources of this handler. Override if needed
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="disposing"></param>
|
|
||||||
/// <returns>Return <see langword="true"/> if dispose was successfull and garbage collecting for this object can be supressed</returns>
|
|
||||||
protected virtual bool Dispose(bool disposing)
|
|
||||||
{
|
{
|
||||||
return false;
|
try
|
||||||
|
{
|
||||||
|
await described.UpdateRouter
|
||||||
|
.HandleErrorAsync(described.Client, exception, HandleErrorSource.HandleUpdateError, cancellationToken)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (NotImplementedException)
|
||||||
|
{
|
||||||
|
_ = 0xBAD + 0xC0DE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Fault();
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
/// <summary>
|
|
||||||
/// Handles failed filters during handler describing.
|
|
||||||
/// Use <see cref="Result"/> to control how router should treat this fail.
|
|
||||||
/// <see cref="Result.Next"/> to silently continue decribing.
|
|
||||||
/// <see cref="Result.Fault"/> to stop\break desribing sequence.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="report"></param>
|
|
||||||
/// <param name="client"></param>
|
|
||||||
/// <param name="cancellationToken"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public virtual Task<Result> FiltersFallback(FiltersFallbackReport report, ITelegramBotClient client, CancellationToken cancellationToken = default)
|
|
||||||
{
|
{
|
||||||
return Task.FromResult(Result.Ok());
|
LifetimeToken.LifetimeEnded();
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (LifetimeToken.IsEnded)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (Dispose(true))
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IHandlerContainer GetContainer(DescribedHandlerDescriptor handlerInfo)
|
||||||
|
{
|
||||||
|
if (this is IHandlerContainerFactory handlerDefainedContainerFactory)
|
||||||
|
return handlerDefainedContainerFactory.CreateContainer(handlerInfo);
|
||||||
|
|
||||||
|
if (handlerInfo.UpdateRouter.DefaultContainerFactory is not null)
|
||||||
|
return handlerInfo.UpdateRouter.DefaultContainerFactory.CreateContainer(handlerInfo);
|
||||||
|
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes the handler logic for the given container and cancellation token.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="container">The <see cref="IHandlerContainer"/> for the update.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||||
|
protected abstract Task<Result> ExecuteInternal(IHandlerContainer container, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dispose resources of this handler. Override if needed
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing"></param>
|
||||||
|
/// <returns>Return <see langword="true"/> if dispose was successfull and garbage collecting for this object can be supressed</returns>
|
||||||
|
protected virtual bool Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles failed filters during handler describing.
|
||||||
|
/// Use <see cref="Result"/> to control how router should treat this fail.
|
||||||
|
/// <see cref="Result.Next"/> to silently continue decribing.
|
||||||
|
/// <see cref="Result.Fault"/> to stop\break desribing sequence.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="report"></param>
|
||||||
|
/// <param name="client"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual Task<Result> FiltersFallback(FiltersFallbackReport report, ITelegramBotClient client, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return Task.FromResult(Result.Ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (LifetimeToken.IsEnded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Dispose(true))
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
using Telegrator.Core.Descriptors;
|
using Telegrator.Core.Descriptors;
|
||||||
|
|
||||||
namespace Telegrator.Core
|
namespace Telegrator.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provider for managing awaiting handlers that can wait for specific update types.
|
||||||
|
/// </summary>
|
||||||
|
public interface IAwaitingProvider : IHandlersProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provider for managing awaiting handlers that can wait for specific update types.
|
/// Registers the usage of a handler and returns a disposable object to manage its lifetime.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IAwaitingProvider : IHandlersProvider
|
/// <param name="handlerDescriptor">The <see cref="HandlerDescriptor"/> to use.</param>
|
||||||
{
|
/// <returns>An <see cref="IDisposable"/> that manages the handler's usage lifetime.</returns>
|
||||||
/// <summary>
|
public IDisposable UseHandler(HandlerDescriptor handlerDescriptor);
|
||||||
/// Registers the usage of a handler and returns a disposable object to manage its lifetime.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handlerDescriptor">The <see cref="HandlerDescriptor"/> to use.</param>
|
|
||||||
/// <returns>An <see cref="IDisposable"/> that manages the handler's usage lifetime.</returns>
|
|
||||||
public IDisposable UseHandler(HandlerDescriptor handlerDescriptor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
namespace Telegrator.Core
|
namespace Telegrator.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for providers that collect and manage handler collections.
|
||||||
|
/// Provides access to a collection of handlers for various processing operations.
|
||||||
|
/// </summary>
|
||||||
|
public interface ICollectingProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interface for providers that collect and manage handler collections.
|
/// Gets the collection of handlers managed by this provider.
|
||||||
/// Provides access to a collection of handlers for various processing operations.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ICollectingProvider
|
public IHandlersCollection Handlers { get; }
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the collection of handlers managed by this provider.
|
|
||||||
/// </summary>
|
|
||||||
public IHandlersCollection Handlers { get; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
using Telegrator.Core.Descriptors;
|
using Telegrator.Core.Descriptors;
|
||||||
|
|
||||||
namespace Telegrator.Core
|
namespace Telegrator.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for classes that can provide custom handler descriptors.
|
||||||
|
/// Allows classes to define their own handler description logic beyond the standard reflection-based approach.
|
||||||
|
/// </summary>
|
||||||
|
public interface ICustomDescriptorsProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interface for classes that can provide custom handler descriptors.
|
/// Describes the handlers provided by this class.
|
||||||
/// Allows classes to define their own handler description logic beyond the standard reflection-based approach.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ICustomDescriptorsProvider
|
/// <returns>A collection of handler descriptors.</returns>
|
||||||
{
|
public IEnumerable<HandlerDescriptor> DescribeHandlers();
|
||||||
/// <summary>
|
|
||||||
/// Describes the handlers provided by this class.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A collection of handler descriptors.</returns>
|
|
||||||
public IEnumerable<HandlerDescriptor> DescribeHandlers();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,40 @@
|
|||||||
using Telegram.Bot.Types.Enums;
|
using Telegram.Bot.Types.Enums;
|
||||||
using Telegrator.Core.Descriptors;
|
using Telegrator.Core.Descriptors;
|
||||||
|
|
||||||
namespace Telegrator.Core
|
namespace Telegrator.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Collection class for managing handler descriptors organized by update type.
|
||||||
|
/// Provides functionality for collecting, adding, and organizing handlers.
|
||||||
|
/// </summary>
|
||||||
|
public interface IHandlersCollection
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Collection class for managing handler descriptors organized by update type.
|
/// Gets the collection of <see cref="UpdateType"/>'s allowed by registered handlers
|
||||||
/// Provides functionality for collecting, adding, and organizing handlers.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IHandlersCollection
|
public IEnumerable<UpdateType> AllowedTypes { get; }
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the collection of <see cref="UpdateType"/>'s allowed by registered handlers
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<UpdateType> AllowedTypes { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the collection of <see cref="UpdateType"/> keys for the handler lists.
|
/// Gets the collection of <see cref="UpdateType"/> keys for the handler lists.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<UpdateType> Keys { get; }
|
public IEnumerable<UpdateType> Keys { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the collection of <see cref="HandlerDescriptorList"/> values.
|
/// Gets the collection of <see cref="HandlerDescriptorList"/> values.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<HandlerDescriptorList> Values { get; }
|
public IEnumerable<HandlerDescriptorList> Values { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="HandlerDescriptorList"/> for the specified <see cref="UpdateType"/>.
|
/// Gets the <see cref="HandlerDescriptorList"/> for the specified <see cref="UpdateType"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="updateType">The update type key.</param>
|
/// <param name="updateType">The update type key.</param>
|
||||||
/// <returns>The handler descriptor list for the given update type.</returns>
|
/// <returns>The handler descriptor list for the given update type.</returns>
|
||||||
public HandlerDescriptorList this[UpdateType updateType] { get; }
|
public HandlerDescriptorList this[UpdateType updateType] { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a <see cref="HandlerDescriptor"/> to the collection and returns the updated collection.
|
/// Adds a <see cref="HandlerDescriptor"/> to the collection and returns the updated collection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="descriptor">The handler descriptor to add.</param>
|
/// <param name="descriptor">The handler descriptor to add.</param>
|
||||||
/// <returns>The updated <see cref="IHandlersCollection"/>.</returns>
|
/// <returns>The updated <see cref="IHandlersCollection"/>.</returns>
|
||||||
public IHandlersCollection AddDescriptor(HandlerDescriptor descriptor);
|
public IHandlersCollection AddDescriptor(HandlerDescriptor descriptor);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
namespace Telegrator.Core
|
namespace Telegrator.Core;
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Combines <see cref="IHandlersCollection"/> and <see cref="IHandlersProvider"/>.
|
/// Combines <see cref="IHandlersCollection"/> and <see cref="IHandlersProvider"/>.
|
||||||
/// Provides functionality of collecting, organizing and resolving handlers instances.
|
/// Provides functionality of collecting, organizing and resolving handlers instances.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IHandlersManager : IHandlersCollection, IHandlersProvider
|
public interface IHandlersManager : IHandlersCollection, IHandlersProvider
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,39 +2,38 @@
|
|||||||
using Telegrator.Core.Descriptors;
|
using Telegrator.Core.Descriptors;
|
||||||
using Telegrator.Core.Handlers;
|
using Telegrator.Core.Handlers;
|
||||||
|
|
||||||
namespace Telegrator.Core
|
namespace Telegrator.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides methods to retrieve and describe handler information for updates.
|
||||||
|
/// </summary>
|
||||||
|
public interface IHandlersProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides methods to retrieve and describe handler information for updates.
|
/// Gets the collection of <see cref="UpdateType"/>'s allowed by registered handlers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IHandlersProvider
|
public IEnumerable<UpdateType> AllowedTypes { get; }
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the collection of <see cref="UpdateType"/>'s allowed by registered handlers
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<UpdateType> AllowedTypes { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="updateType"></param>
|
/// <param name="updateType"></param>
|
||||||
/// <param name="list"></param>
|
/// <param name="list"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public bool TryGetDescriptorList(UpdateType updateType, out HandlerDescriptorList? list);
|
public bool TryGetDescriptorList(UpdateType updateType, out HandlerDescriptorList? list);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Instantiates a handler for the given descriptor, using the appropriate creation strategy based on descriptor type.
|
/// Instantiates a handler for the given descriptor, using the appropriate creation strategy based on descriptor type.
|
||||||
/// Supports singleton, implicit, keyed, and general descriptor types with different instantiation patterns.
|
/// Supports singleton, implicit, keyed, and general descriptor types with different instantiation patterns.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="descriptor">The handler descriptor.</param>
|
/// <param name="descriptor">The handler descriptor.</param>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns>An instance of <see cref="UpdateHandlerBase"/> for the descriptor</returns>
|
/// <returns>An instance of <see cref="UpdateHandlerBase"/> for the descriptor</returns>
|
||||||
public UpdateHandlerBase GetHandlerInstance(HandlerDescriptor descriptor, CancellationToken cancellationToken = default);
|
public UpdateHandlerBase GetHandlerInstance(HandlerDescriptor descriptor, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the provider contains any handlers.
|
/// Determines whether the provider contains any handlers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if the provider is empty; otherwise, false.</returns>
|
/// <returns>True if the provider is empty; otherwise, false.</returns>
|
||||||
public bool IsEmpty();
|
public bool IsEmpty();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,20 @@
|
|||||||
using Telegram.Bot;
|
using Telegram.Bot;
|
||||||
using Telegram.Bot.Polling;
|
using Telegram.Bot.Polling;
|
||||||
|
|
||||||
namespace Telegrator.Core
|
namespace Telegrator.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for handling exceptions that occur during update routing operations.
|
||||||
|
/// Provides a centralized way to handle and log errors that occur during bot operation.
|
||||||
|
/// </summary>
|
||||||
|
public interface IRouterExceptionHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interface for handling exceptions that occur during update routing operations.
|
/// Handles exceptions that occur during update routing.
|
||||||
/// Provides a centralized way to handle and log errors that occur during bot operation.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IRouterExceptionHandler
|
/// <param name="botClient">The <see cref="ITelegramBotClient"/> instance.</param>
|
||||||
{
|
/// <param name="exception">The exception that occurred.</param>
|
||||||
/// <summary>
|
/// <param name="source">The <see cref="HandleErrorSource"/> indicating the source of the error.</param>
|
||||||
/// Handles exceptions that occur during update routing.
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// </summary>
|
public void HandleException(ITelegramBotClient botClient, Exception exception, HandleErrorSource source, CancellationToken cancellationToken);
|
||||||
/// <param name="botClient">The <see cref="ITelegramBotClient"/> instance.</param>
|
|
||||||
/// <param name="exception">The exception that occurred.</param>
|
|
||||||
/// <param name="source">The <see cref="HandleErrorSource"/> indicating the source of the error.</param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
|
||||||
public void HandleException(ITelegramBotClient botClient, Exception exception, HandleErrorSource source, CancellationToken cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
using Telegram.Bot.Types;
|
using Telegram.Bot.Types;
|
||||||
|
|
||||||
namespace Telegrator.Core
|
namespace Telegrator.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for providing bot information and metadata.
|
||||||
|
/// Contains information about the bot user and provides initialization capabilities.
|
||||||
|
/// </summary>
|
||||||
|
public interface ITelegramBotInfo
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interface for providing bot information and metadata.
|
/// Gets the <see cref="User"/> representing the bot.
|
||||||
/// Contains information about the bot user and provides initialization capabilities.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ITelegramBotInfo
|
public User User { get; }
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="User"/> representing the bot.
|
|
||||||
/// </summary>
|
|
||||||
public User User { get; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +1,37 @@
|
|||||||
using Telegrator.Core.Descriptors;
|
using Telegrator.Core.Descriptors;
|
||||||
|
|
||||||
namespace Telegrator.Core
|
namespace Telegrator.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a delegate for when a handler is enqueued.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="args">The <see cref="DescribedHandlerDescriptor"/> for the enqueued handler.</param>
|
||||||
|
public delegate void HandlerEnqueued(DescribedHandlerDescriptor args);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a delegate for when a handler is executing.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="args">The <see cref="DescribedHandlerDescriptor"/> for the executing handler.</param>
|
||||||
|
public delegate void HandlerExecuting(DescribedHandlerDescriptor args);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a pool for managing the execution and queuing of update handlers.
|
||||||
|
/// </summary>
|
||||||
|
public interface IUpdateHandlersPool : IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a delegate for when a handler is enqueued.
|
/// Occurs when a handler is enqueued.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="args">The <see cref="DescribedHandlerDescriptor"/> for the enqueued handler.</param>
|
public event HandlerEnqueued? HandlerEnqueued;
|
||||||
public delegate void HandlerEnqueued(DescribedHandlerDescriptor args);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a delegate for when a handler is executing.
|
/// Occurs when a handler is entering execution.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="args">The <see cref="DescribedHandlerDescriptor"/> for the executing handler.</param>
|
public event HandlerExecuting? HandlerExecuting;
|
||||||
public delegate void HandlerExecuting(DescribedHandlerDescriptor args);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides a pool for managing the execution and queuing of update handlers.
|
/// Enqueues a collection of handlers for execution.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IUpdateHandlersPool : IDisposable
|
/// <param name="handlers">The handlers to enqueue.</param>
|
||||||
{
|
public Task Enqueue(params IEnumerable<DescribedHandlerDescriptor> handlers);
|
||||||
/// <summary>
|
|
||||||
/// Occurs when a handler is enqueued.
|
|
||||||
/// </summary>
|
|
||||||
public event HandlerEnqueued? HandlerEnqueued;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Occurs when a handler is entering execution.
|
|
||||||
/// </summary>
|
|
||||||
public event HandlerExecuting? HandlerExecuting;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Enqueues a collection of handlers for execution.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handlers">The handlers to enqueue.</param>
|
|
||||||
public Task Enqueue(params IEnumerable<DescribedHandlerDescriptor> handlers);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,47 +2,46 @@
|
|||||||
using Telegrator.Core.Handlers;
|
using Telegrator.Core.Handlers;
|
||||||
using Telegrator.Core.States;
|
using Telegrator.Core.States;
|
||||||
|
|
||||||
namespace Telegrator.Core
|
namespace Telegrator.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for update routers that handle incoming updates and manage handler execution.
|
||||||
|
/// Combines update handling capabilities with polling provider functionality and exception handling.
|
||||||
|
/// </summary>
|
||||||
|
public interface IUpdateRouter : IUpdateHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interface for update routers that handle incoming updates and manage handler execution.
|
/// Gets the <see cref="TelegratorOptions"/> for the router.
|
||||||
/// Combines update handling capabilities with polling provider functionality and exception handling.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IUpdateRouter : IUpdateHandler
|
public TelegratorOptions Options { get; }
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="TelegratorOptions"/> for the router.
|
|
||||||
/// </summary>
|
|
||||||
public TelegratorOptions Options { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="IUpdateHandlersPool"/> that manages handler execution.
|
/// Gets the <see cref="IUpdateHandlersPool"/> that manages handler execution.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IUpdateHandlersPool HandlersPool { get; }
|
public IUpdateHandlersPool HandlersPool { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="IHandlersProvider"/> that manages handlers for polling.
|
/// Gets the <see cref="IHandlersProvider"/> that manages handlers for polling.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IHandlersProvider HandlersProvider { get; }
|
public IHandlersProvider HandlersProvider { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="IAwaitingProvider"/> that manages awaiting handlers for polling.
|
/// Gets the <see cref="IAwaitingProvider"/> that manages awaiting handlers for polling.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IAwaitingProvider AwaitingProvider { get; }
|
public IAwaitingProvider AwaitingProvider { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="IStateStorage"/> that manages storing of handlers state.
|
/// Gets the <see cref="IStateStorage"/> that manages storing of handlers state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IStateStorage StateStorage { get; }
|
public IStateStorage StateStorage { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="IRouterExceptionHandler"/> for handling exceptions.
|
/// Gets or sets the <see cref="IRouterExceptionHandler"/> for handling exceptions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IRouterExceptionHandler? ExceptionHandler { get; set; }
|
public IRouterExceptionHandler? ExceptionHandler { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default hand;er container factory
|
/// Default hand;er container factory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IHandlerContainerFactory? DefaultContainerFactory { get; set; }
|
public IHandlerContainerFactory? DefaultContainerFactory { get; set; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+118
-119
@@ -1,134 +1,133 @@
|
|||||||
namespace Telegrator
|
namespace Telegrator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enumeration of dice types supported by Telegram.
|
||||||
|
/// Used for filtering dice messages and determining dice emoji representations.
|
||||||
|
/// </summary>
|
||||||
|
public enum DiceType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enumeration of dice types supported by Telegram.
|
/// Standard dice (🎲).
|
||||||
/// Used for filtering dice messages and determining dice emoji representations.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum DiceType
|
Dice,
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Standard dice (🎲).
|
|
||||||
/// </summary>
|
|
||||||
Dice,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Darts (🎯).
|
|
||||||
/// </summary>
|
|
||||||
Darts,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Bowling (🎳).
|
|
||||||
/// </summary>
|
|
||||||
Bowling,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Basketball (🏀).
|
|
||||||
/// </summary>
|
|
||||||
Basketball,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Football (⚽).
|
|
||||||
/// </summary>
|
|
||||||
Football,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Casino slot machine (🎰).
|
|
||||||
/// </summary>
|
|
||||||
Casino
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Flags version of <see cref="Telegram.Bot.Types.Enums.ChatType"/>
|
/// Darts (🎯).
|
||||||
/// Type of the <see cref="Telegram.Bot.Types.Chat"/>, from which the message or inline query was sent
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Flags]
|
Darts,
|
||||||
public enum ChatTypeFlags
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Normal one-to-one chat with a user or bot
|
|
||||||
/// </summary>
|
|
||||||
Private = 0x1,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Normal group chat
|
|
||||||
/// </summary>
|
|
||||||
Group = 0x2,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A channel
|
|
||||||
/// </summary>
|
|
||||||
Channel = 0x4,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A supergroup
|
|
||||||
/// </summary>
|
|
||||||
Supergroup = 0x8,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Value possible only in <see cref="Telegram.Bot.Types.InlineQuery.ChatType"/>: private chat with the inline query sender
|
|
||||||
/// </summary>
|
|
||||||
Sender
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Messages from where this filter was originated
|
/// Bowling (🎳).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum FilterOrigin
|
Bowling,
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// None, empty filter
|
|
||||||
/// </summary>
|
|
||||||
None,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// From <see cref="Attributes.UpdateHandlerAttribute{T}"/> update validator filter
|
|
||||||
/// </summary>
|
|
||||||
Validator,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// From <see cref="Attributes.StateKeeperAttribute{TKey, TState, TKeeper}"/> state machine filter
|
|
||||||
/// </summary>
|
|
||||||
StateKeeper,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// From regular <see cref="Attributes.UpdateFilterAttribute{T}"/>
|
|
||||||
/// </summary>
|
|
||||||
Regualr
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Levels of debug writing
|
/// Basketball (🏀).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Flags]
|
Basketball,
|
||||||
public enum DebugLevel
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// None to write
|
|
||||||
/// </summary>
|
|
||||||
None = 0x0,
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write debug messages from filters execution
|
/// Football (⚽).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Filters = 0x1,
|
Football,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write debug messages from handlers providers execution
|
/// Casino slot machine (🎰).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Providers = 0x2,
|
Casino
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Write debug messages from update router's execution
|
|
||||||
/// </summary>
|
|
||||||
Router = 0x4,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Write debug messages from handlers pool execution
|
|
||||||
/// </summary>
|
|
||||||
HandlersPool = 0x8
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flags version of <see cref="Telegram.Bot.Types.Enums.ChatType"/>
|
||||||
|
/// Type of the <see cref="Telegram.Bot.Types.Chat"/>, from which the message or inline query was sent
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum ChatTypeFlags
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Normal one-to-one chat with a user or bot
|
||||||
|
/// </summary>
|
||||||
|
Private = 0x1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Normal group chat
|
||||||
|
/// </summary>
|
||||||
|
Group = 0x2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A channel
|
||||||
|
/// </summary>
|
||||||
|
Channel = 0x4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A supergroup
|
||||||
|
/// </summary>
|
||||||
|
Supergroup = 0x8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Value possible only in <see cref="Telegram.Bot.Types.InlineQuery.ChatType"/>: private chat with the inline query sender
|
||||||
|
/// </summary>
|
||||||
|
Sender
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
/// <summary>
|
||||||
|
/// Messages from where this filter was originated
|
||||||
|
/// </summary>
|
||||||
|
public enum FilterOrigin
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// None, empty filter
|
||||||
|
/// </summary>
|
||||||
|
None,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// From <see cref="Attributes.UpdateHandlerAttribute{T}"/> update validator filter
|
||||||
|
/// </summary>
|
||||||
|
Validator,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// From <see cref="Attributes.StateKeeperAttribute{TKey, TState, TKeeper}"/> state machine filter
|
||||||
|
/// </summary>
|
||||||
|
StateKeeper,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// From regular <see cref="Attributes.UpdateFilterAttribute{T}"/>
|
||||||
|
/// </summary>
|
||||||
|
Regualr
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
/// <summary>
|
||||||
|
/// Levels of debug writing
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum DebugLevel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// None to write
|
||||||
|
/// </summary>
|
||||||
|
None = 0x0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write debug messages from filters execution
|
||||||
|
/// </summary>
|
||||||
|
Filters = 0x1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write debug messages from handlers providers execution
|
||||||
|
/// </summary>
|
||||||
|
Providers = 0x2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write debug messages from update router's execution
|
||||||
|
/// </summary>
|
||||||
|
Router = 0x4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write debug messages from handlers pool execution
|
||||||
|
/// </summary>
|
||||||
|
HandlersPool = 0x8
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|||||||
@@ -1,52 +1,51 @@
|
|||||||
using Telegrator.Core.Descriptors;
|
using Telegrator.Core.Descriptors;
|
||||||
|
|
||||||
namespace Telegrator
|
namespace Telegrator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exception thrown when attempting to modify a frozen collection.
|
||||||
|
/// </summary>
|
||||||
|
public class CollectionFrozenException : Exception
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Exception thrown when attempting to modify a frozen collection.
|
/// Initializes a new instance of the <see cref="CollectionFrozenException"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CollectionFrozenException : Exception
|
public CollectionFrozenException()
|
||||||
{
|
: base("Can't change a frozen collection.") { }
|
||||||
/// <summary>
|
}
|
||||||
/// Initializes a new instance of the <see cref="CollectionFrozenException"/> class.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public CollectionFrozenException()
|
/// Exception thrown when a type is not a valid filter type.
|
||||||
: base("Can't change a frozen collection.") { }
|
/// </summary>
|
||||||
}
|
public class NotFilterTypeException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="NotFilterTypeException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type that is not a filter type.</param>
|
||||||
|
public NotFilterTypeException(Type type)
|
||||||
|
: base(string.Format("\"{0}\" is not a filter type", type.Name)) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exception thrown when a handler execution fails.
|
||||||
|
/// Contains information about the handler and the inner exception.
|
||||||
|
/// </summary>
|
||||||
|
public class HandlerFaultedException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The handler info associated with the faulted handler.
|
||||||
|
/// </summary>
|
||||||
|
public readonly DescribedHandlerDescriptor HandlerInfo;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Exception thrown when a type is not a valid filter type.
|
/// Initializes a new instance of the <see cref="HandlerFaultedException"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class NotFilterTypeException : Exception
|
/// <param name="handlerInfo">The handler info.</param>
|
||||||
|
/// <param name="inner">The inner exception.</param>
|
||||||
|
public HandlerFaultedException(DescribedHandlerDescriptor handlerInfo, Exception inner)
|
||||||
|
: base(string.Format("Handler's \"{0}\" execution was faulted", handlerInfo.DisplayString), inner)
|
||||||
{
|
{
|
||||||
/// <summary>
|
HandlerInfo = handlerInfo;
|
||||||
/// Initializes a new instance of the <see cref="NotFilterTypeException"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The type that is not a filter type.</param>
|
|
||||||
public NotFilterTypeException(Type type)
|
|
||||||
: base(string.Format("\"{0}\" is not a filter type", type.Name)) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Exception thrown when a handler execution fails.
|
|
||||||
/// Contains information about the handler and the inner exception.
|
|
||||||
/// </summary>
|
|
||||||
public class HandlerFaultedException : Exception
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The handler info associated with the faulted handler.
|
|
||||||
/// </summary>
|
|
||||||
public readonly DescribedHandlerDescriptor HandlerInfo;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HandlerFaultedException"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handlerInfo">The handler info.</param>
|
|
||||||
/// <param name="inner">The inner exception.</param>
|
|
||||||
public HandlerFaultedException(DescribedHandlerDescriptor handlerInfo, Exception inner)
|
|
||||||
: base(string.Format("Handler's \"{0}\" execution was faulted", handlerInfo.DisplayString), inner)
|
|
||||||
{
|
|
||||||
HandlerInfo = handlerInfo;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,72 +2,71 @@
|
|||||||
using Telegram.Bot.Types;
|
using Telegram.Bot.Types;
|
||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Filters
|
namespace Telegrator.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter thet checks <see cref="CallbackQuery"/>'s data
|
||||||
|
/// </summary>
|
||||||
|
public class CallbackDataFilter : Filter<CallbackQuery>
|
||||||
{
|
{
|
||||||
|
private readonly string _data;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filter thet checks <see cref="CallbackQuery"/>'s data
|
/// Initialize new instance of <see cref="CallbackDataFilter"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CallbackDataFilter : Filter<CallbackQuery>
|
/// <param name="data"></param>
|
||||||
|
public CallbackDataFilter(string data)
|
||||||
{
|
{
|
||||||
private readonly string _data;
|
_data = data;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initialize new instance of <see cref="CallbackDataFilter"/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data"></param>
|
|
||||||
public CallbackDataFilter(string data)
|
|
||||||
{
|
|
||||||
_data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override bool CanPass(FilterExecutionContext<CallbackQuery> context)
|
|
||||||
{
|
|
||||||
return context.Input.Data == _data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc/>
|
||||||
/// Filter that checks if <see cref="CallbackQuery"/> belongs to a specific message
|
public override bool CanPass(FilterExecutionContext<CallbackQuery> context)
|
||||||
/// </summary>
|
|
||||||
public class CallbackInlineIdFilter : Filter<CallbackQuery>
|
|
||||||
{
|
{
|
||||||
private readonly string _inlineMessageId;
|
return context.Input.Data == _data;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initialize new instance of <see cref="CallbackInlineIdFilter"/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inlineMessageId"></param>
|
|
||||||
public CallbackInlineIdFilter(string inlineMessageId)
|
|
||||||
{
|
|
||||||
_inlineMessageId = inlineMessageId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override bool CanPass(FilterExecutionContext<CallbackQuery> context)
|
|
||||||
{
|
|
||||||
return context.Input.InlineMessageId == _inlineMessageId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Filters callback queries by matching their data with a regular expression.
|
|
||||||
/// </summary>
|
|
||||||
public class CallbackRegexFilter : RegexFilterBase<CallbackQuery>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="CallbackRegexFilter"/> class with a pattern and options.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pattern">The regex pattern.</param>
|
|
||||||
/// <param name="regexOptions">The regex options.</param>
|
|
||||||
public CallbackRegexFilter(string pattern, RegexOptions regexOptions = default)
|
|
||||||
: base(clb => clb.Data, pattern, regexOptions) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="CallbackRegexFilter"/> class with a regex object.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="regex">The regex object.</param>
|
|
||||||
public CallbackRegexFilter(Regex regex)
|
|
||||||
: base(clb => clb.Data, regex) { }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks if <see cref="CallbackQuery"/> belongs to a specific message
|
||||||
|
/// </summary>
|
||||||
|
public class CallbackInlineIdFilter : Filter<CallbackQuery>
|
||||||
|
{
|
||||||
|
private readonly string _inlineMessageId;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize new instance of <see cref="CallbackInlineIdFilter"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="inlineMessageId"></param>
|
||||||
|
public CallbackInlineIdFilter(string inlineMessageId)
|
||||||
|
{
|
||||||
|
_inlineMessageId = inlineMessageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool CanPass(FilterExecutionContext<CallbackQuery> context)
|
||||||
|
{
|
||||||
|
return context.Input.InlineMessageId == _inlineMessageId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters callback queries by matching their data with a regular expression.
|
||||||
|
/// </summary>
|
||||||
|
public class CallbackRegexFilter : RegexFilterBase<CallbackQuery>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CallbackRegexFilter"/> class with a pattern and options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pattern">The regex pattern.</param>
|
||||||
|
/// <param name="regexOptions">The regex options.</param>
|
||||||
|
public CallbackRegexFilter(string pattern, RegexOptions regexOptions = default)
|
||||||
|
: base(clb => clb.Data, pattern, regexOptions) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CallbackRegexFilter"/> class with a regex object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="regex">The regex object.</param>
|
||||||
|
public CallbackRegexFilter(Regex regex)
|
||||||
|
: base(clb => clb.Data, regex) { }
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,31 +2,30 @@
|
|||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
using Telegrator.Handlers;
|
using Telegrator.Handlers;
|
||||||
|
|
||||||
namespace Telegrator.Filters
|
namespace Telegrator.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks if a command matches any of the specified aliases.
|
||||||
|
/// Requires a <see cref="CommandHandlerAttribute"/> to be applied first to extract the command.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="alliases">The command aliases to check against.</param>
|
||||||
|
public class CommandAlliasFilter(params string[] alliases) : Filter<Message>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filter that checks if a command matches any of the specified aliases.
|
/// Gets the command that was received and extracted by the <see cref="CommandHandlerAttribute"/>.
|
||||||
/// Requires a <see cref="CommandHandlerAttribute"/> to be applied first to extract the command.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="alliases">The command aliases to check against.</param>
|
public string ReceivedCommand { get; private set; } = string.Empty;
|
||||||
public class CommandAlliasFilter(params string[] alliases) : Filter<Message>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the command that was received and extracted by the <see cref="CommandHandlerAttribute"/>.
|
|
||||||
/// </summary>
|
|
||||||
public string ReceivedCommand { get; private set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if the received command matches any of the specified aliases.
|
/// Checks if the received command matches any of the specified aliases.
|
||||||
/// This filter requires a <see cref="CommandHandlerAttribute"/> to be applied first
|
/// This filter requires a <see cref="CommandHandlerAttribute"/> to be applied first
|
||||||
/// to extract the command from the message.
|
/// to extract the command from the message.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">The filter execution context containing the completed filters.</param>
|
/// <param name="context">The filter execution context containing the completed filters.</param>
|
||||||
/// <returns>True if the command matches any of the specified aliases; otherwise, false.</returns>
|
/// <returns>True if the command matches any of the specified aliases; otherwise, false.</returns>
|
||||||
public override bool CanPass(FilterExecutionContext<Message> context)
|
public override bool CanPass(FilterExecutionContext<Message> context)
|
||||||
{
|
{
|
||||||
ReceivedCommand = context.CompletedFilters.Get<CommandHandlerAttribute>(0).ReceivedCommand;
|
ReceivedCommand = context.CompletedFilters.Get<CommandHandlerAttribute>(0).ReceivedCommand;
|
||||||
return alliases.Contains(ReceivedCommand, StringComparer.InvariantCultureIgnoreCase);
|
return alliases.Contains(ReceivedCommand, StringComparer.InvariantCultureIgnoreCase);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,203 +3,202 @@ using Telegram.Bot.Types;
|
|||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
using Telegrator.Handlers;
|
using Telegrator.Handlers;
|
||||||
|
|
||||||
namespace Telegrator.Filters
|
namespace Telegrator.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract base class for filters that operate on command arguments.
|
||||||
|
/// Provides functionality to extract and validate command arguments from message text.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The index of the argument to filter (0-based).</param>
|
||||||
|
public abstract class CommandArgumentFilterBase(int index) : Filter<Message>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstract base class for filters that operate on command arguments.
|
/// Gets the chosen argument at the specified index.
|
||||||
/// Provides functionality to extract and validate command arguments from message text.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index">The index of the argument to filter (0-based).</param>
|
protected string Target { get; private set; } = null!;
|
||||||
public abstract class CommandArgumentFilterBase(int index) : Filter<Message>
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the filter can pass by extracting the command argument and validating it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The filter execution context containing the message.</param>
|
||||||
|
/// <returns>True if the argument exists and passes validation; otherwise, false.</returns>
|
||||||
|
public override bool CanPass(FilterExecutionContext<Message> context)
|
||||||
{
|
{
|
||||||
/// <summary>
|
CommandHandlerAttribute attr = context.CompletedFilters.Get<CommandHandlerAttribute>(0);
|
||||||
/// Gets the chosen argument at the specified index.
|
string[] args = attr.Arguments ??= context.Input.SplitArgs();
|
||||||
/// </summary>
|
Target = args.ElementAtOrDefault(index);
|
||||||
protected string Target { get; private set; } = null!;
|
|
||||||
|
|
||||||
/// <summary>
|
if (Target == null)
|
||||||
/// Determines whether the filter can pass by extracting the command argument and validating it.
|
return false;
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The filter execution context containing the message.</param>
|
|
||||||
/// <returns>True if the argument exists and passes validation; otherwise, false.</returns>
|
|
||||||
public override bool CanPass(FilterExecutionContext<Message> context)
|
|
||||||
{
|
|
||||||
CommandHandlerAttribute attr = context.CompletedFilters.Get<CommandHandlerAttribute>(0);
|
|
||||||
string[] args = attr.Arguments ??= context.Input.SplitArgs();
|
|
||||||
Target = args.ElementAtOrDefault(index);
|
|
||||||
|
|
||||||
if (Target == null)
|
return CanPassNext(context);
|
||||||
return false;
|
|
||||||
|
|
||||||
return CanPassNext(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether the filter can pass for the given context.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The filter execution context.</param>
|
|
||||||
/// <returns>True if the filter passes; otherwise, false.</returns>
|
|
||||||
protected abstract bool CanPassNext(FilterExecutionContext<Message> context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filter that checks if a command has arguments count >= <paramref name="count"/>.
|
/// Determines whether the filter can pass for the given context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="count"></param>
|
/// <param name="context">The filter execution context.</param>
|
||||||
public class ArgumentCountFilter(int count) : Filter<Message>
|
/// <returns>True if the filter passes; otherwise, false.</returns>
|
||||||
|
protected abstract bool CanPassNext(FilterExecutionContext<Message> context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks if a command has arguments count >= <paramref name="count"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="count"></param>
|
||||||
|
public class ArgumentCountFilter(int count) : Filter<Message>
|
||||||
|
{
|
||||||
|
private readonly int Count = count;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool CanPass(FilterExecutionContext<Message> context)
|
||||||
{
|
{
|
||||||
private readonly int Count = count;
|
CommandHandlerAttribute attr = context.CompletedFilters.Get<CommandHandlerAttribute>(0);
|
||||||
|
string[] args = attr.Arguments ??= context.Input.SplitArgs();
|
||||||
/// <inheritdoc/>
|
return args.Length >= Count;
|
||||||
public override bool CanPass(FilterExecutionContext<Message> context)
|
}
|
||||||
{
|
}
|
||||||
CommandHandlerAttribute attr = context.CompletedFilters.Get<CommandHandlerAttribute>(0);
|
|
||||||
string[] args = attr.Arguments ??= context.Input.SplitArgs();
|
/// <summary>
|
||||||
return args.Length >= Count;
|
/// Filter that checks if a command argument starts with a specified content.
|
||||||
}
|
/// </summary>
|
||||||
}
|
/// <param name="content">The content to check if the argument starts with.</param>
|
||||||
|
/// <param name="comparison">The string comparison type to use for the check.</param>
|
||||||
/// <summary>
|
/// <param name="index">The index of the argument to check (0-based).</param>
|
||||||
/// Filter that checks if a command argument starts with a specified content.
|
public class ArgumentStartsWithFilter(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0) : CommandArgumentFilterBase(index)
|
||||||
/// </summary>
|
{
|
||||||
/// <param name="content">The content to check if the argument starts with.</param>
|
/// <summary>
|
||||||
/// <param name="comparison">The string comparison type to use for the check.</param>
|
/// The content to check if the argument starts with.
|
||||||
/// <param name="index">The index of the argument to check (0-based).</param>
|
/// </summary>
|
||||||
public class ArgumentStartsWithFilter(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0) : CommandArgumentFilterBase(index)
|
protected readonly string Content = content;
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The content to check if the argument starts with.
|
/// The string comparison type to use for the check.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly string Content = content;
|
protected readonly StringComparison Comparison = comparison;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The string comparison type to use for the check.
|
/// Checks if the command argument starts with the specified content using the configured comparison.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly StringComparison Comparison = comparison;
|
/// <param name="_">The filter execution context (unused).</param>
|
||||||
|
/// <returns>True if the argument starts with the specified content; otherwise, false.</returns>
|
||||||
/// <summary>
|
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
||||||
/// Checks if the command argument starts with the specified content using the configured comparison.
|
=> Target.StartsWith(Content, Comparison);
|
||||||
/// </summary>
|
}
|
||||||
/// <param name="_">The filter execution context (unused).</param>
|
|
||||||
/// <returns>True if the argument starts with the specified content; otherwise, false.</returns>
|
/// <summary>
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
/// Filter that checks if a command argument ends with a specified content.
|
||||||
=> Target.StartsWith(Content, Comparison);
|
/// </summary>
|
||||||
}
|
/// <param name="content">The content to check if the argument ends with.</param>
|
||||||
|
/// <param name="comparison">The string comparison type to use for the check.</param>
|
||||||
/// <summary>
|
/// <param name="index">The index of the argument to check (0-based).</param>
|
||||||
/// Filter that checks if a command argument ends with a specified content.
|
public class ArgumentEndsWithFilter(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0) : CommandArgumentFilterBase(index)
|
||||||
/// </summary>
|
{
|
||||||
/// <param name="content">The content to check if the argument ends with.</param>
|
/// <summary>
|
||||||
/// <param name="comparison">The string comparison type to use for the check.</param>
|
/// The content to check if the argument ends with.
|
||||||
/// <param name="index">The index of the argument to check (0-based).</param>
|
/// </summary>
|
||||||
public class ArgumentEndsWithFilter(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0) : CommandArgumentFilterBase(index)
|
protected readonly string Content = content;
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The content to check if the argument ends with.
|
/// The string comparison type to use for the check.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly string Content = content;
|
protected readonly StringComparison Comparison = comparison;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The string comparison type to use for the check.
|
/// Checks if the command argument ends with the specified content using the configured comparison.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly StringComparison Comparison = comparison;
|
/// <param name="_">The filter execution context (unused).</param>
|
||||||
|
/// <returns>True if the argument ends with the specified content; otherwise, false.</returns>
|
||||||
/// <summary>
|
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
||||||
/// Checks if the command argument ends with the specified content using the configured comparison.
|
=> Target.EndsWith(Content, Comparison);
|
||||||
/// </summary>
|
}
|
||||||
/// <param name="_">The filter execution context (unused).</param>
|
|
||||||
/// <returns>True if the argument ends with the specified content; otherwise, false.</returns>
|
/// <summary>
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
/// Filter that checks if a command argument contains a specified content.
|
||||||
=> Target.EndsWith(Content, Comparison);
|
/// </summary>
|
||||||
}
|
/// <param name="content">The content to check if the argument contains.</param>
|
||||||
|
/// <param name="comparison">The string comparison type to use for the check.</param>
|
||||||
/// <summary>
|
/// <param name="index">The index of the argument to check (0-based).</param>
|
||||||
/// Filter that checks if a command argument contains a specified content.
|
public class ArgumentContainsFilter(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0) : CommandArgumentFilterBase(index)
|
||||||
/// </summary>
|
{
|
||||||
/// <param name="content">The content to check if the argument contains.</param>
|
/// <summary>
|
||||||
/// <param name="comparison">The string comparison type to use for the check.</param>
|
/// The content to check if the argument contains.
|
||||||
/// <param name="index">The index of the argument to check (0-based).</param>
|
/// </summary>
|
||||||
public class ArgumentContainsFilter(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0) : CommandArgumentFilterBase(index)
|
protected readonly string Content = content;
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The content to check if the argument contains.
|
/// The string comparison type to use for the check.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly string Content = content;
|
protected readonly StringComparison Comparison = comparison;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The string comparison type to use for the check.
|
/// Checks if the command argument contains the specified content using the configured comparison.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly StringComparison Comparison = comparison;
|
/// <param name="_">The filter execution context (unused).</param>
|
||||||
|
/// <returns>True if the argument contains the specified content; otherwise, false.</returns>
|
||||||
/// <summary>
|
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
||||||
/// Checks if the command argument contains the specified content using the configured comparison.
|
=> Target.IndexOf(Content, Comparison) >= 0;
|
||||||
/// </summary>
|
}
|
||||||
/// <param name="_">The filter execution context (unused).</param>
|
|
||||||
/// <returns>True if the argument contains the specified content; otherwise, false.</returns>
|
/// <summary>
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
/// Filter that checks if a command argument equals a specified content.
|
||||||
=> Target.IndexOf(Content, Comparison) >= 0;
|
/// </summary>
|
||||||
}
|
/// <param name="content">The content to check if the argument equals.</param>
|
||||||
|
/// <param name="comparison">The string comparison type to use for the check.</param>
|
||||||
/// <summary>
|
/// <param name="index">The index of the argument to check (0-based).</param>
|
||||||
/// Filter that checks if a command argument equals a specified content.
|
public class ArgumentEqualsFilter(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0) : CommandArgumentFilterBase(index)
|
||||||
/// </summary>
|
{
|
||||||
/// <param name="content">The content to check if the argument equals.</param>
|
/// <summary>
|
||||||
/// <param name="comparison">The string comparison type to use for the check.</param>
|
/// The content to check if the argument equals.
|
||||||
/// <param name="index">The index of the argument to check (0-based).</param>
|
/// </summary>
|
||||||
public class ArgumentEqualsFilter(string content, StringComparison comparison = StringComparison.InvariantCulture, int index = 0) : CommandArgumentFilterBase(index)
|
protected readonly string Content = content;
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The content to check if the argument equals.
|
/// The string comparison type to use for the check.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly string Content = content;
|
protected readonly StringComparison Comparison = comparison;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The string comparison type to use for the check.
|
/// Checks if the command argument equals the specified content using the configured comparison.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly StringComparison Comparison = comparison;
|
/// <param name="_">The filter execution context (unused).</param>
|
||||||
|
/// <returns>True if the argument equals the specified content; otherwise, false.</returns>
|
||||||
/// <summary>
|
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
||||||
/// Checks if the command argument equals the specified content using the configured comparison.
|
=> Target.Equals(Content, Comparison);
|
||||||
/// </summary>
|
}
|
||||||
/// <param name="_">The filter execution context (unused).</param>
|
|
||||||
/// <returns>True if the argument equals the specified content; otherwise, false.</returns>
|
/// <summary>
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
/// Filter that checks if a command argument matches a regular expression pattern.
|
||||||
=> Target.Equals(Content, Comparison);
|
/// </summary>
|
||||||
}
|
/// <param name="regex">The regular expression to match against the argument.</param>
|
||||||
|
/// <param name="index">The index of the argument to check (0-based).</param>
|
||||||
/// <summary>
|
public class ArgumentRegexFilter(Regex regex, int index = 0) : CommandArgumentFilterBase(index)
|
||||||
/// Filter that checks if a command argument matches a regular expression pattern.
|
{
|
||||||
/// </summary>
|
private readonly Regex _regex = regex;
|
||||||
/// <param name="regex">The regular expression to match against the argument.</param>
|
|
||||||
/// <param name="index">The index of the argument to check (0-based).</param>
|
/// <summary>
|
||||||
public class ArgumentRegexFilter(Regex regex, int index = 0) : CommandArgumentFilterBase(index)
|
/// Gets the match found by the regex.
|
||||||
{
|
/// </summary>
|
||||||
private readonly Regex _regex = regex;
|
public Match Match { get; private set; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the match found by the regex.
|
/// Initializes a new instance of <see cref="ArgumentRegexFilter"/> with a regex pattern.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Match Match { get; private set; } = null!;
|
/// <param name="pattern">The regular expression pattern to match.</param>
|
||||||
|
/// <param name="options">The regex options to use.</param>
|
||||||
/// <summary>
|
/// <param name="matchTimeout">The timeout for the regex match operation.</param>
|
||||||
/// Initializes a new instance of <see cref="ArgumentRegexFilter"/> with a regex pattern.
|
/// <param name="index">The index of the argument to check (0-based).</param>
|
||||||
/// </summary>
|
public ArgumentRegexFilter(string pattern, RegexOptions options = RegexOptions.None, TimeSpan matchTimeout = default, int index = 0)
|
||||||
/// <param name="pattern">The regular expression pattern to match.</param>
|
: this(new Regex(pattern, options, matchTimeout), index) { }
|
||||||
/// <param name="options">The regex options to use.</param>
|
|
||||||
/// <param name="matchTimeout">The timeout for the regex match operation.</param>
|
/// <summary>
|
||||||
/// <param name="index">The index of the argument to check (0-based).</param>
|
/// Checks if the command argument matches the regular expression pattern.
|
||||||
public ArgumentRegexFilter(string pattern, RegexOptions options = RegexOptions.None, TimeSpan matchTimeout = default, int index = 0)
|
/// </summary>
|
||||||
: this(new Regex(pattern, options, matchTimeout), index) { }
|
/// <param name="context">The filter execution context.</param>
|
||||||
|
/// <returns>True if the argument matches the regex pattern; otherwise, false.</returns>
|
||||||
/// <summary>
|
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
||||||
/// Checks if the command argument matches the regular expression pattern.
|
{
|
||||||
/// </summary>
|
Match = _regex.Match(Target);
|
||||||
/// <param name="context">The filter execution context.</param>
|
return Match.Success;
|
||||||
/// <returns>True if the argument matches the regex pattern; otherwise, false.</returns>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
|
||||||
{
|
|
||||||
Match = _regex.Match(Target);
|
|
||||||
return Match.Success;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,124 +2,123 @@
|
|||||||
using Telegram.Bot.Types;
|
using Telegram.Bot.Types;
|
||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Filters
|
namespace Telegrator.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract base class for filters that operate based on the current environment.
|
||||||
|
/// Provides functionality to detect debug vs release environments.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class EnvironmentFilter : Filter<Update>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstract base class for filters that operate based on the current environment.
|
/// Gets a value indicating whether the current environment is debug mode.
|
||||||
/// Provides functionality to detect debug vs release environments.
|
/// This is set during static initialization based on the DEBUG conditional compilation symbol.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class EnvironmentFilter : Filter<Update>
|
protected static bool IsCurrentEnvDebug { get; private set; } = false;
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the current environment is debug mode.
|
|
||||||
/// This is set during static initialization based on the DEBUG conditional compilation symbol.
|
|
||||||
/// </summary>
|
|
||||||
protected static bool IsCurrentEnvDebug { get; private set; } = false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Static constructor that initializes the environment detection.
|
|
||||||
/// </summary>
|
|
||||||
static EnvironmentFilter()
|
|
||||||
=> SetIsCurrentEnvDebug();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the debug environment flag. This method is only compiled in DEBUG builds.
|
|
||||||
/// </summary>
|
|
||||||
[Conditional("DEBUG")]
|
|
||||||
private static void SetIsCurrentEnvDebug()
|
|
||||||
=> IsCurrentEnvDebug = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filter that only passes in debug environment builds.
|
/// Static constructor that initializes the environment detection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class IsDebugEnvironmentFilter() : EnvironmentFilter
|
static EnvironmentFilter()
|
||||||
{
|
=> SetIsCurrentEnvDebug();
|
||||||
/// <summary>
|
|
||||||
/// Checks if the current environment is debug mode.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="_">The filter execution context (unused).</param>
|
|
||||||
/// <returns>True if the current environment is debug mode; otherwise, false.</returns>
|
|
||||||
public override bool CanPass(FilterExecutionContext<Update> _)
|
|
||||||
=> IsCurrentEnvDebug;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filter that only passes in release environment builds.
|
/// Sets the debug environment flag. This method is only compiled in DEBUG builds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class IsReleaseEnvironmentFilter() : EnvironmentFilter
|
[Conditional("DEBUG")]
|
||||||
{
|
private static void SetIsCurrentEnvDebug()
|
||||||
/// <summary>
|
=> IsCurrentEnvDebug = true;
|
||||||
/// Checks if the current environment is release mode.
|
}
|
||||||
/// </summary>
|
|
||||||
/// <param name="_">The filter execution context (unused).</param>
|
/// <summary>
|
||||||
/// <returns>True if the current environment is release mode; otherwise, false.</returns>
|
/// Filter that only passes in debug environment builds.
|
||||||
public override bool CanPass(FilterExecutionContext<Update> _)
|
/// </summary>
|
||||||
=> !IsCurrentEnvDebug;
|
public class IsDebugEnvironmentFilter() : EnvironmentFilter
|
||||||
}
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the current environment is debug mode.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="_">The filter execution context (unused).</param>
|
||||||
|
/// <returns>True if the current environment is debug mode; otherwise, false.</returns>
|
||||||
|
public override bool CanPass(FilterExecutionContext<Update> _)
|
||||||
|
=> IsCurrentEnvDebug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that only passes in release environment builds.
|
||||||
|
/// </summary>
|
||||||
|
public class IsReleaseEnvironmentFilter() : EnvironmentFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the current environment is release mode.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="_">The filter execution context (unused).</param>
|
||||||
|
/// <returns>True if the current environment is release mode; otherwise, false.</returns>
|
||||||
|
public override bool CanPass(FilterExecutionContext<Update> _)
|
||||||
|
=> !IsCurrentEnvDebug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks environment variable values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="variable">The environment variable name to check.</param>
|
||||||
|
/// <param name="value">The expected value of the environment variable (optional).</param>
|
||||||
|
/// <param name="comparison">The string comparison type to use for value matching.</param>
|
||||||
|
public class EnvironmentVariableFilter(string variable, string? value, StringComparison comparison) : Filter<Update>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The environment variable name to check.
|
||||||
|
/// </summary>
|
||||||
|
private readonly string _variable = variable;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filter that checks environment variable values.
|
/// The expected value of the environment variable (optional).
|
||||||
|
/// </summary>
|
||||||
|
private readonly string? _value = value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The string comparison type to use for value matching.
|
||||||
|
/// </summary>
|
||||||
|
private readonly StringComparison _comparison = comparison;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="EnvironmentVariableFilter"/> class with a specific value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="variable">The environment variable name to check.</param>
|
/// <param name="variable">The environment variable name to check.</param>
|
||||||
/// <param name="value">The expected value of the environment variable (optional).</param>
|
/// <param name="value">The expected value of the environment variable.</param>
|
||||||
/// <param name="comparison">The string comparison type to use for value matching.</param>
|
public EnvironmentVariableFilter(string variable, string? value)
|
||||||
public class EnvironmentVariableFilter(string variable, string? value, StringComparison comparison) : Filter<Update>
|
: this(variable, value, StringComparison.InvariantCulture) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="EnvironmentVariableFilter"/> class that checks for non-null values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="variable">The environment variable name to check.</param>
|
||||||
|
public EnvironmentVariableFilter(string variable)
|
||||||
|
: this(variable, "{NOT_NULL}", StringComparison.InvariantCulture) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="EnvironmentVariableFilter"/> class with custom comparison.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="variable">The environment variable name to check.</param>
|
||||||
|
/// <param name="comparison">The string comparison type to use.</param>
|
||||||
|
public EnvironmentVariableFilter(string variable, StringComparison comparison)
|
||||||
|
: this(variable, "{NOT_NULL}", comparison) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the environment variable matches the expected criteria.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="_">The filter execution context (unused).</param>
|
||||||
|
/// <returns>True if the environment variable matches the criteria; otherwise, false.</returns>
|
||||||
|
public override bool CanPass(FilterExecutionContext<Update> _)
|
||||||
{
|
{
|
||||||
/// <summary>
|
string? envValue = Environment.GetEnvironmentVariable(_variable);
|
||||||
/// The environment variable name to check.
|
|
||||||
/// </summary>
|
|
||||||
private readonly string _variable = variable;
|
|
||||||
|
|
||||||
/// <summary>
|
if (envValue == null)
|
||||||
/// The expected value of the environment variable (optional).
|
return _value == null;
|
||||||
/// </summary>
|
|
||||||
private readonly string? _value = value;
|
|
||||||
|
|
||||||
/// <summary>
|
if (_value == "{NOT_NULL}")
|
||||||
/// The string comparison type to use for value matching.
|
return true;
|
||||||
/// </summary>
|
|
||||||
private readonly StringComparison _comparison = comparison;
|
|
||||||
|
|
||||||
/// <summary>
|
return envValue.Equals(_value, _comparison);
|
||||||
/// Initializes a new instance of the <see cref="EnvironmentVariableFilter"/> class with a specific value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="variable">The environment variable name to check.</param>
|
|
||||||
/// <param name="value">The expected value of the environment variable.</param>
|
|
||||||
public EnvironmentVariableFilter(string variable, string? value)
|
|
||||||
: this(variable, value, StringComparison.InvariantCulture) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="EnvironmentVariableFilter"/> class that checks for non-null values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="variable">The environment variable name to check.</param>
|
|
||||||
public EnvironmentVariableFilter(string variable)
|
|
||||||
: this(variable, "{NOT_NULL}", StringComparison.InvariantCulture) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="EnvironmentVariableFilter"/> class with custom comparison.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="variable">The environment variable name to check.</param>
|
|
||||||
/// <param name="comparison">The string comparison type to use.</param>
|
|
||||||
public EnvironmentVariableFilter(string variable, StringComparison comparison)
|
|
||||||
: this(variable, "{NOT_NULL}", comparison) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the environment variable matches the expected criteria.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="_">The filter execution context (unused).</param>
|
|
||||||
/// <returns>True if the environment variable matches the criteria; otherwise, false.</returns>
|
|
||||||
public override bool CanPass(FilterExecutionContext<Update> _)
|
|
||||||
{
|
|
||||||
string? envValue = Environment.GetEnvironmentVariable(_variable);
|
|
||||||
|
|
||||||
if (envValue == null)
|
|
||||||
return _value == null;
|
|
||||||
|
|
||||||
if (_value == "{NOT_NULL}")
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return envValue.Equals(_value, _comparison);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+118
-119
@@ -1,135 +1,134 @@
|
|||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Filters
|
namespace Telegrator.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for filters, providing logical operations and collectability.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
||||||
|
public abstract class Filter<T> : IFilter<T> where T : class
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base class for filters, providing logical operations and collectability.
|
/// Creates a filter from a function.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
/// <param name="filter">The filter function.</param>
|
||||||
public abstract class Filter<T> : IFilter<T> where T : class
|
/// <returns>A <see cref="Filter{T}"/> instance.</returns>
|
||||||
{
|
public static Filter<T> If(Func<FilterExecutionContext<T>, bool> filter)
|
||||||
/// <summary>
|
=> new FunctionFilter<T>(filter);
|
||||||
/// Creates a filter from a function.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filter">The filter function.</param>
|
|
||||||
/// <returns>A <see cref="Filter{T}"/> instance.</returns>
|
|
||||||
public static Filter<T> If(Func<FilterExecutionContext<T>, bool> filter)
|
|
||||||
=> new FunctionFilter<T>(filter);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a filter that always passes.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>An <see cref="AnyFilter{T}"/> instance.</returns>
|
|
||||||
public static AnyFilter<T> Any()
|
|
||||||
=> new AnyFilter<T>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a filter that inverts the result of this filter.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A <see cref="ReverseFilter{T}"/> instance.</returns>
|
|
||||||
public Filter<T> Not()
|
|
||||||
=> new ReverseFilter<T>(this);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a filter that inverts the result of this filter.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="Q"></typeparam>
|
|
||||||
/// <returns>A <see cref="ReverseFilter{T}"/> instance.</returns>
|
|
||||||
public static Filter<Q> Not<Q>(IFilter<Q> filter) where Q : class
|
|
||||||
=> new ReverseFilter<Q>(filter);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a filter that passes only if both this and the specified filter pass.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filter">The filter to combine with.</param>
|
|
||||||
/// <returns>An <see cref="AndFilter{T}"/> instance.</returns>
|
|
||||||
public AndFilter<T> And(IFilter<T> filter)
|
|
||||||
=> new AndFilter<T>(this, filter);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a filter that passes if either this or the specified filter pass.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filter">The filter to combine with.</param>
|
|
||||||
/// <returns>An <see cref="OrFilter{T}"/> instance.</returns>
|
|
||||||
public OrFilter<T> Or(IFilter<T> filter)
|
|
||||||
=> new OrFilter<T>(this, filter);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a filter that passes if either this or the specified filter pass.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="Q"></typeparam>
|
|
||||||
/// <param name="left"></param>
|
|
||||||
/// <param name="right"></param>
|
|
||||||
/// <returns>An <see cref="OrFilter{Q}"/> instance.</returns>
|
|
||||||
public static OrFilter<Q> Or<Q>(IFilter<Q> left, IFilter<Q> right) where Q : class
|
|
||||||
=> new OrFilter<Q>(left, right);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether this filter is collectible.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsCollectible => GetType().HasPublicProperties();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether the filter can pass for the given context.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The filter execution context.</param>
|
|
||||||
/// <returns>True if the filter passes; otherwise, false.</returns>
|
|
||||||
public abstract bool CanPass(FilterExecutionContext<T> context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Implicitly creates <see cref="IFilter{T}"/> from function
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filter"></param>
|
|
||||||
public static implicit operator Filter<T>(Func<FilterExecutionContext<T>, bool> filter) => Filter<T>.If(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A filter that always passes.
|
/// Creates a filter that always passes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
/// <returns>An <see cref="AnyFilter{T}"/> instance.</returns>
|
||||||
public class AnyFilter<T> : Filter<T> where T : class
|
public static AnyFilter<T> Any()
|
||||||
{
|
=> new AnyFilter<T>();
|
||||||
/// <inheritdoc/>
|
|
||||||
public override bool CanPass(FilterExecutionContext<T> context)
|
|
||||||
=> true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A filter that inverts the result of another filter.
|
/// Creates a filter that inverts the result of this filter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
/// <returns>A <see cref="ReverseFilter{T}"/> instance.</returns>
|
||||||
public class ReverseFilter<T> : Filter<T> where T : class
|
public Filter<T> Not()
|
||||||
{
|
=> new ReverseFilter<T>(this);
|
||||||
private readonly IFilter<T> filter;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="ReverseFilter{T}"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filter">The filter to invert.</param>
|
|
||||||
public ReverseFilter(IFilter<T> filter)
|
|
||||||
=> this.filter = filter;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override bool CanPass(FilterExecutionContext<T> context)
|
|
||||||
=> !filter.CanPass(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A filter that uses a function to determine if it passes.
|
/// Creates a filter that inverts the result of this filter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
/// <typeparam name="Q"></typeparam>
|
||||||
public class FunctionFilter<T> : Filter<T> where T : class
|
/// <returns>A <see cref="ReverseFilter{T}"/> instance.</returns>
|
||||||
{
|
public static Filter<Q> Not<Q>(IFilter<Q> filter) where Q : class
|
||||||
private readonly Func<FilterExecutionContext<T>, bool>? FilterFunc;
|
=> new ReverseFilter<Q>(filter);
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="FunctionFilter{T}"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="funcFilter">The filter function.</param>
|
|
||||||
public FunctionFilter(Func<FilterExecutionContext<T>, bool> funcFilter)
|
|
||||||
=> FilterFunc = funcFilter;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>
|
||||||
public override bool CanPass(FilterExecutionContext<T> context)
|
/// Creates a filter that passes only if both this and the specified filter pass.
|
||||||
=> context.Input != null && FilterFunc != null && FilterFunc(context);
|
/// </summary>
|
||||||
}
|
/// <param name="filter">The filter to combine with.</param>
|
||||||
|
/// <returns>An <see cref="AndFilter{T}"/> instance.</returns>
|
||||||
|
public AndFilter<T> And(IFilter<T> filter)
|
||||||
|
=> new AndFilter<T>(this, filter);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a filter that passes if either this or the specified filter pass.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filter">The filter to combine with.</param>
|
||||||
|
/// <returns>An <see cref="OrFilter{T}"/> instance.</returns>
|
||||||
|
public OrFilter<T> Or(IFilter<T> filter)
|
||||||
|
=> new OrFilter<T>(this, filter);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a filter that passes if either this or the specified filter pass.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="Q"></typeparam>
|
||||||
|
/// <param name="left"></param>
|
||||||
|
/// <param name="right"></param>
|
||||||
|
/// <returns>An <see cref="OrFilter{Q}"/> instance.</returns>
|
||||||
|
public static OrFilter<Q> Or<Q>(IFilter<Q> left, IFilter<Q> right) where Q : class
|
||||||
|
=> new OrFilter<Q>(left, right);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this filter is collectible.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsCollectible => GetType().HasPublicProperties();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the filter can pass for the given context.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The filter execution context.</param>
|
||||||
|
/// <returns>True if the filter passes; otherwise, false.</returns>
|
||||||
|
public abstract bool CanPass(FilterExecutionContext<T> context);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implicitly creates <see cref="IFilter{T}"/> from function
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filter"></param>
|
||||||
|
public static implicit operator Filter<T>(Func<FilterExecutionContext<T>, bool> filter) => Filter<T>.If(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A filter that always passes.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
||||||
|
public class AnyFilter<T> : Filter<T> where T : class
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool CanPass(FilterExecutionContext<T> context)
|
||||||
|
=> true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A filter that inverts the result of another filter.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
||||||
|
public class ReverseFilter<T> : Filter<T> where T : class
|
||||||
|
{
|
||||||
|
private readonly IFilter<T> filter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ReverseFilter{T}"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filter">The filter to invert.</param>
|
||||||
|
public ReverseFilter(IFilter<T> filter)
|
||||||
|
=> this.filter = filter;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool CanPass(FilterExecutionContext<T> context)
|
||||||
|
=> !filter.CanPass(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A filter that uses a function to determine if it passes.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
||||||
|
public class FunctionFilter<T> : Filter<T> where T : class
|
||||||
|
{
|
||||||
|
private readonly Func<FilterExecutionContext<T>, bool>? FilterFunc;
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="FunctionFilter{T}"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="funcFilter">The filter function.</param>
|
||||||
|
public FunctionFilter(Func<FilterExecutionContext<T>, bool> funcFilter)
|
||||||
|
=> FilterFunc = funcFilter;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool CanPass(FilterExecutionContext<T> context)
|
||||||
|
=> context.Input != null && FilterFunc != null && FilterFunc(context);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +1,53 @@
|
|||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Filters
|
namespace Telegrator.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for filters that join multiple filters together.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
||||||
|
public abstract class JoinedFilter<T>(params IFilter<T>[] filters) : Filter<T>, IJoinedFilter<T> where T : class
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base class for filters that join multiple filters together.
|
/// Gets the array of joined filters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
public IFilter<T>[] Filters { get; } = filters;
|
||||||
public abstract class JoinedFilter<T>(params IFilter<T>[] filters) : Filter<T>, IJoinedFilter<T> where T : class
|
}
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the array of joined filters.
|
/// A filter that passes only if both joined filters pass.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IFilter<T>[] Filters { get; } = filters;
|
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
||||||
}
|
public class AndFilter<T> : JoinedFilter<T> where T : class
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A filter that passes only if both joined filters pass.
|
/// Initializes a new instance of the <see cref="AndFilter{T}"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
/// <param name="leftFilter">The left filter.</param>
|
||||||
public class AndFilter<T> : JoinedFilter<T> where T : class
|
/// <param name="rightFilter">The right filter.</param>
|
||||||
{
|
public AndFilter(IFilter<T> leftFilter, IFilter<T> rightFilter)
|
||||||
/// <summary>
|
: base(leftFilter, rightFilter) { }
|
||||||
/// Initializes a new instance of the <see cref="AndFilter{T}"/> class.
|
|
||||||
/// </summary>
|
/// <inheritdoc/>
|
||||||
/// <param name="leftFilter">The left filter.</param>
|
public override bool CanPass(FilterExecutionContext<T> context)
|
||||||
/// <param name="rightFilter">The right filter.</param>
|
=> Filters[0].CanPass(context) && Filters[1].CanPass(context);
|
||||||
public AndFilter(IFilter<T> leftFilter, IFilter<T> rightFilter)
|
}
|
||||||
: base(leftFilter, rightFilter) { }
|
|
||||||
|
/// <summary>
|
||||||
/// <inheritdoc/>
|
/// A filter that passes if at least one of the joined filters passes.
|
||||||
public override bool CanPass(FilterExecutionContext<T> context)
|
/// </summary>
|
||||||
=> Filters[0].CanPass(context) && Filters[1].CanPass(context);
|
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
||||||
}
|
public class OrFilter<T> : JoinedFilter<T> where T : class
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A filter that passes if at least one of the joined filters passes.
|
/// Initializes a new instance of the <see cref="OrFilter{T}"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the input for the filter.</typeparam>
|
/// <param name="leftFilter">The left filter.</param>
|
||||||
public class OrFilter<T> : JoinedFilter<T> where T : class
|
/// <param name="rightFilter">The right filter.</param>
|
||||||
{
|
public OrFilter(IFilter<T> leftFilter, IFilter<T> rightFilter)
|
||||||
/// <summary>
|
: base(leftFilter, rightFilter) { }
|
||||||
/// Initializes a new instance of the <see cref="OrFilter{T}"/> class.
|
|
||||||
/// </summary>
|
/// <inheritdoc/>
|
||||||
/// <param name="leftFilter">The left filter.</param>
|
public override bool CanPass(FilterExecutionContext<T> context)
|
||||||
/// <param name="rightFilter">The right filter.</param>
|
=> Filters[0].CanPass(context) || Filters[1].CanPass(context);
|
||||||
public OrFilter(IFilter<T> leftFilter, IFilter<T> rightFilter)
|
|
||||||
: base(leftFilter, rightFilter) { }
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override bool CanPass(FilterExecutionContext<T> context)
|
|
||||||
=> Filters[0].CanPass(context) || Filters[1].CanPass(context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,63 +2,62 @@
|
|||||||
using Telegram.Bot.Types.Enums;
|
using Telegram.Bot.Types.Enums;
|
||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Filters
|
namespace Telegrator.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks if a message contains a mention of the bot or a specific user.
|
||||||
|
/// Requires a <see cref="MessageHasEntityFilter"/> to be applied first to identify mention entities.
|
||||||
|
/// </summary>
|
||||||
|
public class MentionedFilter : MessageFilterBase
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filter that checks if a message contains a mention of the bot or a specific user.
|
/// The username to check for in the mention (null means check for bot's username).
|
||||||
/// Requires a <see cref="MessageHasEntityFilter"/> to be applied first to identify mention entities.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MentionedFilter : MessageFilterBase
|
private readonly string? Mention;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MentionedFilter"/> class that checks for bot mentions.
|
||||||
|
/// </summary>
|
||||||
|
public MentionedFilter()
|
||||||
{
|
{
|
||||||
/// <summary>
|
Mention = null;
|
||||||
/// The username to check for in the mention (null means check for bot's username).
|
}
|
||||||
/// </summary>
|
|
||||||
private readonly string? Mention;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="MentionedFilter"/> class that checks for bot mentions.
|
/// Initializes a new instance of the <see cref="MentionedFilter"/> class that checks for specific user mentions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MentionedFilter()
|
/// <param name="mention">The username to check for in the mention.</param>
|
||||||
{
|
public MentionedFilter(string mention)
|
||||||
Mention = null;
|
{
|
||||||
}
|
Mention = mention.TrimStart('@');
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MentionedFilter"/> class that checks for specific user mentions.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="mention">The username to check for in the mention.</param>
|
|
||||||
public MentionedFilter(string mention)
|
|
||||||
{
|
|
||||||
Mention = mention.TrimStart('@');
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the message contains a mention of the specified user or bot.
|
|
||||||
/// This filter requires a <see cref="MessageHasEntityFilter"/> to be applied first
|
|
||||||
/// to identify mention entities in the message.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The filter execution context containing the message and completed filters.</param>
|
|
||||||
/// <returns>True if the message contains the specified mention; otherwise, false.</returns>
|
|
||||||
/// <exception cref="ArgumentNullException">Thrown when the bot username is null and no specific mention is provided.</exception>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
|
||||||
{
|
|
||||||
if (Target.Text == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
string userName = Mention ?? context.BotInfo.User.Username ?? throw new ArgumentNullException(nameof(context), "MentionedFilter requires BotInfo to be initialized");
|
|
||||||
IEnumerable<MessageEntity> entities = context.CompletedFilters
|
|
||||||
.Get<MessageHasEntityFilter>()
|
|
||||||
.SelectMany(ent => ent.FoundEntities)
|
|
||||||
.Where(ent => ent.Type == MessageEntityType.Mention);
|
|
||||||
|
|
||||||
foreach (MessageEntity ent in entities)
|
|
||||||
{
|
|
||||||
string mention = Target.Text.Substring(ent.Offset + 1, ent.Length - 1);
|
|
||||||
if (mention == userName)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the message contains a mention of the specified user or bot.
|
||||||
|
/// This filter requires a <see cref="MessageHasEntityFilter"/> to be applied first
|
||||||
|
/// to identify mention entities in the message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The filter execution context containing the message and completed filters.</param>
|
||||||
|
/// <returns>True if the message contains the specified mention; otherwise, false.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when the bot username is null and no specific mention is provided.</exception>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
||||||
|
{
|
||||||
|
if (Target.Text == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
string userName = Mention ?? context.BotInfo.User.Username ?? throw new ArgumentNullException(nameof(context), "MentionedFilter requires BotInfo to be initialized");
|
||||||
|
IEnumerable<MessageEntity> entities = context.CompletedFilters
|
||||||
|
.Get<MessageHasEntityFilter>()
|
||||||
|
.SelectMany(ent => ent.FoundEntities)
|
||||||
|
.Where(ent => ent.Type == MessageEntityType.Mention);
|
||||||
|
|
||||||
|
foreach (MessageEntity ent in entities)
|
||||||
|
{
|
||||||
|
string mention = Target.Text.Substring(ent.Offset + 1, ent.Length - 1);
|
||||||
|
if (mention == userName)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,218 +3,217 @@ using Telegram.Bot.Types.Enums;
|
|||||||
using Telegram.Bot.Types.ReplyMarkups;
|
using Telegram.Bot.Types.ReplyMarkups;
|
||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Filters
|
namespace Telegrator.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for filters that operate on the chat of the message being processed.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class MessageChatFilter : MessageFilterBase
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base class for filters that operate on the chat of the message being processed.
|
/// Gets the chat of the message being processed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class MessageChatFilter : MessageFilterBase
|
public Chat Chat { get; private set; } = null!;
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the chat of the message being processed.
|
|
||||||
/// </summary>
|
|
||||||
public Chat Chat { get; private set; } = null!;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
||||||
|
{
|
||||||
|
Chat = Target.Chat;
|
||||||
|
return CanPassNext(context.CreateChild(Chat));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the filter passes for the given chat context.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The filter execution context for the chat.</param>
|
||||||
|
/// <returns>True if the filter passes; otherwise, false.</returns>
|
||||||
|
protected abstract bool CanPassNext(FilterExecutionContext<Chat> context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters messages whose chat is a forum.
|
||||||
|
/// </summary>
|
||||||
|
public class MessageChatIsForumFilter : MessageChatFilter
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Chat> _)
|
||||||
|
=> Chat.IsForum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters messages whose chat ID matches the specified value.
|
||||||
|
/// </summary>
|
||||||
|
public class MessageChatIdFilter(long id) : MessageChatFilter
|
||||||
|
{
|
||||||
|
private readonly long Id = id;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Chat> _)
|
||||||
|
=> Chat.Id == Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters messages whose chat type matches the specified value.
|
||||||
|
/// </summary>
|
||||||
|
public class MessageChatTypeFilter : MessageChatFilter
|
||||||
|
{
|
||||||
|
private readonly ChatType? Type;
|
||||||
|
private readonly ChatTypeFlags? Flags;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize new instance of <see cref="MessageChatTypeFilter"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"></param>
|
||||||
|
public MessageChatTypeFilter(ChatType type)
|
||||||
|
=> Type = type;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize new instance of <see cref="MessageChatTypeFilter"/> with <see cref="ChatTypeFlags"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"></param>
|
||||||
|
public MessageChatTypeFilter(ChatTypeFlags type)
|
||||||
|
=> Flags = type;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Chat> _)
|
||||||
|
{
|
||||||
|
if (Type.HasValue)
|
||||||
|
return Chat.Type == Type.Value;
|
||||||
|
|
||||||
|
if (Flags != null)
|
||||||
{
|
{
|
||||||
Chat = Target.Chat;
|
ChatTypeFlags? asFlag = ToFlag(Chat.Type);
|
||||||
return CanPassNext(context.CreateChild(Chat));
|
return asFlag.HasValue && Flags.Value.HasFlag(asFlag.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
return false;
|
||||||
/// Determines whether the filter passes for the given chat context.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The filter execution context for the chat.</param>
|
|
||||||
/// <returns>True if the filter passes; otherwise, false.</returns>
|
|
||||||
protected abstract bool CanPassNext(FilterExecutionContext<Chat> context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private static ChatTypeFlags? ToFlag(ChatType type) => type switch
|
||||||
/// Filters messages whose chat is a forum.
|
|
||||||
/// </summary>
|
|
||||||
public class MessageChatIsForumFilter : MessageChatFilter
|
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
ChatType.Channel => ChatTypeFlags.Channel,
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Chat> _)
|
ChatType.Group => ChatTypeFlags.Group,
|
||||||
=> Chat.IsForum;
|
ChatType.Supergroup => ChatTypeFlags.Supergroup,
|
||||||
}
|
ChatType.Sender => ChatTypeFlags.Sender,
|
||||||
|
ChatType.Private => ChatTypeFlags.Private,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters messages whose chat title matches the specified value.
|
||||||
|
/// </summary>
|
||||||
|
public class MessageChatTitleFilter : MessageChatFilter
|
||||||
|
{
|
||||||
|
private readonly string? Title;
|
||||||
|
private readonly StringComparison Comparison = StringComparison.InvariantCulture;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filters messages whose chat ID matches the specified value.
|
/// Initializes a new instance of the <see cref="MessageChatTitleFilter"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MessageChatIdFilter(long id) : MessageChatFilter
|
/// <param name="title">The chat title to match.</param>
|
||||||
{
|
public MessageChatTitleFilter(string? title) => Title = title;
|
||||||
private readonly long Id = id;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Chat> _)
|
|
||||||
=> Chat.Id == Id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filters messages whose chat type matches the specified value.
|
/// Initializes a new instance of the <see cref="MessageChatTitleFilter"/> class with a specific string comparison.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MessageChatTypeFilter : MessageChatFilter
|
/// <param name="title">The chat title to match.</param>
|
||||||
|
/// <param name="comparison">The string comparison to use.</param>
|
||||||
|
public MessageChatTitleFilter(string? title, StringComparison comparison)
|
||||||
|
: this(title) => Comparison = comparison;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Chat> _)
|
||||||
{
|
{
|
||||||
private readonly ChatType? Type;
|
if (Chat.Title == null)
|
||||||
private readonly ChatTypeFlags? Flags;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initialize new instance of <see cref="MessageChatTypeFilter"/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type"></param>
|
|
||||||
public MessageChatTypeFilter(ChatType type)
|
|
||||||
=> Type = type;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initialize new instance of <see cref="MessageChatTypeFilter"/> with <see cref="ChatTypeFlags"/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type"></param>
|
|
||||||
public MessageChatTypeFilter(ChatTypeFlags type)
|
|
||||||
=> Flags = type;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Chat> _)
|
|
||||||
{
|
|
||||||
if (Type.HasValue)
|
|
||||||
return Chat.Type == Type.Value;
|
|
||||||
|
|
||||||
if (Flags != null)
|
|
||||||
{
|
|
||||||
ChatTypeFlags? asFlag = ToFlag(Chat.Type);
|
|
||||||
return asFlag.HasValue && Flags.Value.HasFlag(asFlag.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
private static ChatTypeFlags? ToFlag(ChatType type) => type switch
|
return Chat.Title.Equals(Title, Comparison);
|
||||||
{
|
}
|
||||||
ChatType.Channel => ChatTypeFlags.Channel,
|
}
|
||||||
ChatType.Group => ChatTypeFlags.Group,
|
|
||||||
ChatType.Supergroup => ChatTypeFlags.Supergroup,
|
/// <summary>
|
||||||
ChatType.Sender => ChatTypeFlags.Sender,
|
/// Filters messages whose chat username matches the specified value.
|
||||||
ChatType.Private => ChatTypeFlags.Private,
|
/// </summary>
|
||||||
_ => null
|
public class MessageChatUsernameFilter : MessageChatFilter
|
||||||
};
|
{
|
||||||
}
|
private readonly string? UserName;
|
||||||
|
private readonly StringComparison Comparison = StringComparison.InvariantCulture;
|
||||||
/// <summary>
|
|
||||||
/// Filters messages whose chat title matches the specified value.
|
/// <summary>
|
||||||
/// </summary>
|
/// Initializes a new instance of the <see cref="MessageChatUsernameFilter"/> class.
|
||||||
public class MessageChatTitleFilter : MessageChatFilter
|
/// </summary>
|
||||||
{
|
/// <param name="userName">The chat username to match.</param>
|
||||||
private readonly string? Title;
|
public MessageChatUsernameFilter(string? userName) => UserName = userName;
|
||||||
private readonly StringComparison Comparison = StringComparison.InvariantCulture;
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Initializes a new instance of the <see cref="MessageChatUsernameFilter"/> class with a specific string comparison.
|
||||||
/// Initializes a new instance of the <see cref="MessageChatTitleFilter"/> class.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="userName">The chat username to match.</param>
|
||||||
/// <param name="title">The chat title to match.</param>
|
/// <param name="comparison">The string comparison to use.</param>
|
||||||
public MessageChatTitleFilter(string? title) => Title = title;
|
public MessageChatUsernameFilter(string? userName, StringComparison comparison)
|
||||||
|
: this(userName) => Comparison = comparison;
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MessageChatTitleFilter"/> class with a specific string comparison.
|
/// <inheritdoc/>
|
||||||
/// </summary>
|
protected override bool CanPassNext(FilterExecutionContext<Chat> _)
|
||||||
/// <param name="title">The chat title to match.</param>
|
{
|
||||||
/// <param name="comparison">The string comparison to use.</param>
|
if (Chat.Username == null)
|
||||||
public MessageChatTitleFilter(string? title, StringComparison comparison)
|
return false;
|
||||||
: this(title) => Comparison = comparison;
|
|
||||||
|
return Chat.Username.Equals(UserName, Comparison);
|
||||||
/// <inheritdoc/>
|
}
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Chat> _)
|
}
|
||||||
{
|
|
||||||
if (Chat.Title == null)
|
/// <summary>
|
||||||
return false;
|
/// Filters messages whose chat first and/or last name matches the specified values.
|
||||||
|
/// </summary>
|
||||||
return Chat.Title.Equals(Title, Comparison);
|
public class MessageChatNameFilter : MessageChatFilter
|
||||||
}
|
{
|
||||||
}
|
private readonly string? FirstName;
|
||||||
|
private readonly string? LastName;
|
||||||
/// <summary>
|
private readonly StringComparison Comparison = StringComparison.InvariantCulture;
|
||||||
/// Filters messages whose chat username matches the specified value.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public class MessageChatUsernameFilter : MessageChatFilter
|
/// Initializes a new instance of the <see cref="MessageChatNameFilter"/> class.
|
||||||
{
|
/// </summary>
|
||||||
private readonly string? UserName;
|
/// <param name="firstName">The chat first name to match.</param>
|
||||||
private readonly StringComparison Comparison = StringComparison.InvariantCulture;
|
/// <param name="lastName">The chat last name to match.</param>
|
||||||
|
public MessageChatNameFilter(string? firstName, string? lastName)
|
||||||
/// <summary>
|
{
|
||||||
/// Initializes a new instance of the <see cref="MessageChatUsernameFilter"/> class.
|
FirstName = firstName;
|
||||||
/// </summary>
|
LastName = lastName;
|
||||||
/// <param name="userName">The chat username to match.</param>
|
}
|
||||||
public MessageChatUsernameFilter(string? userName) => UserName = userName;
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Initializes a new instance of the <see cref="MessageChatNameFilter"/> class with a specific string comparison.
|
||||||
/// Initializes a new instance of the <see cref="MessageChatUsernameFilter"/> class with a specific string comparison.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="firstName">The chat first name to match.</param>
|
||||||
/// <param name="userName">The chat username to match.</param>
|
/// <param name="lastName">The chat last name to match.</param>
|
||||||
/// <param name="comparison">The string comparison to use.</param>
|
/// <param name="comparison">The string comparison to use.</param>
|
||||||
public MessageChatUsernameFilter(string? userName, StringComparison comparison)
|
public MessageChatNameFilter(string? firstName, string? lastName, StringComparison comparison)
|
||||||
: this(userName) => Comparison = comparison;
|
: this(firstName, lastName) => Comparison = comparison;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Chat> _)
|
protected override bool CanPassNext(FilterExecutionContext<Chat> _)
|
||||||
{
|
{
|
||||||
if (Chat.Username == null)
|
if (LastName != null)
|
||||||
return false;
|
{
|
||||||
|
if (Chat.LastName == null)
|
||||||
return Chat.Username.Equals(UserName, Comparison);
|
return false;
|
||||||
}
|
|
||||||
}
|
if (Chat.LastName.Equals(LastName, Comparison))
|
||||||
|
return false;
|
||||||
/// <summary>
|
}
|
||||||
/// Filters messages whose chat first and/or last name matches the specified values.
|
|
||||||
/// </summary>
|
if (FirstName != null)
|
||||||
public class MessageChatNameFilter : MessageChatFilter
|
{
|
||||||
{
|
if (Chat.FirstName == null)
|
||||||
private readonly string? FirstName;
|
return false;
|
||||||
private readonly string? LastName;
|
|
||||||
private readonly StringComparison Comparison = StringComparison.InvariantCulture;
|
if (Chat.FirstName.Equals(FirstName, Comparison))
|
||||||
|
return false;
|
||||||
/// <summary>
|
}
|
||||||
/// Initializes a new instance of the <see cref="MessageChatNameFilter"/> class.
|
|
||||||
/// </summary>
|
return true;
|
||||||
/// <param name="firstName">The chat first name to match.</param>
|
|
||||||
/// <param name="lastName">The chat last name to match.</param>
|
|
||||||
public MessageChatNameFilter(string? firstName, string? lastName)
|
|
||||||
{
|
|
||||||
FirstName = firstName;
|
|
||||||
LastName = lastName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MessageChatNameFilter"/> class with a specific string comparison.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="firstName">The chat first name to match.</param>
|
|
||||||
/// <param name="lastName">The chat last name to match.</param>
|
|
||||||
/// <param name="comparison">The string comparison to use.</param>
|
|
||||||
public MessageChatNameFilter(string? firstName, string? lastName, StringComparison comparison)
|
|
||||||
: this(firstName, lastName) => Comparison = comparison;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Chat> _)
|
|
||||||
{
|
|
||||||
if (LastName != null)
|
|
||||||
{
|
|
||||||
if (Chat.LastName == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (Chat.LastName.Equals(LastName, Comparison))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FirstName != null)
|
|
||||||
{
|
|
||||||
if (Chat.FirstName == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (Chat.FirstName.Equals(FirstName, Comparison))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,273 +3,272 @@ using Telegram.Bot.Types;
|
|||||||
using Telegram.Bot.Types.Enums;
|
using Telegram.Bot.Types.Enums;
|
||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Filters
|
namespace Telegrator.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base abstract class for all filter of <see cref="Message"/> updates
|
||||||
|
/// </summary>
|
||||||
|
public abstract class MessageFilterBase : Filter<Message>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base abstract class for all filter of <see cref="Message"/> updates
|
/// Target message for filterring
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class MessageFilterBase : Filter<Message>
|
protected Message Target { get; private set; } = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected virtual bool CanPassBase(FilterExecutionContext<Message> context)
|
||||||
{
|
{
|
||||||
/// <summary>
|
FromReplyChainFilter? repliedFilter = context.CompletedFilters.Get<FromReplyChainFilter>().SingleOrDefault();
|
||||||
/// Target message for filterring
|
Target = repliedFilter?.Reply ?? context.Input;
|
||||||
/// </summary>
|
|
||||||
protected Message Target { get; private set; } = null!;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
if (Target is not { Id: > 0 })
|
||||||
protected virtual bool CanPassBase(FilterExecutionContext<Message> context)
|
return false;
|
||||||
{
|
|
||||||
FromReplyChainFilter? repliedFilter = context.CompletedFilters.Get<FromReplyChainFilter>().SingleOrDefault();
|
|
||||||
Target = repliedFilter?.Reply ?? context.Input;
|
|
||||||
|
|
||||||
if (Target is not { Id: > 0 })
|
return true;
|
||||||
return false;
|
}
|
||||||
|
|
||||||
return true;
|
/// <inheritdoc/>
|
||||||
}
|
public override bool CanPass(FilterExecutionContext<Message> context)
|
||||||
|
{
|
||||||
|
if (!CanPassBase(context))
|
||||||
|
return false;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
return CanPassNext(context);
|
||||||
public override bool CanPass(FilterExecutionContext<Message> context)
|
|
||||||
{
|
|
||||||
if (!CanPassBase(context))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return CanPassNext(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether the filter can pass for the given context.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected abstract bool CanPassNext(FilterExecutionContext<Message> context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filters messages by their <see cref="MessageType"/>.
|
/// Determines whether the filter can pass for the given context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MessageTypeFilter : MessageFilterBase
|
/// <param name="context"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected abstract bool CanPassNext(FilterExecutionContext<Message> context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters messages by their <see cref="MessageType"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class MessageTypeFilter : MessageFilterBase
|
||||||
|
{
|
||||||
|
private readonly MessageType type;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MessageTypeFilter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The message type to filter by.</param>
|
||||||
|
public MessageTypeFilter(MessageType type) => this.type = type;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
||||||
|
=> Target.Type == type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters messages that are automatic forwards.
|
||||||
|
/// </summary>
|
||||||
|
public class IsAutomaticFormwardMessageFilter : MessageFilterBase
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
||||||
|
=> Target.IsAutomaticForward;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters messages that are sent from offline.
|
||||||
|
/// </summary>
|
||||||
|
public class IsFromOfflineMessageFilter : MessageFilterBase
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
||||||
|
=> Target.IsFromOffline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters service messages (e.g., chat events).
|
||||||
|
/// </summary>
|
||||||
|
public class IsServiceMessageMessageFilter : MessageFilterBase
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
||||||
|
=> Target.IsServiceMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters messages that are topic messages.
|
||||||
|
/// </summary>
|
||||||
|
public class IsTopicMessageMessageFilter : MessageFilterBase
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
||||||
|
=> Target.IsTopicMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters messages by dice throw value and optionally by dice type.
|
||||||
|
/// </summary>
|
||||||
|
public class DiceThrowedFilter : MessageFilterBase
|
||||||
|
{
|
||||||
|
private readonly DiceType Dice;
|
||||||
|
private readonly int Value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DiceThrowedFilter"/> class for a specific value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The dice value to filter by.</param>
|
||||||
|
public DiceThrowedFilter(int value)
|
||||||
{
|
{
|
||||||
private readonly MessageType type;
|
Value = value;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MessageTypeFilter"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The message type to filter by.</param>
|
|
||||||
public MessageTypeFilter(MessageType type) => this.type = type;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
|
||||||
=> Target.Type == type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filters messages that are automatic forwards.
|
/// Initializes a new instance of the <see cref="DiceThrowedFilter"/> class for a specific dice type and value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class IsAutomaticFormwardMessageFilter : MessageFilterBase
|
/// <param name="diceType">The dice type to filter by.</param>
|
||||||
|
/// <param name="value">The dice value to filter by.</param>
|
||||||
|
public DiceThrowedFilter(DiceType diceType, int value) : this(value) => Dice = diceType;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
if (Target.Dice == null)
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
return false;
|
||||||
=> Target.IsAutomaticForward;
|
|
||||||
|
if (Target.Dice.Emoji != GetEmojyForDiceType(Dice))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return Target.Dice.Value == Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? GetEmojyForDiceType(DiceType? diceType) => diceType switch
|
||||||
|
{
|
||||||
|
DiceType.Dice => "🎲",
|
||||||
|
DiceType.Darts => "🎯",
|
||||||
|
DiceType.Bowling => "🎳",
|
||||||
|
DiceType.Basketball => "🏀",
|
||||||
|
DiceType.Football => "⚽",
|
||||||
|
DiceType.Casino => "🎰",
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters messages by matching their text with a regular expression.
|
||||||
|
/// </summary>
|
||||||
|
public class MessageRegexFilter : RegexFilterBase<Message>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MessageRegexFilter"/> class with a pattern and options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pattern">The regex pattern.</param>
|
||||||
|
/// <param name="regexOptions">The regex options.</param>
|
||||||
|
public MessageRegexFilter(string pattern, RegexOptions regexOptions = default)
|
||||||
|
: base(msg => msg.Text, pattern, regexOptions) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MessageRegexFilter"/> class with a regex object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="regex">The regex object.</param>
|
||||||
|
public MessageRegexFilter(Regex regex)
|
||||||
|
: base(msg => msg.Text, regex) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters messages that contain a specific entity type, content, offset, or length.
|
||||||
|
/// </summary>
|
||||||
|
public class MessageHasEntityFilter : MessageFilterBase
|
||||||
|
{
|
||||||
|
private readonly StringComparison _stringComparison = StringComparison.CurrentCulture;
|
||||||
|
private readonly MessageEntityType? EntityType;
|
||||||
|
private readonly string? Content;
|
||||||
|
private readonly int? Offset;
|
||||||
|
private readonly int? Length;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the entities found in the message that match the filter.
|
||||||
|
/// </summary>
|
||||||
|
public MessageEntity[] FoundEntities { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MessageHasEntityFilter"/> class for a specific entity type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The entity type to filter by.</param>
|
||||||
|
public MessageHasEntityFilter(MessageEntityType type)
|
||||||
|
{
|
||||||
|
EntityType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filters messages that are sent from offline.
|
/// Initializes a new instance of the <see cref="MessageHasEntityFilter"/> class for a specific entity type, offset, and length.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class IsFromOfflineMessageFilter : MessageFilterBase
|
/// <param name="type">The entity type to filter by.</param>
|
||||||
|
/// <param name="offset">The offset to filter by.</param>
|
||||||
|
/// <param name="length">The length to filter by.</param>
|
||||||
|
public MessageHasEntityFilter(MessageEntityType type, int? offset, int? length)
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
EntityType = type;
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
Offset = offset;
|
||||||
=> Target.IsFromOffline;
|
Length = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filters service messages (e.g., chat events).
|
/// Initializes a new instance of the <see cref="MessageHasEntityFilter"/> class for a specific entity type and content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class IsServiceMessageMessageFilter : MessageFilterBase
|
/// <param name="type">The entity type to filter by.</param>
|
||||||
|
/// <param name="content">The content to filter by.</param>
|
||||||
|
/// <param name="stringComparison">The string comparison to use.</param>
|
||||||
|
public MessageHasEntityFilter(MessageEntityType type, string? content, StringComparison stringComparison = StringComparison.CurrentCulture)
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
EntityType = type;
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
Content = content;
|
||||||
=> Target.IsServiceMessage;
|
_stringComparison = stringComparison;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filters messages that are topic messages.
|
/// Initializes a new instance of the <see cref="MessageHasEntityFilter"/> class for a specific entity type, offset, length, and content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class IsTopicMessageMessageFilter : MessageFilterBase
|
/// <param name="type">The entity type to filter by.</param>
|
||||||
|
/// <param name="offset">The offset to filter by.</param>
|
||||||
|
/// <param name="length">The length to filter by.</param>
|
||||||
|
/// <param name="content">The content to filter by.</param>
|
||||||
|
/// <param name="stringComparison">The string comparison to use.</param>
|
||||||
|
public MessageHasEntityFilter(MessageEntityType type, int? offset, int? length, string? content, StringComparison stringComparison = StringComparison.CurrentCulture)
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
EntityType = type;
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
Offset = offset;
|
||||||
=> Target.IsTopicMessage;
|
Length = length;
|
||||||
|
Content = content;
|
||||||
|
_stringComparison = stringComparison;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc/>
|
||||||
/// Filters messages by dice throw value and optionally by dice type.
|
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
||||||
/// </summary>
|
|
||||||
public class DiceThrowedFilter : MessageFilterBase
|
|
||||||
{
|
{
|
||||||
private readonly DiceType Dice;
|
if (context.Input is not { Entities.Length: > 0 })
|
||||||
private readonly int Value;
|
return false;
|
||||||
|
|
||||||
/// <summary>
|
FoundEntities = Target.Entities.Where(entity => FilterEntity(Target.Text, entity)).ToArray();
|
||||||
/// Initializes a new instance of the <see cref="DiceThrowedFilter"/> class for a specific value.
|
return FoundEntities.Length != 0;
|
||||||
/// </summary>
|
}
|
||||||
/// <param name="value">The dice value to filter by.</param>
|
|
||||||
public DiceThrowedFilter(int value)
|
private bool FilterEntity(string? text, MessageEntity entity)
|
||||||
|
{
|
||||||
|
if (EntityType != null && entity.Type != EntityType)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Offset != null && entity.Offset != Offset)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Length != null && entity.Length != Length)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Content != null)
|
||||||
{
|
{
|
||||||
Value = value;
|
if (text is not { Length: > 0 })
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="DiceThrowedFilter"/> class for a specific dice type and value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="diceType">The dice type to filter by.</param>
|
|
||||||
/// <param name="value">The dice value to filter by.</param>
|
|
||||||
public DiceThrowedFilter(DiceType diceType, int value) : this(value) => Dice = diceType;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
|
||||||
{
|
|
||||||
if (Target.Dice == null)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (Target.Dice.Emoji != GetEmojyForDiceType(Dice))
|
if (!text.Substring(entity.Offset, entity.Length).Equals(Content, _stringComparison))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return Target.Dice.Value == Value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string? GetEmojyForDiceType(DiceType? diceType) => diceType switch
|
return true;
|
||||||
{
|
|
||||||
DiceType.Dice => "🎲",
|
|
||||||
DiceType.Darts => "🎯",
|
|
||||||
DiceType.Bowling => "🎳",
|
|
||||||
DiceType.Basketball => "🏀",
|
|
||||||
DiceType.Football => "⚽",
|
|
||||||
DiceType.Casino => "🎰",
|
|
||||||
_ => null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Filters messages by matching their text with a regular expression.
|
|
||||||
/// </summary>
|
|
||||||
public class MessageRegexFilter : RegexFilterBase<Message>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MessageRegexFilter"/> class with a pattern and options.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pattern">The regex pattern.</param>
|
|
||||||
/// <param name="regexOptions">The regex options.</param>
|
|
||||||
public MessageRegexFilter(string pattern, RegexOptions regexOptions = default)
|
|
||||||
: base(msg => msg.Text, pattern, regexOptions) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MessageRegexFilter"/> class with a regex object.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="regex">The regex object.</param>
|
|
||||||
public MessageRegexFilter(Regex regex)
|
|
||||||
: base(msg => msg.Text, regex) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Filters messages that contain a specific entity type, content, offset, or length.
|
|
||||||
/// </summary>
|
|
||||||
public class MessageHasEntityFilter : MessageFilterBase
|
|
||||||
{
|
|
||||||
private readonly StringComparison _stringComparison = StringComparison.CurrentCulture;
|
|
||||||
private readonly MessageEntityType? EntityType;
|
|
||||||
private readonly string? Content;
|
|
||||||
private readonly int? Offset;
|
|
||||||
private readonly int? Length;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the entities found in the message that match the filter.
|
|
||||||
/// </summary>
|
|
||||||
public MessageEntity[] FoundEntities { get; set; } = null!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MessageHasEntityFilter"/> class for a specific entity type.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The entity type to filter by.</param>
|
|
||||||
public MessageHasEntityFilter(MessageEntityType type)
|
|
||||||
{
|
|
||||||
EntityType = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MessageHasEntityFilter"/> class for a specific entity type, offset, and length.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The entity type to filter by.</param>
|
|
||||||
/// <param name="offset">The offset to filter by.</param>
|
|
||||||
/// <param name="length">The length to filter by.</param>
|
|
||||||
public MessageHasEntityFilter(MessageEntityType type, int? offset, int? length)
|
|
||||||
{
|
|
||||||
EntityType = type;
|
|
||||||
Offset = offset;
|
|
||||||
Length = length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MessageHasEntityFilter"/> class for a specific entity type and content.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The entity type to filter by.</param>
|
|
||||||
/// <param name="content">The content to filter by.</param>
|
|
||||||
/// <param name="stringComparison">The string comparison to use.</param>
|
|
||||||
public MessageHasEntityFilter(MessageEntityType type, string? content, StringComparison stringComparison = StringComparison.CurrentCulture)
|
|
||||||
{
|
|
||||||
EntityType = type;
|
|
||||||
Content = content;
|
|
||||||
_stringComparison = stringComparison;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MessageHasEntityFilter"/> class for a specific entity type, offset, length, and content.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The entity type to filter by.</param>
|
|
||||||
/// <param name="offset">The offset to filter by.</param>
|
|
||||||
/// <param name="length">The length to filter by.</param>
|
|
||||||
/// <param name="content">The content to filter by.</param>
|
|
||||||
/// <param name="stringComparison">The string comparison to use.</param>
|
|
||||||
public MessageHasEntityFilter(MessageEntityType type, int? offset, int? length, string? content, StringComparison stringComparison = StringComparison.CurrentCulture)
|
|
||||||
{
|
|
||||||
EntityType = type;
|
|
||||||
Offset = offset;
|
|
||||||
Length = length;
|
|
||||||
Content = content;
|
|
||||||
_stringComparison = stringComparison;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
|
||||||
{
|
|
||||||
if (context.Input is not { Entities.Length: > 0 })
|
|
||||||
return false;
|
|
||||||
|
|
||||||
FoundEntities = Target.Entities.Where(entity => FilterEntity(Target.Text, entity)).ToArray();
|
|
||||||
return FoundEntities.Length != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool FilterEntity(string? text, MessageEntity entity)
|
|
||||||
{
|
|
||||||
if (EntityType != null && entity.Type != EntityType)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (Offset != null && entity.Offset != Offset)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (Length != null && entity.Length != Length)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (Content != null)
|
|
||||||
{
|
|
||||||
if (text is not { Length: > 0 })
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!text.Substring(entity.Offset, entity.Length).Equals(Content, _stringComparison))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,102 +1,101 @@
|
|||||||
using Telegram.Bot.Types;
|
using Telegram.Bot.Types;
|
||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Filters
|
namespace Telegrator.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks if message has appropriate reply chain.
|
||||||
|
/// DOES NOT SHiFT MESSAGE FILTERS TARGET
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="replyDepth">The depth of reply chain to traverse (default: 1).</param>
|
||||||
|
public class MessageHasReplyFilter(int replyDepth = 1) : Filter<Message>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filter that checks if message has appropriate reply chain.
|
/// Gets the replied message at the specified depth in the reply chain.
|
||||||
/// DOES NOT SHiFT MESSAGE FILTERS TARGET
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="replyDepth">The depth of reply chain to traverse (default: 1).</param>
|
public Message Reply { get; private set; } = null!;
|
||||||
public class MessageHasReplyFilter(int replyDepth = 1) : Filter<Message>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the replied message at the specified depth in the reply chain.
|
|
||||||
/// </summary>
|
|
||||||
public Message Reply { get; private set; } = null!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the depth of reply chain traversal.
|
|
||||||
/// </summary>
|
|
||||||
public int ReplyDepth { get; private set; } = replyDepth;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines if the message can pass through the filter by first validating
|
|
||||||
/// the reply chain and then applying specific filter logic.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The filter execution context containing the message.</param>
|
|
||||||
/// <returns>True if the message passes both reply validation and specific filter criteria; otherwise, false.</returns>
|
|
||||||
public override bool CanPass(FilterExecutionContext<Message> context)
|
|
||||||
{
|
|
||||||
Message reply = context.Input;
|
|
||||||
for (int i = ReplyDepth; i > 0; i--)
|
|
||||||
{
|
|
||||||
if (reply.ReplyToMessage is not { Id: > 0 } replyMessage)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
reply = replyMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
Reply = reply;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Helper filter class for filters that operate on replied messages.
|
/// Gets the depth of reply chain traversal.
|
||||||
/// Provides functionality to traverse reply chains and access replied message content
|
|
||||||
/// and shifts any next message filter to filter the content of found reply.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="replyDepth"></param>
|
public int ReplyDepth { get; private set; } = replyDepth;
|
||||||
public class FromReplyChainFilter(int replyDepth = 1) : Filter<Message>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the replied message at the specified depth in the reply chain.
|
|
||||||
/// </summary>
|
|
||||||
public Message Reply { get; private set; } = null!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the depth of reply chain traversal.
|
|
||||||
/// </summary>
|
|
||||||
public int ReplyDepth { get; private set; } = replyDepth;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines if the message can pass through the filter by first validating
|
|
||||||
/// the reply chain and then applying specific filter logic.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The filter execution context containing the message.</param>
|
|
||||||
/// <returns>True if the message passes both reply validation and specific filter criteria; otherwise, false.</returns>
|
|
||||||
public override bool CanPass(FilterExecutionContext<Message> context)
|
|
||||||
{
|
|
||||||
Message reply = context.Input;
|
|
||||||
for (int i = ReplyDepth; i > 0; i--)
|
|
||||||
{
|
|
||||||
if (reply.ReplyToMessage is not { Id: > 0 } replyMessage)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
reply = replyMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
Reply = reply;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filter that checks if the replied message was sent by the bot itself.
|
/// Determines if the message can pass through the filter by first validating
|
||||||
/// <para>( ! ): REQUIRES <see cref="MessageHasReplyFilter"/> before</para>
|
/// the reply chain and then applying specific filter logic.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MeRepliedFilter : Filter<Message>
|
/// <param name="context">The filter execution context containing the message.</param>
|
||||||
|
/// <returns>True if the message passes both reply validation and specific filter criteria; otherwise, false.</returns>
|
||||||
|
public override bool CanPass(FilterExecutionContext<Message> context)
|
||||||
{
|
{
|
||||||
/// <summary>
|
Message reply = context.Input;
|
||||||
/// Checks if the replied message was sent by the bot.
|
for (int i = ReplyDepth; i > 0; i--)
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The filter execution context containing bot information.</param>
|
|
||||||
/// <returns>True if the replied message was sent by the bot; otherwise, false.</returns>
|
|
||||||
public override bool CanPass(FilterExecutionContext<Message> context)
|
|
||||||
{
|
{
|
||||||
MessageHasReplyFilter repliedFilter = context.CompletedFilters.Get<MessageHasReplyFilter>(0);
|
if (reply.ReplyToMessage is not { Id: > 0 } replyMessage)
|
||||||
return context.BotInfo.User == repliedFilter.Reply.From;
|
return false;
|
||||||
|
|
||||||
|
reply = replyMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reply = reply;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper filter class for filters that operate on replied messages.
|
||||||
|
/// Provides functionality to traverse reply chains and access replied message content
|
||||||
|
/// and shifts any next message filter to filter the content of found reply.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="replyDepth"></param>
|
||||||
|
public class FromReplyChainFilter(int replyDepth = 1) : Filter<Message>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the replied message at the specified depth in the reply chain.
|
||||||
|
/// </summary>
|
||||||
|
public Message Reply { get; private set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the depth of reply chain traversal.
|
||||||
|
/// </summary>
|
||||||
|
public int ReplyDepth { get; private set; } = replyDepth;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if the message can pass through the filter by first validating
|
||||||
|
/// the reply chain and then applying specific filter logic.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The filter execution context containing the message.</param>
|
||||||
|
/// <returns>True if the message passes both reply validation and specific filter criteria; otherwise, false.</returns>
|
||||||
|
public override bool CanPass(FilterExecutionContext<Message> context)
|
||||||
|
{
|
||||||
|
Message reply = context.Input;
|
||||||
|
for (int i = ReplyDepth; i > 0; i--)
|
||||||
|
{
|
||||||
|
if (reply.ReplyToMessage is not { Id: > 0 } replyMessage)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
reply = replyMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
Reply = reply;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks if the replied message was sent by the bot itself.
|
||||||
|
/// <para>( ! ): REQUIRES <see cref="MessageHasReplyFilter"/> before</para>
|
||||||
|
/// </summary>
|
||||||
|
public class MeRepliedFilter : Filter<Message>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the replied message was sent by the bot.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The filter execution context containing bot information.</param>
|
||||||
|
/// <returns>True if the replied message was sent by the bot; otherwise, false.</returns>
|
||||||
|
public override bool CanPass(FilterExecutionContext<Message> context)
|
||||||
|
{
|
||||||
|
MessageHasReplyFilter repliedFilter = context.CompletedFilters.Get<MessageHasReplyFilter>(0);
|
||||||
|
return context.BotInfo.User == repliedFilter.Reply.From;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,182 +1,181 @@
|
|||||||
using Telegram.Bot.Types;
|
using Telegram.Bot.Types;
|
||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
|
|
||||||
namespace Telegrator.Filters
|
namespace Telegrator.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract base class for filters that operate on message senders.
|
||||||
|
/// Provides functionality to access and validate the user who sent the message.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class MessageSenderFilter : MessageFilterBase
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstract base class for filters that operate on message senders.
|
/// Gets the user who sent the message.
|
||||||
/// Provides functionality to access and validate the user who sent the message.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class MessageSenderFilter : MessageFilterBase
|
public User User { get; private set; } = null!;
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the user who sent the message.
|
|
||||||
/// </summary>
|
|
||||||
public User User { get; private set; } = null!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines if the message can pass through the filter by validating
|
|
||||||
/// that the message has a valid sender.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The filter execution context containing the message.</param>
|
|
||||||
/// <returns>True if the message has a valid sender; otherwise, false.</returns>
|
|
||||||
public override bool CanPass(FilterExecutionContext<Message> context)
|
|
||||||
{
|
|
||||||
if (!base.CanPassBase(context))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
User = Target.From!;
|
|
||||||
if (User is not { Id: > 0 })
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return CanPassNext(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filter that checks if the message sender has a specific username.
|
/// Determines if the message can pass through the filter by validating
|
||||||
|
/// that the message has a valid sender.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="username">The username to check for.</param>
|
/// <param name="context">The filter execution context containing the message.</param>
|
||||||
public class FromUsernameFilter(string username) : MessageSenderFilter
|
/// <returns>True if the message has a valid sender; otherwise, false.</returns>
|
||||||
|
public override bool CanPass(FilterExecutionContext<Message> context)
|
||||||
{
|
{
|
||||||
/// <summary>
|
if (!base.CanPassBase(context))
|
||||||
/// The username to check for.
|
return false;
|
||||||
/// </summary>
|
|
||||||
private readonly string _username = username;
|
|
||||||
|
|
||||||
/// <summary>
|
User = Target.From!;
|
||||||
/// The string comparison type to use for username matching.
|
if (User is not { Id: > 0 })
|
||||||
/// </summary>
|
return false;
|
||||||
private readonly StringComparison _comparison = StringComparison.InvariantCulture;
|
|
||||||
|
|
||||||
/// <summary>
|
return CanPassNext(context);
|
||||||
/// Initializes a new instance of the <see cref="FromUsernameFilter"/> class with custom string comparison.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="username">The username to check for.</param>
|
|
||||||
/// <param name="comparison">The string comparison type to use.</param>
|
|
||||||
public FromUsernameFilter(string username, StringComparison comparison)
|
|
||||||
: this(username) => _comparison = comparison;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the message sender has the specified username.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The filter execution context (unused).</param>
|
|
||||||
/// <returns>True if the sender has the specified username; otherwise, false.</returns>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
|
||||||
=> User.Username != null && User.Username.Equals(_username, _comparison);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Filter that checks if the message sender has specific first and/or last name.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="firstName">The first name to check for.</param>
|
|
||||||
/// <param name="lastName">The last name to check for (optional).</param>
|
|
||||||
/// <param name="comparison">The string comparison type to use.</param>
|
|
||||||
public class FromUserFilter(string firstName, string? lastName, StringComparison comparison) : MessageSenderFilter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The first name to check for.
|
|
||||||
/// </summary>
|
|
||||||
private readonly string _firstName = firstName;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The last name to check for (optional).
|
|
||||||
/// </summary>
|
|
||||||
private readonly string? _lastName = lastName;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The string comparison type to use for name matching.
|
|
||||||
/// </summary>
|
|
||||||
private readonly StringComparison _comparison = comparison;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="FromUserFilter"/> class with first and last name.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="firstName">The first name to check for.</param>
|
|
||||||
/// <param name="lastName">The last name to check for.</param>
|
|
||||||
public FromUserFilter(string firstName, string lastName)
|
|
||||||
: this(firstName, lastName, StringComparison.InvariantCulture) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="FromUserFilter"/> class with first name only.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="firstName">The first name to check for.</param>
|
|
||||||
public FromUserFilter(string firstName)
|
|
||||||
: this(firstName, null, StringComparison.InvariantCulture) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="FromUserFilter"/> class with first name and custom comparison.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="firstName">The first name to check for.</param>
|
|
||||||
/// <param name="comparison">The string comparison type to use.</param>
|
|
||||||
public FromUserFilter(string firstName, StringComparison comparison)
|
|
||||||
: this(firstName, null, comparison) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the message sender has the specified first and/or last name.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The filter execution context (unused).</param>
|
|
||||||
/// <returns>True if the sender has the specified name(s); otherwise, false.</returns>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
|
||||||
{
|
|
||||||
if (User.LastName != null)
|
|
||||||
{
|
|
||||||
if (_lastName == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!_firstName.Equals(User.LastName, _comparison))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return User.FirstName.Equals(_firstName, _comparison);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Filter that checks if the message sender has a specific user ID.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="userId">The user ID to check for.</param>
|
|
||||||
public class FromUserIdFilter(long userId) : MessageSenderFilter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The user ID to check for.
|
|
||||||
/// </summary>
|
|
||||||
private readonly long _userId = userId;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the message sender has the specified user ID.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="_">The filter execution context (unused).</param>
|
|
||||||
/// <returns>True if the sender has the specified user ID; otherwise, false.</returns>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
|
||||||
=> User.Id == _userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Filter that checks if the message was sent by a bot.
|
|
||||||
/// </summary>
|
|
||||||
public class FromBotFilter() : MessageSenderFilter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the message was sent by a bot.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="_">The filter execution context (unused).</param>
|
|
||||||
/// <returns>True if the message was sent by a bot; otherwise, false.</returns>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
|
||||||
=> User.IsBot;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Filter that checks if the message was sent by a premium user.
|
|
||||||
/// </summary>
|
|
||||||
public class FromPremiumUserFilter() : MessageSenderFilter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the message was sent by a premium user.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="_">The filter execution context (unused).</param>
|
|
||||||
/// <returns>True if the message was sent by a premium user; otherwise, false.</returns>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
|
||||||
=> User.IsPremium;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks if the message sender has a specific username.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="username">The username to check for.</param>
|
||||||
|
public class FromUsernameFilter(string username) : MessageSenderFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The username to check for.
|
||||||
|
/// </summary>
|
||||||
|
private readonly string _username = username;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The string comparison type to use for username matching.
|
||||||
|
/// </summary>
|
||||||
|
private readonly StringComparison _comparison = StringComparison.InvariantCulture;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="FromUsernameFilter"/> class with custom string comparison.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="username">The username to check for.</param>
|
||||||
|
/// <param name="comparison">The string comparison type to use.</param>
|
||||||
|
public FromUsernameFilter(string username, StringComparison comparison)
|
||||||
|
: this(username) => _comparison = comparison;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the message sender has the specified username.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The filter execution context (unused).</param>
|
||||||
|
/// <returns>True if the sender has the specified username; otherwise, false.</returns>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
||||||
|
=> User.Username != null && User.Username.Equals(_username, _comparison);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks if the message sender has specific first and/or last name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstName">The first name to check for.</param>
|
||||||
|
/// <param name="lastName">The last name to check for (optional).</param>
|
||||||
|
/// <param name="comparison">The string comparison type to use.</param>
|
||||||
|
public class FromUserFilter(string firstName, string? lastName, StringComparison comparison) : MessageSenderFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The first name to check for.
|
||||||
|
/// </summary>
|
||||||
|
private readonly string _firstName = firstName;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The last name to check for (optional).
|
||||||
|
/// </summary>
|
||||||
|
private readonly string? _lastName = lastName;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The string comparison type to use for name matching.
|
||||||
|
/// </summary>
|
||||||
|
private readonly StringComparison _comparison = comparison;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="FromUserFilter"/> class with first and last name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstName">The first name to check for.</param>
|
||||||
|
/// <param name="lastName">The last name to check for.</param>
|
||||||
|
public FromUserFilter(string firstName, string lastName)
|
||||||
|
: this(firstName, lastName, StringComparison.InvariantCulture) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="FromUserFilter"/> class with first name only.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstName">The first name to check for.</param>
|
||||||
|
public FromUserFilter(string firstName)
|
||||||
|
: this(firstName, null, StringComparison.InvariantCulture) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="FromUserFilter"/> class with first name and custom comparison.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstName">The first name to check for.</param>
|
||||||
|
/// <param name="comparison">The string comparison type to use.</param>
|
||||||
|
public FromUserFilter(string firstName, StringComparison comparison)
|
||||||
|
: this(firstName, null, comparison) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the message sender has the specified first and/or last name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The filter execution context (unused).</param>
|
||||||
|
/// <returns>True if the sender has the specified name(s); otherwise, false.</returns>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
||||||
|
{
|
||||||
|
if (User.LastName != null)
|
||||||
|
{
|
||||||
|
if (_lastName == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!_firstName.Equals(User.LastName, _comparison))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return User.FirstName.Equals(_firstName, _comparison);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks if the message sender has a specific user ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId">The user ID to check for.</param>
|
||||||
|
public class FromUserIdFilter(long userId) : MessageSenderFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The user ID to check for.
|
||||||
|
/// </summary>
|
||||||
|
private readonly long _userId = userId;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the message sender has the specified user ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="_">The filter execution context (unused).</param>
|
||||||
|
/// <returns>True if the sender has the specified user ID; otherwise, false.</returns>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
||||||
|
=> User.Id == _userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks if the message was sent by a bot.
|
||||||
|
/// </summary>
|
||||||
|
public class FromBotFilter() : MessageSenderFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the message was sent by a bot.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="_">The filter execution context (unused).</param>
|
||||||
|
/// <returns>True if the message was sent by a bot; otherwise, false.</returns>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
||||||
|
=> User.IsBot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks if the message was sent by a premium user.
|
||||||
|
/// </summary>
|
||||||
|
public class FromPremiumUserFilter() : MessageSenderFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the message was sent by a premium user.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="_">The filter execution context (unused).</param>
|
||||||
|
/// <returns>True if the message was sent by a premium user; otherwise, false.</returns>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
||||||
|
=> User.IsPremium;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,185 +1,183 @@
|
|||||||
using Telegram.Bot.Types;
|
using Telegram.Bot.Types;
|
||||||
using Telegrator.Core.Filters;
|
using Telegrator.Core.Filters;
|
||||||
using static System.Net.Mime.MediaTypeNames;
|
|
||||||
|
|
||||||
namespace Telegrator.Filters
|
namespace Telegrator.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract base class for filters that operate on message text content.
|
||||||
|
/// Provides common functionality for extracting and validating message text.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class MessageTextFilter : MessageFilterBase
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstract base class for filters that operate on message text content.
|
/// Gets the current message being processed by the filter.
|
||||||
/// Provides common functionality for extracting and validating message text.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class MessageTextFilter : MessageFilterBase
|
public Message Message { get; private set; } = null!;
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the current message being processed by the filter.
|
|
||||||
/// </summary>
|
|
||||||
public Message Message { get; private set; } = null!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the extracted text content from the current message.
|
|
||||||
/// </summary>
|
|
||||||
public string Text { get; private set; } = null!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines if the message can pass through the filter by validating the message
|
|
||||||
/// and extracting its text content for further processing.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The filter execution context containing the message update.</param>
|
|
||||||
/// <returns>True if the message is valid and can be processed further; otherwise, false.</returns>
|
|
||||||
public override bool CanPass(FilterExecutionContext<Message> context)
|
|
||||||
{
|
|
||||||
if (!base.CanPassBase(context))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (Target is not { Id: > 0, Text.Length: > 0 })
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Text = Target.Text;
|
|
||||||
return CanPassNext(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filter that checks if the message text starts with a specified content.
|
/// Gets the extracted text content from the current message.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="content">The content to check if the message text starts with.</param>
|
public string Text { get; private set; } = null!;
|
||||||
/// <param name="comparison">The string comparison type to use for the check.</param>
|
|
||||||
public class TextStartsWithFilter(string content, StringComparison comparison = StringComparison.InvariantCulture) : MessageTextFilter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The content to check if the message text starts with.
|
|
||||||
/// </summary>
|
|
||||||
protected readonly string Content = content;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The string comparison type to use for the check.
|
|
||||||
/// </summary>
|
|
||||||
protected readonly StringComparison Comparison = comparison;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the message text starts with the specified content using the configured comparison.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="_">The filter execution context (unused).</param>
|
|
||||||
/// <returns>True if the text starts with the specified content; otherwise, false.</returns>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
|
||||||
=> Text.StartsWith(Content, Comparison);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filter that checks if the message text ends with a specified content.
|
/// Determines if the message can pass through the filter by validating the message
|
||||||
|
/// and extracting its text content for further processing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="content">The content to check if the message text ends with.</param>
|
/// <param name="context">The filter execution context containing the message update.</param>
|
||||||
/// <param name="comparison">The string comparison type to use for the check.</param>
|
/// <returns>True if the message is valid and can be processed further; otherwise, false.</returns>
|
||||||
public class TextEndsWithFilter(string content, StringComparison comparison = StringComparison.InvariantCulture) : MessageTextFilter
|
public override bool CanPass(FilterExecutionContext<Message> context)
|
||||||
{
|
{
|
||||||
/// <summary>
|
if (!base.CanPassBase(context))
|
||||||
/// The content to check if the message text ends with.
|
return false;
|
||||||
/// </summary>
|
|
||||||
protected readonly string Content = content;
|
|
||||||
|
|
||||||
/// <summary>
|
if (Target is not { Id: > 0, Text.Length: > 0 })
|
||||||
/// The string comparison type to use for the check.
|
return false;
|
||||||
/// </summary>
|
|
||||||
protected readonly StringComparison Comparison = comparison;
|
|
||||||
|
|
||||||
/// <summary>
|
Text = Target.Text;
|
||||||
/// Checks if the message text ends with the specified content using the configured comparison.
|
return CanPassNext(context);
|
||||||
/// </summary>
|
|
||||||
/// <param name="_">The filter execution context (unused).</param>
|
|
||||||
/// <returns>True if the text ends with the specified content; otherwise, false.</returns>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
|
||||||
=> Text.EndsWith(Content, Comparison);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Filter that checks if the message text contains a specified content.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="content">The content to check if the message text contains.</param>
|
|
||||||
/// <param name="comparison">The string comparison type to use for the check.</param>
|
|
||||||
public class TextContainsFilter(string content, StringComparison comparison = StringComparison.InvariantCulture) : MessageTextFilter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The content to check if the message text contains.
|
|
||||||
/// </summary>
|
|
||||||
protected readonly string Content = content;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The string comparison type to use for the check.
|
|
||||||
/// </summary>
|
|
||||||
protected readonly StringComparison Comparison = comparison;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the message text contains the specified content using the configured comparison.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="_">The filter execution context (unused).</param>
|
|
||||||
/// <returns>True if the text contains the specified content; otherwise, false.</returns>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
|
||||||
=> Text.IndexOf(Content, Comparison) >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Filter that checks if the message text equals a specified content.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="content">The content to check if the message text equals.</param>
|
|
||||||
/// <param name="comparison">The string comparison type to use for the check.</param>
|
|
||||||
public class TextEqualsFilter(string content, StringComparison comparison = StringComparison.InvariantCulture) : MessageTextFilter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The content to check if the message text equals.
|
|
||||||
/// </summary>
|
|
||||||
protected readonly string Content = content;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The string comparison type to use for the check.
|
|
||||||
/// </summary>
|
|
||||||
protected readonly StringComparison Comparison = comparison;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the message text equals the specified content using the configured comparison.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="_">The filter execution context (unused).</param>
|
|
||||||
/// <returns>True if the text equals the specified content; otherwise, false.</returns>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
|
||||||
=> Text.Equals(Content, Comparison);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Filter that checks if the message text is not null or empty.
|
|
||||||
/// </summary>
|
|
||||||
public class TextNotNullOrEmptyFilter() : MessageTextFilter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the message text is not null or empty.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="_">The filter execution context (unused).</param>
|
|
||||||
/// <returns>True if the text is not null or empty; otherwise, false.</returns>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
|
||||||
=> !string.IsNullOrEmpty(Text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Filter that checks if the message text contains a 'word'.
|
|
||||||
/// 'Word' must be a separate member of the text, and not have any alphabetic characters next to it.
|
|
||||||
/// </summary>
|
|
||||||
public class TextContainsWordFilter(string word, StringComparison comparison = StringComparison.InvariantCulture, int startIndex = 0) : MessageTextFilter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The content to check if the message text equals.
|
|
||||||
/// </summary>
|
|
||||||
protected readonly string Word = word;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The string comparison type to use for the check.
|
|
||||||
/// </summary>
|
|
||||||
protected readonly StringComparison Comparison = comparison;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The search starting position.
|
|
||||||
/// </summary>
|
|
||||||
protected readonly int StartIndex = startIndex;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
|
||||||
=> Text.ContainsWord(Word, Comparison, StartIndex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks if the message text starts with a specified content.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">The content to check if the message text starts with.</param>
|
||||||
|
/// <param name="comparison">The string comparison type to use for the check.</param>
|
||||||
|
public class TextStartsWithFilter(string content, StringComparison comparison = StringComparison.InvariantCulture) : MessageTextFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The content to check if the message text starts with.
|
||||||
|
/// </summary>
|
||||||
|
protected readonly string Content = content;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The string comparison type to use for the check.
|
||||||
|
/// </summary>
|
||||||
|
protected readonly StringComparison Comparison = comparison;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the message text starts with the specified content using the configured comparison.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="_">The filter execution context (unused).</param>
|
||||||
|
/// <returns>True if the text starts with the specified content; otherwise, false.</returns>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
||||||
|
=> Text.StartsWith(Content, Comparison);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks if the message text ends with a specified content.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">The content to check if the message text ends with.</param>
|
||||||
|
/// <param name="comparison">The string comparison type to use for the check.</param>
|
||||||
|
public class TextEndsWithFilter(string content, StringComparison comparison = StringComparison.InvariantCulture) : MessageTextFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The content to check if the message text ends with.
|
||||||
|
/// </summary>
|
||||||
|
protected readonly string Content = content;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The string comparison type to use for the check.
|
||||||
|
/// </summary>
|
||||||
|
protected readonly StringComparison Comparison = comparison;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the message text ends with the specified content using the configured comparison.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="_">The filter execution context (unused).</param>
|
||||||
|
/// <returns>True if the text ends with the specified content; otherwise, false.</returns>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
||||||
|
=> Text.EndsWith(Content, Comparison);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks if the message text contains a specified content.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">The content to check if the message text contains.</param>
|
||||||
|
/// <param name="comparison">The string comparison type to use for the check.</param>
|
||||||
|
public class TextContainsFilter(string content, StringComparison comparison = StringComparison.InvariantCulture) : MessageTextFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The content to check if the message text contains.
|
||||||
|
/// </summary>
|
||||||
|
protected readonly string Content = content;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The string comparison type to use for the check.
|
||||||
|
/// </summary>
|
||||||
|
protected readonly StringComparison Comparison = comparison;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the message text contains the specified content using the configured comparison.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="_">The filter execution context (unused).</param>
|
||||||
|
/// <returns>True if the text contains the specified content; otherwise, false.</returns>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
||||||
|
=> Text.IndexOf(Content, Comparison) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks if the message text equals a specified content.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">The content to check if the message text equals.</param>
|
||||||
|
/// <param name="comparison">The string comparison type to use for the check.</param>
|
||||||
|
public class TextEqualsFilter(string content, StringComparison comparison = StringComparison.InvariantCulture) : MessageTextFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The content to check if the message text equals.
|
||||||
|
/// </summary>
|
||||||
|
protected readonly string Content = content;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The string comparison type to use for the check.
|
||||||
|
/// </summary>
|
||||||
|
protected readonly StringComparison Comparison = comparison;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the message text equals the specified content using the configured comparison.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="_">The filter execution context (unused).</param>
|
||||||
|
/// <returns>True if the text equals the specified content; otherwise, false.</returns>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
||||||
|
=> Text.Equals(Content, Comparison);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks if the message text is not null or empty.
|
||||||
|
/// </summary>
|
||||||
|
public class TextNotNullOrEmptyFilter() : MessageTextFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the message text is not null or empty.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="_">The filter execution context (unused).</param>
|
||||||
|
/// <returns>True if the text is not null or empty; otherwise, false.</returns>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> _)
|
||||||
|
=> !string.IsNullOrEmpty(Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter that checks if the message text contains a 'word'.
|
||||||
|
/// 'Word' must be a separate member of the text, and not have any alphabetic characters next to it.
|
||||||
|
/// </summary>
|
||||||
|
public class TextContainsWordFilter(string word, StringComparison comparison = StringComparison.InvariantCulture, int startIndex = 0) : MessageTextFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The content to check if the message text equals.
|
||||||
|
/// </summary>
|
||||||
|
protected readonly string Word = word;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The string comparison type to use for the check.
|
||||||
|
/// </summary>
|
||||||
|
protected readonly StringComparison Comparison = comparison;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The search starting position.
|
||||||
|
/// </summary>
|
||||||
|
protected readonly int StartIndex = startIndex;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected override bool CanPassNext(FilterExecutionContext<Message> context)
|
||||||
|
=> Text.ContainsWord(Word, Comparison, StartIndex);
|
||||||
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user