using System.Collections.ObjectModel; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; using Telegrator.Handlers.Components; using Telegrator.Logging; using Telegrator.MadiatorCore; using Telegrator.MadiatorCore.Descriptors; namespace Telegrator.Providers { /// /// Provides handler resolution and instantiation logic for Telegram bot updates. /// Responsible for mapping update types to handler descriptors, filtering handlers based on update context, /// and creating handler instances with appropriate lifecycle management. /// public class HandlersProvider : IHandlersProvider { /// public IEnumerable AllowedTypes { get; } /// /// Read-only dictionary mapping to lists of handler descriptors. /// Each descriptor list is frozen to prevent modification after initialization. /// public readonly ReadOnlyDictionary HandlersDictionary; /// /// Configuration options for the bot and handler execution behavior. /// protected readonly TelegratorOptions Options; /// /// Initializes a new instance of with the specified handler collections and configuration. /// /// Collection of handler descriptor lists organized by update type /// Configuration options for the bot and handler execution /// Thrown when options or botInfo is null public HandlersProvider(IHandlersCollection handlers, TelegratorOptions options) { AllowedTypes = handlers.AllowedTypes; HandlersDictionary = handlers.Values.ForEach(list => list.Freeze()).ToReadOnlyDictionary(list => list.HandlingType); Options = options ?? throw new ArgumentNullException(nameof(options)); Alligator.LogTrace("{0} created!", GetType().Name); } /// /// Initializes a new instance of with the specified handler collections and configuration. /// /// Collection of handler descriptor lists organized by update type /// Configuration options for the bot and handler execution /// Thrown when options or botInfo is null public HandlersProvider(IEnumerable handlers, TelegratorOptions options) { AllowedTypes = Update.AllTypes; HandlersDictionary = handlers.ForEach(list => list.Freeze()).ToReadOnlyDictionary(list => list.HandlingType); Options = options ?? throw new ArgumentNullException(nameof(options)); Alligator.LogTrace("{0} created!", GetType().Name); } /// /// Thrown when the descriptor type is not recognized public virtual UpdateHandlerBase GetHandlerInstance(HandlerDescriptor descriptor, CancellationToken cancellationToken = default) { try { // Checking handler instance status cancellationToken.ThrowIfCancellationRequested(); bool useSingleton = UseSingleton(descriptor); // Returning singleton instance if (useSingleton && descriptor.SingletonInstance != null) return descriptor.SingletonInstance; // Creating instance UpdateHandlerBase instance = GetHandlerInstanceInternal(descriptor); if (useSingleton) descriptor.TrySetInstance(instance); // Lazy initialization execution descriptor.LazyInitialization?.Invoke(instance); return instance; } catch (Exception ex) { Alligator.LogError("Failed to create instance of '{0}'", exception: ex, descriptor.ToString()); throw; } } private static UpdateHandlerBase GetHandlerInstanceInternal(HandlerDescriptor descriptor) { if (descriptor.InstanceFactory != null) return descriptor.InstanceFactory.Invoke(); return (UpdateHandlerBase)Activator.CreateInstance(descriptor.HandlerType); } private static bool UseSingleton(HandlerDescriptor descriptor) => descriptor.Type switch { DescriptorType.General or DescriptorType.Keyed => false, DescriptorType.Implicit or DescriptorType.Singleton => true, _ => throw new Exception("Unknown decriptor type") }; /// public virtual bool TryGetDescriptorList(UpdateType updateType, out HandlerDescriptorList? list) { if (UpdateTypeExtensions.SuppressTypes.TryGetValue(updateType, out UpdateType suppressType)) updateType = suppressType; return HandlersDictionary.TryGetValue(updateType, out list); } /// public virtual bool IsEmpty() { return HandlersDictionary.Count == 0; } } }