diff --git a/Telegrator.Hosting/Polling/HostedUpdateReceiver.cs b/Telegrator.Hosting/Polling/HostedUpdateReceiver.cs
index bb94ec3..3a5bc52 100644
--- a/Telegrator.Hosting/Polling/HostedUpdateReceiver.cs
+++ b/Telegrator.Hosting/Polling/HostedUpdateReceiver.cs
@@ -27,7 +27,7 @@ namespace Telegrator.Hosting.Polling
{
logger.LogInformation("Starting receiving updates via long-polling");
_receiverOptions.AllowedUpdates = botHost.UpdateRouter.HandlersProvider.AllowedTypes.ToArray();
- ReactiveUpdateReceiver updateReceiver = new ReactiveUpdateReceiver(botClient, _receiverOptions);
+ DefaultUpdateReceiver updateReceiver = new DefaultUpdateReceiver(botClient, _receiverOptions);
await updateReceiver.ReceiveAsync(_updateRouter, stoppingToken).ConfigureAwait(false);
}
}
diff --git a/Telegrator/Attributes/DontCollectAttribute.cs b/Telegrator/Annotations/DontCollectAttribute.cs
similarity index 91%
rename from Telegrator/Attributes/DontCollectAttribute.cs
rename to Telegrator/Annotations/DontCollectAttribute.cs
index c9766b7..77bd276 100644
--- a/Telegrator/Attributes/DontCollectAttribute.cs
+++ b/Telegrator/Annotations/DontCollectAttribute.cs
@@ -1,4 +1,4 @@
-namespace Telegrator.Attributes
+namespace Telegrator.Annotations
{
///
/// Attribute that prevents a class from being automatically collected by the handler collection system.
diff --git a/Telegrator/Attributes/MightAwaitAttribute.cs b/Telegrator/Annotations/MightAwaitAttribute.cs
similarity index 96%
rename from Telegrator/Attributes/MightAwaitAttribute.cs
rename to Telegrator/Annotations/MightAwaitAttribute.cs
index 685550d..0d35886 100644
--- a/Telegrator/Attributes/MightAwaitAttribute.cs
+++ b/Telegrator/Annotations/MightAwaitAttribute.cs
@@ -1,6 +1,6 @@
using Telegram.Bot.Types.Enums;
-namespace Telegrator.Attributes
+namespace Telegrator.Annotations
{
///
/// Attribute that says if this handler can await some of await types, that is not listed by its handler base.
diff --git a/Telegrator/Annotations/Targetted/WelcomeAttribute.cs b/Telegrator/Annotations/Targetted/WelcomeAttribute.cs
index 590f36c..dece1b4 100644
--- a/Telegrator/Annotations/Targetted/WelcomeAttribute.cs
+++ b/Telegrator/Annotations/Targetted/WelcomeAttribute.cs
@@ -14,7 +14,10 @@ namespace Telegrator.Annotations.Targetted
/// Creates new instance of
///
///
- public WelcomeAttribute(bool onlyFirst = false) : base(new MessageChatTypeFilter(ChatType.Private), new CommandAlliasFilter("start"), Filter.If(ctx => !onlyFirst || ctx.Input.Id == 0))
+ public WelcomeAttribute(bool onlyFirst = false) : base(
+ new MessageChatTypeFilter(ChatType.Private),
+ new CommandAlliasFilter("start"),
+ Filter.If(ctx => !onlyFirst || ctx.Input.Id == 0))
{ }
}
}
diff --git a/Telegrator/Exceptions.cs b/Telegrator/Exceptions.cs
index 28cbac6..6bc5ec4 100644
--- a/Telegrator/Exceptions.cs
+++ b/Telegrator/Exceptions.cs
@@ -36,14 +36,14 @@ namespace Telegrator
///
/// The handler info associated with the faulted handler.
///
- public readonly DescribedHandlerInfo HandlerInfo;
+ public readonly DescribedHandlerDescriptor HandlerInfo;
///
/// Initializes a new instance of the class.
///
/// The handler info.
/// The inner exception.
- public HandlerFaultedException(DescribedHandlerInfo handlerInfo, Exception inner)
+ public HandlerFaultedException(DescribedHandlerDescriptor handlerInfo, Exception inner)
: base(string.Format("Handler's \"{0}\" execution was faulted", handlerInfo.DisplayString), inner)
{
HandlerInfo = handlerInfo;
diff --git a/Telegrator/Filters/Components/AnonymousTypeFilter.cs b/Telegrator/Filters/Components/AnonymousTypeFilter.cs
index 2dddc98..7b194ba 100644
--- a/Telegrator/Filters/Components/AnonymousTypeFilter.cs
+++ b/Telegrator/Filters/Components/AnonymousTypeFilter.cs
@@ -42,8 +42,7 @@ namespace Telegrator.Filters.Components
public static AnonymousTypeFilter Compile(IFilter filter, Func getFilterringTarget) where T : class
{
return new AnonymousTypeFilter(
- filter.GetType().Name,
- getFilterringTarget,
+ filter.GetType().Name, getFilterringTarget,
(context, filterringTarget) => CanPassInternal(context, filter, filterringTarget));
}
diff --git a/Telegrator/Handlers/Building/AwaiterHandler.cs b/Telegrator/Handlers/Building/AwaiterHandler.cs
index f9b3acd..ef21c80 100644
--- a/Telegrator/Handlers/Building/AwaiterHandler.cs
+++ b/Telegrator/Handlers/Building/AwaiterHandler.cs
@@ -37,7 +37,7 @@ namespace Telegrator.Handlers.Building
///
/// The handler information containing the update.
/// An empty handler container.
- public IHandlerContainer CreateContainer(DescribedHandlerInfo describedHandler)
+ public IHandlerContainer CreateContainer(DescribedHandlerDescriptor describedHandler)
{
HandlingUpdate = describedHandler.HandlingUpdate;
return new EmptyHandlerContainer();
diff --git a/Telegrator/Handlers/Components/AbstractUpdateHandler.cs b/Telegrator/Handlers/Components/AbstractUpdateHandler.cs
index f0b8d2e..075cdcd 100644
--- a/Telegrator/Handlers/Components/AbstractUpdateHandler.cs
+++ b/Telegrator/Handlers/Components/AbstractUpdateHandler.cs
@@ -62,7 +62,7 @@ namespace Telegrator.Handlers.Components
///
/// The handler descriptor info.
/// The created handler container.
- public virtual IHandlerContainer CreateContainer(DescribedHandlerInfo handlerInfo)
+ public virtual IHandlerContainer CreateContainer(DescribedHandlerDescriptor handlerInfo)
{
return new HandlerContainer(handlerInfo);
}
diff --git a/Telegrator/Handlers/Components/BranchingUpdateHandler.cs b/Telegrator/Handlers/Components/BranchingUpdateHandler.cs
index ab8061d..87484d2 100644
--- a/Telegrator/Handlers/Components/BranchingUpdateHandler.cs
+++ b/Telegrator/Handlers/Components/BranchingUpdateHandler.cs
@@ -106,7 +106,7 @@ namespace Telegrator.Handlers.Components
/// The handler information.
/// A handler container for this branching handler.
/// Thrown when the awaiting provider is not of the expected type.
- public override IHandlerContainer CreateContainer(DescribedHandlerInfo handlerInfo)
+ public override IHandlerContainer CreateContainer(DescribedHandlerDescriptor handlerInfo)
{
return new HandlerContainer(handlerInfo);
}
diff --git a/Telegrator/Handlers/Components/IHandlerContainerFactory.cs b/Telegrator/Handlers/Components/IHandlerContainerFactory.cs
index 8fc9b1c..c6f91b1 100644
--- a/Telegrator/Handlers/Components/IHandlerContainerFactory.cs
+++ b/Telegrator/Handlers/Components/IHandlerContainerFactory.cs
@@ -12,8 +12,8 @@ namespace Telegrator.Handlers.Components
///
/// Creates a new for the specified awaiting provider and handler info.
///
- /// The for the handler.
+ /// The for the handler.
/// A new instance.
- public IHandlerContainer CreateContainer(DescribedHandlerInfo handlerInfo);
+ public IHandlerContainer CreateContainer(DescribedHandlerDescriptor handlerInfo);
}
}
diff --git a/Telegrator/Handlers/Components/IUpdateHandlerBase.cs b/Telegrator/Handlers/Components/IUpdateHandlerBase.cs
index a19085f..77f0c73 100644
--- a/Telegrator/Handlers/Components/IUpdateHandlerBase.cs
+++ b/Telegrator/Handlers/Components/IUpdateHandlerBase.cs
@@ -26,7 +26,7 @@ public interface IUpdateHandlerBase : IDisposable
///
/// The cancellation token.
/// A representing the asynchronous operation.
- Task Execute(DescribedHandlerInfo described, CancellationToken cancellationToken = default);
+ Task Execute(DescribedHandlerDescriptor described, CancellationToken cancellationToken = default);
///
/// Handles failed filters during handler describing.
diff --git a/Telegrator/Handlers/Components/UpdateHandlerBase.cs b/Telegrator/Handlers/Components/UpdateHandlerBase.cs
index a4acb7c..e672577 100644
--- a/Telegrator/Handlers/Components/UpdateHandlerBase.cs
+++ b/Telegrator/Handlers/Components/UpdateHandlerBase.cs
@@ -22,13 +22,13 @@ namespace Telegrator.Handlers.Components
public HandlerLifetimeToken LifetimeToken { get; } = new HandlerLifetimeToken();
///
- public Result Ok => Result.Ok();
+ public static Result Ok => Result.Ok();
///
- public Result Fault => Result.Fault();
+ public static Result Fault => Result.Fault();
///
- public Result Next => Result.Next();
+ public static Result Next => Result.Next();
///
/// Executes the handler logic and marks the lifetime as ended after execution.
@@ -36,7 +36,7 @@ namespace Telegrator.Handlers.Components
///
/// The cancellation token.
/// A representing the asynchronous operation.
- public async Task Execute(DescribedHandlerInfo described, CancellationToken cancellationToken = default)
+ public async Task Execute(DescribedHandlerDescriptor described, CancellationToken cancellationToken = default)
{
if (LifetimeToken.IsEnded)
throw new Exception();
@@ -125,7 +125,7 @@ namespace Telegrator.Handlers.Components
}
}
- internal IHandlerContainer GetContainer(DescribedHandlerInfo handlerInfo)
+ internal IHandlerContainer GetContainer(DescribedHandlerDescriptor handlerInfo)
{
if (this is IHandlerContainerFactory handlerDefainedContainerFactory)
return handlerDefainedContainerFactory.CreateContainer(handlerInfo);
diff --git a/Telegrator/Handlers/HandlerContainer.cs b/Telegrator/Handlers/HandlerContainer.cs
index ffbdd89..5046870 100644
--- a/Telegrator/Handlers/HandlerContainer.cs
+++ b/Telegrator/Handlers/HandlerContainer.cs
@@ -37,7 +37,7 @@ namespace Telegrator.Handlers
/// Initializes new instance of
///
///
- public HandlerContainer(DescribedHandlerInfo handlerInfo)
+ public HandlerContainer(DescribedHandlerDescriptor handlerInfo)
{
ActualUpdate = handlerInfo.HandlingUpdate.GetActualUpdateObject();
HandlingUpdate = handlerInfo.HandlingUpdate;
diff --git a/Telegrator/Handlers/MessageHandler.cs b/Telegrator/Handlers/MessageHandler.cs
index 06bdb13..cf823b3 100644
--- a/Telegrator/Handlers/MessageHandler.cs
+++ b/Telegrator/Handlers/MessageHandler.cs
@@ -197,7 +197,7 @@ namespace Telegrator.Handlers
int? directMessageTopicId = null,
SuggestedPostParameters? suggestedPostParameters = null,
CancellationToken cancellationToken = default)
- => await Container.Response(
+ => await Container.Responce(
text, parseMode, replyParameters,
replyMarkup, linkPreviewOptions,
messageThreadId, entities,
diff --git a/Telegrator/MadiatorCore/Descriptors/DescribedHandlerInfo.cs b/Telegrator/MadiatorCore/Descriptors/DescribedHandlerDescriptor.cs
similarity index 63%
rename from Telegrator/MadiatorCore/Descriptors/DescribedHandlerInfo.cs
rename to Telegrator/MadiatorCore/Descriptors/DescribedHandlerDescriptor.cs
index 98b917b..5c379c6 100644
--- a/Telegrator/MadiatorCore/Descriptors/DescribedHandlerInfo.cs
+++ b/Telegrator/MadiatorCore/Descriptors/DescribedHandlerDescriptor.cs
@@ -1,8 +1,6 @@
using Telegram.Bot;
-using Telegram.Bot.Polling;
using Telegram.Bot.Types;
using Telegrator.Filters.Components;
-using Telegrator.Handlers;
using Telegrator.Handlers.Components;
namespace Telegrator.MadiatorCore.Descriptors
@@ -10,47 +8,49 @@ namespace Telegrator.MadiatorCore.Descriptors
///
/// Contains information about a described handler, including its context, client, and execution logic.
///
- public class DescribedHandlerInfo
+ public class DescribedHandlerDescriptor
{
+ private readonly ManualResetEventSlim ResetEvent = new ManualResetEventSlim(false);
+
///
/// descriptor from that handler was described from
///
- public readonly HandlerDescriptor From;
+ public HandlerDescriptor From { get; }
///
/// The update router associated with this handler.
///
- public readonly IUpdateRouter UpdateRouter;
+ public IUpdateRouter UpdateRouter { get; }
///
/// The awaiting provider to fetch new updates inside handler
///
- public readonly IAwaitingProvider AwaitingProvider;
+ public IAwaitingProvider AwaitingProvider { get; }
///
/// The Telegram bot client used for this handler.
///
- public readonly ITelegramBotClient Client;
+ public ITelegramBotClient Client { get; }
///
/// The handler instance being described.
///
- public readonly UpdateHandlerBase HandlerInstance;
+ public UpdateHandlerBase HandlerInstance { get; }
///
/// Extra data associated with the handler execution.
///
- public readonly Dictionary ExtraData;
+ public Dictionary ExtraData { get; }
///
/// List of completed filters for this handler.
///
- public readonly CompletedFiltersList CompletedFilters;
+ public CompletedFiltersList CompletedFilters { get; }
///
/// The update being handled.
///
- public readonly Update HandlingUpdate;
+ public Update HandlingUpdate { get; }
///
/// Lifetime token for the handler instance.
@@ -63,7 +63,12 @@ namespace Telegrator.MadiatorCore.Descriptors
public string DisplayString { get; set; }
///
- /// Initializes a new instance of the class.
+ /// The final execution result.
+ ///
+ public Result? Result { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
///
/// descriptor from that handler was described from
///
@@ -72,7 +77,14 @@ namespace Telegrator.MadiatorCore.Descriptors
/// The handler instance.
/// The filter execution context.
/// Optional display string.
- public DescribedHandlerInfo(HandlerDescriptor fromDescriptor, IUpdateRouter updateRouter, IAwaitingProvider awaitingProvider, ITelegramBotClient client, UpdateHandlerBase handlerInstance, FilterExecutionContext filterContext, string? displayString)
+ public DescribedHandlerDescriptor(
+ HandlerDescriptor fromDescriptor,
+ IUpdateRouter updateRouter,
+ IAwaitingProvider awaitingProvider,
+ ITelegramBotClient client,
+ UpdateHandlerBase handlerInstance,
+ FilterExecutionContext filterContext,
+ string? displayString)
{
From = fromDescriptor;
UpdateRouter = updateRouter;
@@ -85,6 +97,22 @@ namespace Telegrator.MadiatorCore.Descriptors
DisplayString = displayString ?? fromDescriptor.HandlerType.Name;
}
+ public async Task AwaitResult(CancellationToken cancellationToken)
+ {
+ await Task.Yield();
+ ResetEvent.Reset();
+ ResetEvent.Wait(cancellationToken);
+ }
+
+ public void ReportResult(Result result)
+ {
+ if (result != null)
+ throw new InvalidOperationException("Result already reported");
+
+ Result = result;
+ ResetEvent.Set();
+ }
+
///
public override string ToString()
=> DisplayString ?? From.HandlerType.Name;
diff --git a/Telegrator/MadiatorCore/IRouterExceptionHandler.cs b/Telegrator/MadiatorCore/IRouterExceptionHandler.cs
index 34f6ca8..f421523 100644
--- a/Telegrator/MadiatorCore/IRouterExceptionHandler.cs
+++ b/Telegrator/MadiatorCore/IRouterExceptionHandler.cs
@@ -1,6 +1,5 @@
using Telegram.Bot;
using Telegram.Bot.Polling;
-using Telegrator.Polling;
namespace Telegrator.MadiatorCore
{
diff --git a/Telegrator/MadiatorCore/IUpdateHandlersPool.cs b/Telegrator/MadiatorCore/IUpdateHandlersPool.cs
index 82b8817..e5d4d2e 100644
--- a/Telegrator/MadiatorCore/IUpdateHandlersPool.cs
+++ b/Telegrator/MadiatorCore/IUpdateHandlersPool.cs
@@ -5,14 +5,14 @@ namespace Telegrator.MadiatorCore
///
/// Represents a delegate for when a handler is enqueued.
///
- /// The for the enqueued handler.
- public delegate void HandlerEnqueued(DescribedHandlerInfo args);
+ /// The for the enqueued handler.
+ public delegate void HandlerEnqueued(DescribedHandlerDescriptor args);
///
/// Represents a delegate for when a handler is executing.
///
- /// The for the executing handler.
- public delegate void HandlerExecuting(DescribedHandlerInfo args);
+ /// The for the executing handler.
+ public delegate void HandlerExecuting(DescribedHandlerDescriptor args);
///
/// Provides a pool for managing the execution and queuing of update handlers.
@@ -33,20 +33,6 @@ namespace Telegrator.MadiatorCore
/// Enqueues a collection of handlers for execution.
///
/// The handlers to enqueue.
- public Task Enqueue(IEnumerable handlers);
-
- /*
- ///
- /// Enqueues a single handler for execution.
- ///
- /// The handler to enqueue.
- public void Enqueue(DescribedHandlerInfo handlerInfo);
-
- ///
- /// Dequeues a handler using its lifetime token.
- ///
- /// The of the handler to dequeue.
- public void Dequeue(HandlerLifetimeToken token);
- */
+ public Task Enqueue(params IEnumerable handlers);
}
}
diff --git a/Telegrator/Polling/ReactiveUpdateReceiver.cs b/Telegrator/Polling/DefaultUpdateReceiver.cs
similarity index 97%
rename from Telegrator/Polling/ReactiveUpdateReceiver.cs
rename to Telegrator/Polling/DefaultUpdateReceiver.cs
index a4d5b68..4edbd8e 100644
--- a/Telegrator/Polling/ReactiveUpdateReceiver.cs
+++ b/Telegrator/Polling/DefaultUpdateReceiver.cs
@@ -11,7 +11,7 @@ namespace Telegrator.Polling
///
/// The Telegram bot client for making API requests.
/// Optional receiver options for configuring update polling behavior.
- public class ReactiveUpdateReceiver(ITelegramBotClient client, ReceiverOptions? options) : IUpdateReceiver
+ public class DefaultUpdateReceiver(ITelegramBotClient client, ReceiverOptions? options) : IUpdateReceiver
{
///
/// Gets the receiver options for configuring update polling behavior.
diff --git a/Telegrator/Polling/IUpdateReceiver.cs b/Telegrator/Polling/IUpdateReceiver.cs
new file mode 100644
index 0000000..b81f73d
--- /dev/null
+++ b/Telegrator/Polling/IUpdateReceiver.cs
@@ -0,0 +1,21 @@
+using Telegram.Bot.Polling;
+using Telegram.Bot.Types;
+
+namespace Telegrator.Polling;
+
+///
+/// Requests new s and processes them using provided instance<
+/// /summary>
+public interface IUpdateReceiver
+{
+ ///
+ /// Starts receiving s invoking for each .
+ ///
+ /// This method will block if awaited.
+ ///
+ ///
+ /// The used for processing s
+ /// The with which you can stop receiving
+ /// A that will be completed when cancellation will be requested through
+ Task ReceiveAsync(IUpdateHandler updateHandler, CancellationToken cancellationToken = default);
+}
diff --git a/Telegrator/Polling/UpdateHandlersPool.cs b/Telegrator/Polling/UpdateHandlersPool.cs
index 5b3dd49..3e1dd48 100644
--- a/Telegrator/Polling/UpdateHandlersPool.cs
+++ b/Telegrator/Polling/UpdateHandlersPool.cs
@@ -1,4 +1,6 @@
-using Telegrator.Handlers.Components;
+using System.Security.Authentication.ExtendedProtection;
+using System.Threading.Channels;
+using Telegrator.Handlers.Components;
using Telegrator.Logging;
using Telegrator.MadiatorCore;
using Telegrator.MadiatorCore.Descriptors;
@@ -14,12 +16,18 @@ namespace Telegrator.Polling
///
/// Synchronization object for thread-safe operations.
///
- protected object SyncObj = new object();
+ protected readonly object SyncObj = new object();
+
+ protected readonly Task ChannelReaderTask;
+
+ protected readonly Channel ExecutionChannel;
///
/// Semaphore for controlling the number of concurrently executing handlers.
///
- protected SemaphoreSlim ExecutingHandlersSemaphore = null!;
+ protected readonly SemaphoreSlim? ExecutionLimiter;
+
+ protected readonly IUpdateRouter UpdateRouter;
///
/// The bot configuration options.
@@ -45,72 +53,101 @@ namespace Telegrator.Polling
///
/// Initializes a new instance of the class.
///
+ /// The update handler that claims updates
/// The bot configuration options.
/// The global cancellation token.
- public UpdateHandlersPool(TelegratorOptions options, CancellationToken globalCancellationToken)
+ public UpdateHandlersPool(IUpdateRouter router, TelegratorOptions options, CancellationToken globalCancellationToken)
{
+ UpdateRouter = router;
Options = options;
GlobalCancellationToken = globalCancellationToken;
+
+ ExecutionChannel = Channel.CreateUnbounded(new UnboundedChannelOptions()
+ {
+ SingleReader = true,
+ SingleWriter = true,
+ AllowSynchronousContinuations = false
+ });
if (options.MaximumParallelWorkingHandlers != null)
- {
- ExecutingHandlersSemaphore = new SemaphoreSlim(options.MaximumParallelWorkingHandlers.Value);
- }
+ ExecutionLimiter = new SemaphoreSlim(options.MaximumParallelWorkingHandlers.Value);
+
+ GlobalCancellationToken.Register(() => ExecutionChannel.Writer.Complete());
+ ChannelReaderTask = ReadChannel();
}
///
- public async Task Enqueue(IEnumerable handlers)
+ public async Task Enqueue(params IEnumerable handlers)
{
- Result? lastResult = null;
- foreach (DescribedHandlerInfo handlerInfo in handlers)
+ try
{
- if (lastResult?.NextType != null)
+ foreach (DescribedHandlerDescriptor handlerInfo in handlers)
{
- if (lastResult.NextType != handlerInfo.From.HandlerType)
- continue;
- }
+ if (handlerInfo.UpdateRouter != UpdateRouter)
+ throw new InvalidOperationException("Tried to enqueue update handler info from other router.");
- if (ExecutingHandlersSemaphore != null)
+ await ExecutionChannel.Writer.WriteAsync(handlerInfo, GlobalCancellationToken);
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ _ = 0xDEADBEEF;
+ }
+ }
+
+ private async Task ReadChannel()
+ {
+ try
+ {
+ await foreach (DescribedHandlerDescriptor handlerInfo in ExecutionChannel.Reader.ReadAllAsync(GlobalCancellationToken))
{
- await ExecutingHandlersSemaphore.WaitAsync().ConfigureAwait(false);
- }
+ if (ExecutionLimiter != null)
+ await ExecutionLimiter.WaitAsync(GlobalCancellationToken);
- try
+ // Как только слот получен, "отстреливаем" задачу в ThreadPool
+ // и идем на следующий круг цикла за новым обработчиком из канала.
+ _ = ProcessHandler(handlerInfo);
+ }
+ }
+ catch (ChannelClosedException)
+ {
+ // TODO: add logging
+ }
+ }
+
+ private async Task ProcessHandler(DescribedHandlerDescriptor handlerInfo)
+ {
+ try
+ {
+ Alligator.LogDebug("Described handler '{0}' (Update {1})", handlerInfo.DisplayString, handlerInfo.HandlingUpdate.Id);
+ HandlerExecuting?.Invoke(handlerInfo);
+
+ using UpdateHandlerBase instance = handlerInfo.HandlerInstance;
+ Task task = instance.Execute(handlerInfo);
+ HandlerEnqueued?.Invoke(handlerInfo);
+
+ await task.ConfigureAwait(false);
+ Result lastResult = task.Result;
+
+ handlerInfo.ReportResult(lastResult);
+ ExecutionLimiter?.Release(1);
+
+ if (lastResult.RouteNext)
{
- Alligator.LogDebug("Described handler '{0}' (Update {1})", handlerInfo.DisplayString, handlerInfo.HandlingUpdate.Id);
- HandlerExecuting?.Invoke(handlerInfo);
-
- using (UpdateHandlerBase instance = handlerInfo.HandlerInstance)
- {
- Task task = instance.Execute(handlerInfo);
- HandlerEnqueued?.Invoke(handlerInfo);
-
- await task.ConfigureAwait(false);
- lastResult = task.Result;
- ExecutingHandlersSemaphore?.Release(1);
- }
-
- if (lastResult.RouteNext)
- {
- Alligator.LogTrace("Handler '{0}' requested route continuation (Update {1})", handlerInfo.DisplayString, handlerInfo.HandlingUpdate.Id);
- }
+ Alligator.LogTrace("Handler '{0}' requested route continuation (Update {1})", handlerInfo.DisplayString, handlerInfo.HandlingUpdate.Id);
}
- catch (NotImplementedException)
- {
- _ = 0xBAD + 0xC0DE;
- }
- catch (OperationCanceledException)
- {
- _ = 0xBAD + 0xC0DE;
- break;
- }
- catch (Exception ex)
- {
- Alligator.LogError("Failed to process handler '{0}' (Update {1})", exception: ex, handlerInfo.DisplayString, handlerInfo.HandlingUpdate.Id);
- }
-
- if (lastResult != null && !lastResult.RouteNext)
- break;
+ }
+ catch (NotImplementedException)
+ {
+ _ = 0xBAD + 0xC0DE;
+ }
+ catch (OperationCanceledException)
+ {
+ _ = 0xDEADBEEF;
+ }
+ catch (Exception ex)
+ {
+ Alligator.LogError("Failed to process handler '{0}' (Update {1})", exception: ex, handlerInfo.DisplayString, handlerInfo.HandlingUpdate.Id);
}
}
@@ -122,15 +159,9 @@ namespace Telegrator.Polling
if (disposed)
return;
- if (ExecutingHandlersSemaphore != null)
- {
- ExecutingHandlersSemaphore.Dispose();
- ExecutingHandlersSemaphore = null!;
- }
-
- if (SyncObj != null)
- SyncObj = null!;
-
+ // do not dispose UpdateRouter
+ ExecutionLimiter?.Dispose();
+
GC.SuppressFinalize(this);
disposed = true;
}
diff --git a/Telegrator/Polling/UpdateRouter.cs b/Telegrator/Polling/UpdateRouter.cs
index 5091f0e..3c640f4 100644
--- a/Telegrator/Polling/UpdateRouter.cs
+++ b/Telegrator/Polling/UpdateRouter.cs
@@ -1,4 +1,5 @@
-using System.Text;
+using System.Runtime.InteropServices;
+using System.Text;
using Telegram.Bot;
using Telegram.Bot.Polling;
using Telegram.Bot.Types;
@@ -24,6 +25,7 @@ namespace Telegrator.Polling
private readonly IAwaitingProvider _awaitingProvider;
private readonly IUpdateHandlersPool _HandlersPool;
private readonly ITelegramBotInfo _botInfo;
+ private readonly HandlerDescriptorList _handlingRoutes;
///
public IHandlersProvider HandlersProvider => _handlersProvider;
@@ -55,8 +57,9 @@ namespace Telegrator.Polling
_options = options;
_handlersProvider = handlersProvider;
_awaitingProvider = awaitingProvider;
- _HandlersPool = new UpdateHandlersPool(_options, _options.GlobalCancellationToken);
+ _HandlersPool = new UpdateHandlersPool(this, _options, _options.GlobalCancellationToken);
_botInfo = botInfo;
+ _handlingRoutes = new HandlerDescriptorList();
}
///
@@ -74,6 +77,7 @@ namespace Telegrator.Polling
_awaitingProvider = awaitingProvider;
_HandlersPool = handlersPool;
_botInfo = botInfo;
+ _handlingRoutes = new HandlerDescriptorList();
}
///
@@ -105,19 +109,32 @@ namespace Telegrator.Polling
try
{
- // Getting handlers in update awaiting pool
- IEnumerable handlers = GetHandlers(AwaitingProvider, botClient, update, cancellationToken);
- if (handlers.Any())
+ Result? lastResult = null;
+ foreach (DescribedHandlerDescriptor handlerInfo in GetHandlers(AwaitingProvider, botClient, update, cancellationToken))
{
- // Enqueuing found awiting handlers
- await HandlersPool.Enqueue(handlers);
-
- // Chicking if awaiting handlers has exclusive routing
- if (Options.ExclusiveAwaitingHandlerRouting)
+ if (lastResult?.NextType != null)
{
- Alligator.LogTrace("Receiving Update ({0}) completed with only awaiting handlers", update.Id);
- return;
+ if (lastResult.NextType != handlerInfo.From.HandlerType)
+ continue;
}
+
+ // Enqueuing found awiting handlers
+ await HandlersPool.Enqueue(handlerInfo);
+ await handlerInfo.AwaitResult(cancellationToken).ConfigureAwait(false);
+
+ lastResult = handlerInfo.Result;
+ if (lastResult == null)
+ break; // Smth went horribly wrong, better to stop routing
+
+ if (lastResult != null && !lastResult.RouteNext)
+ break;
+ }
+
+ // Checking if awaiting handlers has exclusive routing
+ if (Options.ExclusiveAwaitingHandlerRouting)
+ {
+ Alligator.LogTrace("Receiving Update ({0}) completed with only awaiting handlers", update.Id);
+ return;
}
// Queuing reagular handlers for execution
@@ -144,7 +161,7 @@ namespace Telegrator.Polling
/// The incoming Telegram update to process
///
/// A collection of described handler information for the update
- protected virtual IEnumerable GetHandlers(IHandlersProvider provider, ITelegramBotClient client, Update update, CancellationToken cancellationToken = default)
+ protected virtual IEnumerable GetHandlers(IHandlersProvider provider, ITelegramBotClient client, Update update, CancellationToken cancellationToken = default)
{
Alligator.LogTrace("Requested handlers for UpdateType.{0}", update.Type);
if (!provider.TryGetDescriptorList(update.Type, out HandlerDescriptorList? descriptors))
@@ -172,13 +189,13 @@ namespace Telegrator.Polling
/// The incoming Telegram update to process
///
/// A collection of described handler information
- protected virtual IEnumerable DescribeDescriptors(IHandlersProvider provider, HandlerDescriptorList descriptors, ITelegramBotClient client, Update update, CancellationToken cancellationToken = default)
+ protected virtual IEnumerable DescribeDescriptors(IHandlersProvider provider, HandlerDescriptorList descriptors, ITelegramBotClient client, Update update, CancellationToken cancellationToken = default)
{
Alligator.LogTrace("Describing descriptors of descriptorsList.HandlingType.{0} for Update ({1})", descriptors.HandlingType, update.Id);
foreach (HandlerDescriptor descriptor in descriptors.Reverse())
{
cancellationToken.ThrowIfCancellationRequested();
- DescribedHandlerInfo? describedHandler = DescribeHandler(provider, descriptor, client, update, out bool breakRouting, cancellationToken);
+ DescribedHandlerDescriptor? describedHandler = DescribeHandler(provider, descriptor, client, update, out bool breakRouting, cancellationToken);
if (breakRouting)
yield break;
@@ -202,7 +219,7 @@ namespace Telegrator.Polling
///
///
/// The described handler info if validation passes; otherwise, null
- public virtual DescribedHandlerInfo? DescribeHandler(IHandlersProvider provider, HandlerDescriptor descriptor, ITelegramBotClient client, Update update, out bool breakRouting, CancellationToken cancellationToken = default)
+ public virtual DescribedHandlerDescriptor? DescribeHandler(IHandlersProvider provider, HandlerDescriptor descriptor, ITelegramBotClient client, Update update, out bool breakRouting, CancellationToken cancellationToken = default)
{
breakRouting = false;
cancellationToken.ThrowIfCancellationRequested();
@@ -231,7 +248,7 @@ namespace Telegrator.Polling
}
}
- return new DescribedHandlerInfo(descriptor, this, AwaitingProvider, client, handlerInstance, filterContext, descriptor.DisplayString);
+ return new DescribedHandlerDescriptor(descriptor, this, AwaitingProvider, client, handlerInstance, filterContext, descriptor.DisplayString);
}
///
diff --git a/Telegrator/Providers/HandlersCollection.cs b/Telegrator/Providers/HandlersCollection.cs
index 37c4f4b..2c41656 100644
--- a/Telegrator/Providers/HandlersCollection.cs
+++ b/Telegrator/Providers/HandlersCollection.cs
@@ -1,7 +1,6 @@
using System.Reflection;
using Telegram.Bot.Types.Enums;
using Telegrator.Annotations;
-using Telegrator.Attributes;
using Telegrator.Configuration;
using Telegrator.MadiatorCore;
using Telegrator.MadiatorCore.Descriptors;
diff --git a/Telegrator/Providers/HandlersManagerBase.cs b/Telegrator/Providers/HandlersManagerBase.cs
index 8f66be4..1883cf1 100644
--- a/Telegrator/Providers/HandlersManagerBase.cs
+++ b/Telegrator/Providers/HandlersManagerBase.cs
@@ -1,7 +1,6 @@
using System.Reflection;
using Telegram.Bot.Types.Enums;
using Telegrator.Annotations;
-using Telegrator.Attributes;
using Telegrator.Configuration;
using Telegrator.Handlers.Components;
using Telegrator.MadiatorCore;
diff --git a/Telegrator/Result.cs b/Telegrator/Result.cs
index 6b987a4..b195b43 100644
--- a/Telegrator/Result.cs
+++ b/Telegrator/Result.cs
@@ -1,9 +1,7 @@
-using Telegram.Bot.Types;
-using Telegrator.Aspects;
+using Telegrator.Aspects;
using Telegrator.Handlers.Components;
-using Telegrator.Filters.Components;
-using Telegrator.MadiatorCore;
using Telegrator.Handlers.Diagnostics;
+using Telegrator.MadiatorCore;
namespace Telegrator
{
diff --git a/Telegrator/Telegrator.csproj b/Telegrator/Telegrator.csproj
index e542237..0f898c0 100644
--- a/Telegrator/Telegrator.csproj
+++ b/Telegrator/Telegrator.csproj
@@ -27,7 +27,8 @@
-
+
+
diff --git a/Telegrator/TelegratorClient.cs b/Telegrator/TelegratorClient.cs
index 4a08021..ce7057b 100644
--- a/Telegrator/TelegratorClient.cs
+++ b/Telegrator/TelegratorClient.cs
@@ -97,7 +97,7 @@ namespace Telegrator
{
try
{
- await new ReactiveUpdateReceiver(this, receiverOptions)
+ await new DefaultUpdateReceiver(this, receiverOptions)
.ReceiveAsync(UpdateRouter, cancellationToken)
.ConfigureAwait(false);
}