From 92df5e9c792d6ba4d4eacec12bcc8cdb52c6ebae Mon Sep 17 00:00:00 2001 From: Rikitav Date: Tue, 19 Aug 2025 12:10:40 +0400 Subject: [PATCH] * hotfix of aspects inspection * Added IHandlersManager. interface that allows both collecting and providing handlers --- Telegrator.Hosting.Web/TelegramBotWebHost.cs | 22 +-- .../Telegrator.Hosting.Web.csproj | 2 +- Telegrator.Hosting/TelegramBotHost.cs | 10 +- Telegrator.Hosting/Telegrator.Hosting.csproj | 2 +- .../Descriptors/HandlerInspector.cs | 2 +- Telegrator/MadiatorCore/IHandlersManager.cs | 11 ++ Telegrator/Providers/HandlersCollection.cs | 5 +- Telegrator/Providers/HandlersManagerBase.cs | 128 ++++++++++++++++++ Telegrator/Telegrator.csproj | 2 +- 9 files changed, 168 insertions(+), 16 deletions(-) create mode 100644 Telegrator/MadiatorCore/IHandlersManager.cs create mode 100644 Telegrator/Providers/HandlersManagerBase.cs diff --git a/Telegrator.Hosting.Web/TelegramBotWebHost.cs b/Telegrator.Hosting.Web/TelegramBotWebHost.cs index 56fb5a6..207e075 100644 --- a/Telegrator.Hosting.Web/TelegramBotWebHost.cs +++ b/Telegrator.Hosting.Web/TelegramBotWebHost.cs @@ -3,17 +3,14 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using System.Text; using Telegram.Bot.Types.Enums; using Telegrator.Configuration; using Telegrator.Hosting.Components; -using Telegrator.Hosting.Providers; using Telegrator.Hosting.Web.Components; -using Telegrator.Hosting.Logging; -using Telegrator.Logging; using Telegrator.MadiatorCore; using Telegrator.MadiatorCore.Descriptors; @@ -199,15 +196,22 @@ namespace Telegrator.Hosting.Web Logger.LogInformation(logBuilder.ToString()); } - private void RegisterHostServices(IServiceCollection service, IHandlersCollection handlers) + private void RegisterHostServices(IServiceCollection services, IHandlersCollection handlers) { //service.RemoveAll(); //service.AddSingleton(this); - service.AddSingleton(this); - service.AddSingleton(this); - service.AddSingleton(this); - service.AddSingleton(handlers); + services.AddSingleton(this); + services.AddSingleton(this); + services.AddSingleton(this); + services.AddSingleton(handlers); + + if (handlers is IHandlersManager manager) + { + services.RemoveAll(); + services.AddSingleton(manager); + services.AddSingleton(manager); + } } } } diff --git a/Telegrator.Hosting.Web/Telegrator.Hosting.Web.csproj b/Telegrator.Hosting.Web/Telegrator.Hosting.Web.csproj index 0ca4cb4..5876b04 100644 --- a/Telegrator.Hosting.Web/Telegrator.Hosting.Web.csproj +++ b/Telegrator.Hosting.Web/Telegrator.Hosting.Web.csproj @@ -15,7 +15,7 @@ True LICENSE README.md - 1.15.4 + 1.15.5 diff --git a/Telegrator.Hosting/TelegramBotHost.cs b/Telegrator.Hosting/TelegramBotHost.cs index 48349a2..ca82e1d 100644 --- a/Telegrator.Hosting/TelegramBotHost.cs +++ b/Telegrator.Hosting/TelegramBotHost.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System.Text; @@ -159,7 +160,14 @@ namespace Telegrator.Hosting services.AddSingleton(this); services.AddSingleton(this); - services.AddSingleton(handlers); + services.AddSingleton(handlers); + + if (handlers is IHandlersManager manager) + { + services.RemoveAll(); + services.AddSingleton(manager); + services.AddSingleton(manager); + } } } } diff --git a/Telegrator.Hosting/Telegrator.Hosting.csproj b/Telegrator.Hosting/Telegrator.Hosting.csproj index 628ddbe..5cbfdf6 100644 --- a/Telegrator.Hosting/Telegrator.Hosting.csproj +++ b/Telegrator.Hosting/Telegrator.Hosting.csproj @@ -16,7 +16,7 @@ True LICENSE README.md - 1.15.4 + 1.15.5 diff --git a/Telegrator/MadiatorCore/Descriptors/HandlerInspector.cs b/Telegrator/MadiatorCore/Descriptors/HandlerInspector.cs index 99f9966..3829db7 100644 --- a/Telegrator/MadiatorCore/Descriptors/HandlerInspector.cs +++ b/Telegrator/MadiatorCore/Descriptors/HandlerInspector.cs @@ -91,7 +91,7 @@ namespace Telegrator.MadiatorCore.Descriptors public static DescriptorAspectsSet GetAspects(Type handlerType) { 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); } } diff --git a/Telegrator/MadiatorCore/IHandlersManager.cs b/Telegrator/MadiatorCore/IHandlersManager.cs new file mode 100644 index 0000000..b026053 --- /dev/null +++ b/Telegrator/MadiatorCore/IHandlersManager.cs @@ -0,0 +1,11 @@ +namespace Telegrator.MadiatorCore +{ + /// + /// Combines and . + /// Provides functionality of collecting, organizing and resolving handlers instances. + /// + public interface IHandlersManager : IHandlersCollection, IHandlersProvider + { + + } +} diff --git a/Telegrator/Providers/HandlersCollection.cs b/Telegrator/Providers/HandlersCollection.cs index 55c0a53..d58ef53 100644 --- a/Telegrator/Providers/HandlersCollection.cs +++ b/Telegrator/Providers/HandlersCollection.cs @@ -74,8 +74,9 @@ namespace Telegrator.Providers throw new Exception("This handler (" + descriptor.HandlerType.FullName + "), must contain constructor without parameters."); _allowedTypes.UnionAdd(descriptor.UpdateType); - foreach (MightAwaitAttribute mightAwaits in descriptor.HandlerType.GetCustomAttributes()) - _allowedTypes.UnionAdd(mightAwaits.UpdateTypes); + MightAwaitAttribute? mightAwait = descriptor.HandlerType.GetCustomAttribute(); + if (mightAwait != null) + _allowedTypes.UnionAdd(mightAwait.UpdateTypes); IntersectCommands(descriptor); HandlerDescriptorList list = GetDescriptorList(descriptor); diff --git a/Telegrator/Providers/HandlersManagerBase.cs b/Telegrator/Providers/HandlersManagerBase.cs new file mode 100644 index 0000000..8f66be4 --- /dev/null +++ b/Telegrator/Providers/HandlersManagerBase.cs @@ -0,0 +1,128 @@ +using System.Reflection; +using Telegram.Bot.Types.Enums; +using Telegrator.Annotations; +using Telegrator.Attributes; +using Telegrator.Configuration; +using Telegrator.Handlers.Components; +using Telegrator.MadiatorCore; +using Telegrator.MadiatorCore.Descriptors; + +namespace Telegrator.Providers +{ + /// + /// Provides functionality of incrementally collecting, organizing and resolving handlers instances. + /// Minimum implementation of . Abstract class, still requires handler instance resolving. + /// + /// + public abstract class HandlersManagerBase(ITelegratorOptions options) : IHandlersManager + { + /// + /// Dictionary that organizes handler descriptors by update type. + /// + protected readonly Dictionary _handlersDictionary = []; + + /// + /// Gets the collection of Telegram.Bot.Types.Enums.UpdateType's allowed by registered handlers + /// + protected readonly List _allowedTypes = []; + + /// + /// Configuration options for handler collecting. + /// + protected readonly ITelegratorOptions? Options = options; + + /// + /// Gets whether handlers must have a parameterless constructor. + /// + protected virtual bool MustHaveParameterlessCtor => true; + + /// + /// List of command aliases that have been registered. + /// + public readonly List CommandAliasses = []; + + /// + public HandlerDescriptorList this[UpdateType updateType] => _handlersDictionary[updateType]; + + /// + public IEnumerable AllowedTypes => _allowedTypes; + + /// + public IEnumerable Keys => _handlersDictionary.Keys; + + /// + public IEnumerable Values => _handlersDictionary.Values; + + /// + public virtual IHandlersCollection AddDescriptor(HandlerDescriptor descriptor) + { + if (MustHaveParameterlessCtor && !descriptor.HandlerType.HasParameterlessCtor()) + throw new Exception("This handler (" + descriptor.HandlerType.FullName + "), must contain constructor without parameters."); + + _allowedTypes.UnionAdd([descriptor.UpdateType]); + MightAwaitAttribute? mightAwait = descriptor.HandlerType.GetCustomAttribute(); + if (mightAwait != null) + _allowedTypes.UnionAdd(mightAwait.UpdateTypes); + + IntersectCommands(descriptor); + HandlerDescriptorList list = GetDescriptorList(descriptor); + + list.Add(descriptor); + return this; + } + + /// + /// Gets the for the specified . + /// + /// The handler descriptor. + /// The handler descriptor list containing the descriptor. + protected virtual HandlerDescriptorList GetDescriptorList(HandlerDescriptor descriptor) + { + UpdateType updateType = UpdateTypeExtensions.SuppressTypes.TryGetValue(descriptor.UpdateType, out UpdateType suppressType) + ? suppressType : descriptor.UpdateType; + + if (!_handlersDictionary.TryGetValue(updateType, out HandlerDescriptorList? list)) + { + list = new HandlerDescriptorList(updateType, Options); + _handlersDictionary.Add(updateType, list); + } + + return list; + } + + /// + /// Checks for intersecting command aliases and handles them according to configuration. + /// + /// The handler descriptor to check for command aliases. + /// Thrown when intersecting command aliases are found and ExceptIntersectingCommandAliases is enabled. + protected virtual void IntersectCommands(HandlerDescriptor descriptor) + { + if (Options == null || !Options.ExceptIntersectingCommandAliases) + return; + + CommandAlliasAttribute? alliasAttribute = descriptor.HandlerType.GetCustomAttribute(); + if (alliasAttribute == null) + return; + + if (CommandAliasses.Intersect(alliasAttribute.Alliases, StringComparer.InvariantCultureIgnoreCase).Any()) + throw new Exception(descriptor.HandlerType.FullName); + + CommandAliasses.AddRange(alliasAttribute.Alliases); + } + + /// + public bool TryGetDescriptorList(UpdateType updateType, out HandlerDescriptorList? list) + { + return _handlersDictionary.TryGetValue(updateType, out list); + } + + /// + public bool IsEmpty() + { + return _handlersDictionary.Any(pair => pair.Value.Count != 0); + } + + /// + public abstract UpdateHandlerBase GetHandlerInstance(HandlerDescriptor descriptor, CancellationToken cancellationToken = default); + } +} diff --git a/Telegrator/Telegrator.csproj b/Telegrator/Telegrator.csproj index f5b6b74..6d50a3d 100644 --- a/Telegrator/Telegrator.csproj +++ b/Telegrator/Telegrator.csproj @@ -17,7 +17,7 @@ telegram;bot;mediator;attributes;aspect;hosting;host;framework;easy;simple;handlers README.md LICENSE - 1.15.4 + 1.15.5