diff --git a/Telegrator.Analyzers/GlobalSuppressions.cs b/Telegrator.Analyzers/GlobalSuppressions.cs
new file mode 100644
index 0000000..361f387
--- /dev/null
+++ b/Telegrator.Analyzers/GlobalSuppressions.cs
@@ -0,0 +1,8 @@
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project.
+// Project-level suppressions either have no target or are given
+// a specific target and scoped to a namespace, type, member, etc.
+
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: SuppressMessage("Style", "IDE0090")]
diff --git a/Telegrator.Generators/GlobalSuppressions.cs b/Telegrator.Generators/GlobalSuppressions.cs
new file mode 100644
index 0000000..361f387
--- /dev/null
+++ b/Telegrator.Generators/GlobalSuppressions.cs
@@ -0,0 +1,8 @@
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project.
+// Project-level suppressions either have no target or are given
+// a specific target and scoped to a namespace, type, member, etc.
+
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: SuppressMessage("Style", "IDE0090")]
diff --git a/Telegrator.Hosting.Web/Polling/HostedUpdateWebhooker.cs b/Telegrator.Hosting.Web/Polling/HostedUpdateWebhooker.cs
index b2cccf6..b62ac92 100644
--- a/Telegrator.Hosting.Web/Polling/HostedUpdateWebhooker.cs
+++ b/Telegrator.Hosting.Web/Polling/HostedUpdateWebhooker.cs
@@ -1,6 +1,5 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
@@ -22,7 +21,7 @@ namespace Telegrator.Hosting.Web.Polling
private readonly ITelegramBotWebHost _botHost;
private readonly ITelegramBotClient _botClient;
private readonly IUpdateRouter _updateRouter;
- private readonly TelegramBotWebOptions _options;
+ private readonly TelegratorWebOptions _options;
///
/// Initiallizes new instance of
@@ -32,7 +31,7 @@ namespace Telegrator.Hosting.Web.Polling
///
///
///
- public HostedUpdateWebhooker(ITelegramBotWebHost botHost, ITelegramBotClient botClient, IUpdateRouter updateRouter, IOptions options)
+ public HostedUpdateWebhooker(ITelegramBotWebHost botHost, ITelegramBotClient botClient, IUpdateRouter updateRouter, IOptions options)
{
if (string.IsNullOrEmpty(options.Value.WebhookUri))
throw new ArgumentNullException(nameof(options), "Option \"WebhookUrl\" must be set to subscribe for update recieving");
diff --git a/Telegrator.Hosting.Web/TelegramBotWebHostBuilder.cs b/Telegrator.Hosting.Web/TelegramBotWebHostBuilder.cs
index cab6f3d..bec7707 100644
--- a/Telegrator.Hosting.Web/TelegramBotWebHostBuilder.cs
+++ b/Telegrator.Hosting.Web/TelegramBotWebHostBuilder.cs
@@ -43,10 +43,6 @@ namespace Telegrator.Hosting.Web
_innerBuilder = webApplicationBuilder;
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
_handlers = new HostHandlersCollection(Services, _settings);
-
- Services.AddSingleton>(Options.Create(settings));
- Services.Configure(Configuration.GetSection(nameof(TelegratorOptions)));
- Services.Configure(Configuration.GetSection(nameof(TelegramBotClientOptions)), new TelegramBotClientOptionsProxy());
}
///
@@ -67,6 +63,15 @@ namespace Telegrator.Hosting.Web
}
}
+ if (!_settings.DisableAutoConfigure)
+ {
+ Services.Configure(Configuration.GetSection(nameof(TelegratorWebOptions)));
+ Services.Configure(Configuration.GetSection(nameof(TelegratorOptions)));
+ Services.Configure(Configuration.GetSection(nameof(TelegramBotClientOptions)), new TelegramBotClientOptionsProxy());
+ }
+
+ Services.AddSingleton(Configuration);
+ Services.AddSingleton>(Options.Create(_settings));
return new TelegramBotWebHost(_innerBuilder, _handlers);
}
}
diff --git a/Telegrator.Hosting/Polling/HostUpdateHandlersPool.cs b/Telegrator.Hosting/Polling/HostUpdateHandlersPool.cs
index 82bb1a2..ad21b7a 100644
--- a/Telegrator.Hosting/Polling/HostUpdateHandlersPool.cs
+++ b/Telegrator.Hosting/Polling/HostUpdateHandlersPool.cs
@@ -1,6 +1,5 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
-using Telegrator.MadiatorCore.Descriptors;
using Telegrator.Polling;
namespace Telegrator.Hosting.Polling
@@ -9,12 +8,5 @@ namespace Telegrator.Hosting.Polling
public class HostUpdateHandlersPool(IOptions options, ILogger logger) : UpdateHandlersPool(options.Value, options.Value.GlobalCancellationToken)
{
private readonly ILogger _logger = logger;
-
- ///
- protected override async Task ExecuteHandlerWrapper(DescribedHandlerInfo enqueuedHandler)
- {
- //_logger.LogInformation("Handler \"{0}\" has entered execution pool", enqueuedHandler.DisplayString);
- await base.ExecuteHandlerWrapper(enqueuedHandler);
- }
}
}
diff --git a/Telegrator.Hosting/TelegramBotHostBuilder.cs b/Telegrator.Hosting/TelegramBotHostBuilder.cs
index c15713c..69a0606 100644
--- a/Telegrator.Hosting/TelegramBotHostBuilder.cs
+++ b/Telegrator.Hosting/TelegramBotHostBuilder.cs
@@ -77,6 +77,7 @@ namespace Telegrator.Hosting
}
Services.AddSingleton>(Options.Create(_settings));
+ Services.AddSingleton(Configuration);
return new TelegramBotHost(_innerBuilder, _handlers);
}
}
diff --git a/Telegrator.Tests/TestUpdateHandler.cs b/Telegrator.Tests/TestUpdateHandler.cs
index 6248edf..341fcb5 100644
--- a/Telegrator.Tests/TestUpdateHandler.cs
+++ b/Telegrator.Tests/TestUpdateHandler.cs
@@ -13,11 +13,11 @@ namespace Telegrator.Tests
{
public bool WasExecuted { get; private set; }
- public override Task Execute(IAbstractHandlerContainer container, CancellationToken cancellationToken)
+ public override Task Execute(IAbstractHandlerContainer container, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
WasExecuted = true;
- return Task.CompletedTask;
+ return Task.FromResult(Result.Ok());
}
}
}
diff --git a/Telegrator.sln b/Telegrator.sln
index f9bed94..88c8e42 100644
--- a/Telegrator.sln
+++ b/Telegrator.sln
@@ -20,6 +20,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegrator.Analyzers", "Tel
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegrator.Hosting.Web", "Telegrator.Hosting.Web\Telegrator.Hosting.Web.csproj", "{98AB490F-6A36-CCFF-F6E6-B029D1665965}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SosalBot", "..\SosalBot\SosalBot\SosalBot.csproj", "{D6AA4D47-0DCE-520E-5779-A14EA9CB1DEC}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
AnalyzersDebug|Any CPU = AnalyzersDebug|Any CPU
@@ -63,6 +65,12 @@ Global
{98AB490F-6A36-CCFF-F6E6-B029D1665965}.Debug|Any CPU.Build.0 = Debug|Any CPU
{98AB490F-6A36-CCFF-F6E6-B029D1665965}.Release|Any CPU.ActiveCfg = Release|Any CPU
{98AB490F-6A36-CCFF-F6E6-B029D1665965}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D6AA4D47-0DCE-520E-5779-A14EA9CB1DEC}.AnalyzersDebug|Any CPU.ActiveCfg = Release|Any CPU
+ {D6AA4D47-0DCE-520E-5779-A14EA9CB1DEC}.AnalyzersDebug|Any CPU.Build.0 = Release|Any CPU
+ {D6AA4D47-0DCE-520E-5779-A14EA9CB1DEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D6AA4D47-0DCE-520E-5779-A14EA9CB1DEC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D6AA4D47-0DCE-520E-5779-A14EA9CB1DEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D6AA4D47-0DCE-520E-5779-A14EA9CB1DEC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Telegrator/Configuration/ITelegratorOptions.cs b/Telegrator/Configuration/ITelegratorOptions.cs
index 82b61b9..5c0787b 100644
--- a/Telegrator/Configuration/ITelegratorOptions.cs
+++ b/Telegrator/Configuration/ITelegratorOptions.cs
@@ -6,11 +6,18 @@
///
public interface ITelegratorOptions
{
+ /*
///
/// Gets or sets a value indicating whether only the first found handler should be executed for each update.
///
public bool ExecuteOnlyFirstFoundHanlder { get; set; }
+ ///
+ /// Gets or sets a value indicating whether to descend the indexr of handler's index on register. ('false' by default)
+ ///
+ public bool DescendDescriptorIndex { get; set; }
+ */
+
///
/// Gets or sets the maximum number of parallel working handlers. Null means no limit.
///
@@ -21,19 +28,14 @@
///
public bool ExclusiveAwaitingHandlerRouting { get; set; }
- ///
- /// Gets or sets the global cancellation token for all bot operations.
- ///
- public CancellationToken GlobalCancellationToken { get; set; }
-
- ///
- /// Gets or sets a value indicating whether to descend the indexr of handler's index on register. ('false' by default)
- ///
- public bool DescendDescriptorIndex { get; set; }
-
///
/// Gets or sets a value indicating whether to exclude intersecting command aliases.
///
public bool ExceptIntersectingCommandAliases { get; set; }
+
+ ///
+ /// Gets or sets the global cancellation token for all bot operations.
+ ///
+ public CancellationToken GlobalCancellationToken { get; set; }
}
}
diff --git a/Telegrator/Handlers/Building/AwaiterHandler.cs b/Telegrator/Handlers/Building/AwaiterHandler.cs
index 3912aa8..acfd31a 100644
--- a/Telegrator/Handlers/Building/AwaiterHandler.cs
+++ b/Telegrator/Handlers/Building/AwaiterHandler.cs
@@ -51,10 +51,10 @@ namespace Telegrator.Handlers.Building
/// The handler container (unused).
/// The cancellation token (unused).
/// A completed task.
- protected override Task ExecuteInternal(IHandlerContainer container, CancellationToken cancellation)
+ protected override Task ExecuteInternal(IHandlerContainer container, CancellationToken cancellation)
{
ResetEvent.Set();
- return Task.CompletedTask;
+ return Task.FromResult(Result.Ok());
}
///
diff --git a/Telegrator/Handlers/Building/BuildedAbstractHandler.cs b/Telegrator/Handlers/Building/BuildedAbstractHandler.cs
index ff926cd..14c215b 100644
--- a/Telegrator/Handlers/Building/BuildedAbstractHandler.cs
+++ b/Telegrator/Handlers/Building/BuildedAbstractHandler.cs
@@ -31,7 +31,7 @@ namespace Telegrator.Handlers.Building
/// The handler container with execution context.
/// The cancellation token.
/// A task representing the asynchronous execution.
- public override Task Execute(IAbstractHandlerContainer container, CancellationToken cancellation)
+ public override Task Execute(IAbstractHandlerContainer container, CancellationToken cancellation)
=> HandlerAction.Invoke(container, cancellation);
}
}
diff --git a/Telegrator/Handlers/Building/HandlerBuilder.cs b/Telegrator/Handlers/Building/HandlerBuilder.cs
index a9dda1c..5a00776 100644
--- a/Telegrator/Handlers/Building/HandlerBuilder.cs
+++ b/Telegrator/Handlers/Building/HandlerBuilder.cs
@@ -11,7 +11,7 @@ namespace Telegrator.Handlers.Building
/// The handler container with execution context.
/// The cancellation token.
/// A task representing the asynchronous execution.
- public delegate Task AbstractHandlerAction(IAbstractHandlerContainer container, CancellationToken cancellation) where TUpdate : class;
+ public delegate Task AbstractHandlerAction(IAbstractHandlerContainer container, CancellationToken cancellation) where TUpdate : class;
///
/// Builder class for creating regular handlers that can process updates.
diff --git a/Telegrator/Handlers/Components/AbstractUpdateHandler.cs b/Telegrator/Handlers/Components/AbstractUpdateHandler.cs
index db5b9c4..794204b 100644
--- a/Telegrator/Handlers/Components/AbstractUpdateHandler.cs
+++ b/Telegrator/Handlers/Components/AbstractUpdateHandler.cs
@@ -74,10 +74,10 @@ namespace Telegrator.Handlers.Components
/// The handler container.
/// Cancellation token.
/// A task representing the asynchronous operation.
- protected override sealed async Task ExecuteInternal(IHandlerContainer container, CancellationToken cancellationToken)
+ protected override sealed async Task ExecuteInternal(IHandlerContainer container, CancellationToken cancellationToken)
{
Container = (IAbstractHandlerContainer)container;
- await Execute(Container, cancellationToken);
+ return await Execute(Container, cancellationToken);
}
///
@@ -86,6 +86,6 @@ namespace Telegrator.Handlers.Components
/// The handler container.
/// Cancellation token.
/// A task representing the asynchronous operation.
- public abstract Task Execute(IAbstractHandlerContainer container, CancellationToken cancellation);
+ public abstract Task Execute(IAbstractHandlerContainer container, CancellationToken cancellation);
}
}
diff --git a/Telegrator/Handlers/Components/BranchingUpdateHandler.cs b/Telegrator/Handlers/Components/BranchingUpdateHandler.cs
index a8b6108..a15cd6f 100644
--- a/Telegrator/Handlers/Components/BranchingUpdateHandler.cs
+++ b/Telegrator/Handlers/Components/BranchingUpdateHandler.cs
@@ -118,13 +118,13 @@ namespace Telegrator.Handlers.Components
/// The handler container.
/// The cancellation token.
/// Thrown when no branch method is set.
- public override async Task Execute(IAbstractHandlerContainer container, CancellationToken cancellation)
+ public override async Task Execute(IAbstractHandlerContainer container, CancellationToken cancellation)
{
if (branchMethodInfo is null)
throw new Exception();
Cancellation = cancellation;
- await BranchExecuteWrapper(container, branchMethodInfo);
+ return await BranchExecuteWrapper(container, branchMethodInfo);
}
///
@@ -132,21 +132,20 @@ namespace Telegrator.Handlers.Components
///
/// The handler container.
/// The method to execute.
- protected virtual async Task BranchExecuteWrapper(IAbstractHandlerContainer container, MethodInfo methodInfo)
+ protected virtual async Task BranchExecuteWrapper(IAbstractHandlerContainer container, MethodInfo methodInfo)
{
if (methodInfo.ReturnType == typeof(void))
{
methodInfo.Invoke(this, []);
- return;
+ return Result.Ok();
}
else
{
object branchReturn = methodInfo.Invoke(this, []);
- if (branchReturn == null)
- return;
-
- if (branchReturn is Task branchTask)
- await branchTask;
+ if (branchReturn is not Task branchTask)
+ throw new InvalidOperationException();
+
+ return await branchTask;
}
}
diff --git a/Telegrator/Handlers/Components/UpdateHandlerBase.cs b/Telegrator/Handlers/Components/UpdateHandlerBase.cs
index a4ef62f..d2e3a37 100644
--- a/Telegrator/Handlers/Components/UpdateHandlerBase.cs
+++ b/Telegrator/Handlers/Components/UpdateHandlerBase.cs
@@ -24,10 +24,16 @@ namespace Telegrator.Handlers.Components
/// The for the update.
/// The cancellation token.
/// A representing the asynchronous operation.
- public async Task Execute(IHandlerContainer container, CancellationToken cancellationToken = default)
+ public async Task Execute(IHandlerContainer container, CancellationToken cancellationToken = default)
{
- await ExecuteInternal(container, cancellationToken);
- LifetimeToken.LifetimeEnded();
+ try
+ {
+ return await ExecuteInternal(container, cancellationToken);
+ }
+ finally
+ {
+ LifetimeToken.LifetimeEnded();
+ }
}
///
@@ -36,6 +42,6 @@ namespace Telegrator.Handlers.Components
/// The for the update.
/// The cancellation token.
/// A representing the asynchronous operation.
- protected abstract Task ExecuteInternal(IHandlerContainer container, CancellationToken cancellationToken);
+ protected abstract Task ExecuteInternal(IHandlerContainer container, CancellationToken cancellationToken);
}
}
diff --git a/Telegrator/Handlers/Result.cs b/Telegrator/Handlers/Result.cs
new file mode 100644
index 0000000..589e7e0
--- /dev/null
+++ b/Telegrator/Handlers/Result.cs
@@ -0,0 +1,30 @@
+namespace Telegrator.Handlers
+{
+ public sealed class Result
+ {
+ public bool Positive { get; }
+
+ public bool RouteNext { get; }
+
+ public Type? NextType { get; }
+
+ internal Result(bool positive, bool routeNext, Type? nextType)
+ {
+ Positive = positive;
+ RouteNext = routeNext;
+ NextType = nextType;
+ }
+
+ public static Result Ok()
+ => new Result(true, false, null);
+
+ public static Result Fault()
+ => new Result(false, false, null);
+
+ public static Result Next()
+ => new Result(true, true, null);
+
+ public static Result Next()
+ => new Result(true, true, typeof(T));
+ }
+}
diff --git a/Telegrator/MadiatorCore/Descriptors/DefaultCustomDescriptors.cs b/Telegrator/MadiatorCore/Descriptors/DefaultCustomDescriptors.cs
index caa272b..b34f4b4 100644
--- a/Telegrator/MadiatorCore/Descriptors/DefaultCustomDescriptors.cs
+++ b/Telegrator/MadiatorCore/Descriptors/DefaultCustomDescriptors.cs
@@ -15,6 +15,8 @@ namespace Telegrator.MadiatorCore.Descriptors
///
public class MethodHandlerDescriptor : HandlerDescriptor where TUpdate : class
{
+ private readonly MethodInfo Method;
+
///
/// Initializes new instance of
///
@@ -28,15 +30,23 @@ namespace Telegrator.MadiatorCore.Descriptors
UpdateType = handlerAttribute.Type;
Indexer = handlerAttribute.GetIndexer();
Filters = new DescriptorFiltersSet(handlerAttribute, stateKeeperAttribute, filters);
- DisplayString = HandlerInspector.GetDisplayName(action.Method);
- InstanceFactory = () => new MethodHandler(action.Method, UpdateType);
+ 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(MethodInfo method, UpdateType updateType) : AbstractUpdateHandler(updateType)
+ private class MethodHandler(UpdateType updateType) : AbstractUpdateHandler(updateType)
{
- private readonly MethodInfo Method = method;
+ internal MethodInfo Method = null!;
- public override async Task Execute(IAbstractHandlerContainer container, CancellationToken cancellation)
+ public override async Task Execute(IAbstractHandlerContainer container, CancellationToken cancellation)
{
if (Method is null)
throw new Exception();
@@ -44,16 +54,15 @@ namespace Telegrator.MadiatorCore.Descriptors
if (Method.ReturnType == typeof(void))
{
Method.Invoke(this, [container, cancellation]);
- return;
+ return Result.Ok();
}
else
{
object branchReturn = Method.Invoke(this, [container, cancellation]);
- if (branchReturn == null)
- return;
+ if (branchReturn is not Task branchTask)
+ throw new InvalidOperationException();
- if (branchReturn is Task branchTask)
- await branchTask;
+ return await branchTask;
}
}
}
diff --git a/Telegrator/MadiatorCore/Descriptors/DescribedHandlerInfo.cs b/Telegrator/MadiatorCore/Descriptors/DescribedHandlerInfo.cs
index 8506fc3..b5ea82a 100644
--- a/Telegrator/MadiatorCore/Descriptors/DescribedHandlerInfo.cs
+++ b/Telegrator/MadiatorCore/Descriptors/DescribedHandlerInfo.cs
@@ -2,6 +2,7 @@
using Telegram.Bot.Polling;
using Telegram.Bot.Types;
using Telegrator.Filters.Components;
+using Telegrator.Handlers;
using Telegrator.Handlers.Components;
namespace Telegrator.MadiatorCore.Descriptors
@@ -81,36 +82,43 @@ namespace Telegrator.MadiatorCore.Descriptors
/// Cancellation token.
/// A task representing the asynchronous operation.
/// Thrown if the handler lifetime has ended or the handler is not a container factory.
- public async Task Execute(CancellationToken cancellationToken)
+ public async Task Execute(CancellationToken cancellationToken)
{
if (HandlerLifetime.IsEnded)
throw new Exception();
- IHandlerContainerFactory? containerFactory = HandlerInstance is IHandlerContainerFactory handlerDefainedContainerFactory
- ? handlerDefainedContainerFactory
- : UpdateRouter.DefaultContainerFactory is not null
- ? UpdateRouter.DefaultContainerFactory
- : throw new Exception();
-
try
{
- HandlerContainer = containerFactory.CreateContainer(UpdateRouter.AwaitingProvider, this);
- await HandlerInstance.Execute(HandlerContainer, cancellationToken);
+ HandlerContainer = GetContainer(UpdateRouter.AwaitingProvider, this);
+ return await HandlerInstance.Execute(HandlerContainer, cancellationToken);
}
catch (OperationCanceledException)
{
// Cancelled
_ = 0xBAD + 0xC0DE;
- return;
+ return Result.Ok();
}
catch (Exception exception)
{
await UpdateRouter
.HandleErrorAsync(Client, exception, HandleErrorSource.HandleUpdateError, cancellationToken)
.ConfigureAwait(false);
+
+ return Result.Fault();
}
}
+ private IHandlerContainer GetContainer(IAwaitingProvider awaitingProvider, DescribedHandlerInfo handlerInfo)
+ {
+ if (HandlerInstance is IHandlerContainerFactory handlerDefainedContainerFactory)
+ return handlerDefainedContainerFactory.CreateContainer(awaitingProvider, handlerInfo);
+
+ if (UpdateRouter.DefaultContainerFactory is not null)
+ return UpdateRouter.DefaultContainerFactory.CreateContainer(awaitingProvider, handlerInfo);
+
+ throw new Exception();
+ }
+
///
public override string ToString()
=> DisplayString ?? HandlerInstance.GetType().Name;
diff --git a/Telegrator/MadiatorCore/IUpdateHandlersPool.cs b/Telegrator/MadiatorCore/IUpdateHandlersPool.cs
index 7547626..82b8817 100644
--- a/Telegrator/MadiatorCore/IUpdateHandlersPool.cs
+++ b/Telegrator/MadiatorCore/IUpdateHandlersPool.cs
@@ -7,6 +7,7 @@ namespace Telegrator.MadiatorCore
///
/// The for the enqueued handler.
public delegate void HandlerEnqueued(DescribedHandlerInfo args);
+
///
/// Represents a delegate for when a handler is executing.
///
@@ -24,7 +25,7 @@ namespace Telegrator.MadiatorCore
public event HandlerEnqueued? HandlerEnqueued;
///
- /// Occurs when a handler is executing.
+ /// Occurs when a handler is entering execution.
///
public event HandlerExecuting? HandlerExecuting;
@@ -32,8 +33,9 @@ namespace Telegrator.MadiatorCore
/// Enqueues a collection of handlers for execution.
///
/// The handlers to enqueue.
- public void Enqueue(IEnumerable handlers);
+ public Task Enqueue(IEnumerable handlers);
+ /*
///
/// Enqueues a single handler for execution.
///
@@ -45,5 +47,6 @@ namespace Telegrator.MadiatorCore
///
/// The of the handler to dequeue.
public void Dequeue(HandlerLifetimeToken token);
+ */
}
}
diff --git a/Telegrator/Polling/LimitedDictionary.cs b/Telegrator/Polling/LimitedDictionary.cs
new file mode 100644
index 0000000..0d8bd47
--- /dev/null
+++ b/Telegrator/Polling/LimitedDictionary.cs
@@ -0,0 +1,52 @@
+using System.Collections;
+using System.Collections.Concurrent;
+
+namespace Telegrator.Polling
+{
+ public class LimitedDictionary : IEnumerable>, IDisposable
+ {
+ private readonly int? _maximum;
+ private readonly SemaphoreSlim _semaphore = null!;
+ private readonly ConcurrentDictionary _dict = [];
+
+ public LimitedDictionary(int? maximum)
+ {
+ _maximum = maximum;
+ if (maximum != null)
+ {
+ int value = maximum.Value;
+ _semaphore = new SemaphoreSlim(value, value);
+ }
+ }
+
+ public async Task Add(TKey key, TValue value, CancellationToken cancellationToken)
+ {
+ if (_semaphore != null)
+ await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+ return _dict.TryAdd(key, value);
+ }
+
+ public bool Remove(TKey key, out TValue result)
+ {
+ if (_dict.TryRemove(key, out result))
+ {
+ _semaphore?.Release(1);
+ return true;
+ }
+
+ return false;
+ }
+
+ public IEnumerator> GetEnumerator() => _dict.GetEnumerator();
+
+ IEnumerator IEnumerable.GetEnumerator() => _dict.GetEnumerator();
+
+ ///
+ public void Dispose()
+ {
+ GC.SuppressFinalize(this);
+ _semaphore.Dispose();
+ }
+ }
+}
diff --git a/Telegrator/Polling/LimitedQueue.cs b/Telegrator/Polling/LimitedQueue.cs
new file mode 100644
index 0000000..3d0978c
--- /dev/null
+++ b/Telegrator/Polling/LimitedQueue.cs
@@ -0,0 +1,42 @@
+using System.Collections.Concurrent;
+
+namespace Telegrator.Polling
+{
+ public class LimitedQueue
+ {
+ private readonly int? _maximum;
+ private readonly ConcurrentQueue _queue = [];
+ private readonly SemaphoreSlim _semaphore = null!;
+
+ public LimitedQueue(int? maximum)
+ {
+ _maximum = maximum;
+ if (maximum != null)
+ {
+ int value = maximum.Value;
+ _semaphore = new SemaphoreSlim(value, value);
+ }
+ }
+
+ public async Task Enqueue(T item, CancellationToken cancellationToken)
+ {
+ if (_maximum.HasValue)
+ await _semaphore.WaitAsync(cancellationToken);
+
+ _queue.Enqueue(item);
+ }
+
+ public bool Dequeue(out T result)
+ {
+ if (_queue.TryDequeue(out result))
+ {
+ if (_maximum.HasValue)
+ _semaphore?.Release(1);
+
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/Telegrator/Polling/UpdateHandlersPool.cs b/Telegrator/Polling/UpdateHandlersPool.cs
index b1a3ee9..2252fe2 100644
--- a/Telegrator/Polling/UpdateHandlersPool.cs
+++ b/Telegrator/Polling/UpdateHandlersPool.cs
@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
+using Telegrator.Handlers;
using Telegrator.MadiatorCore;
using Telegrator.MadiatorCore.Descriptors;
@@ -15,6 +16,7 @@ namespace Telegrator.Polling
///
protected object SyncObj = new object();
+ /*
///
/// Event that signals when awaiting handlers are queued.
///
@@ -34,6 +36,13 @@ namespace Telegrator.Polling
/// Dictionary for tracking currently executing handlers.
///
protected readonly ConcurrentDictionary ExecutingHandlersPool = [];
+ */
+
+ //protected readonly ConcurrentDictionary> AwaitingHandlersQueue;
+
+ //protected readonly LimitedDictionary ExecutingHandlersPool;
+
+ protected SemaphoreSlim ExecutingHandlersSemaphore = null!;
///
/// The bot configuration options.
@@ -65,26 +74,62 @@ namespace Telegrator.Polling
{
Options = options;
GlobalCancellationToken = globalCancellationToken;
+ //AwaitingHandlersQueue = new ConcurrentDictionary>();
+ //ExecutingHandlersPool = new LimitedDictionary(options.MaximumParallelWorkingHandlers);
if (options.MaximumParallelWorkingHandlers != null)
{
- ExecutingHandlersSemaphore = new SemaphoreSlim(options.MaximumParallelWorkingHandlers ?? 0);
- AwaitingHandlersQueuedEvent = new ManualResetEventSlim(false);
+ ExecutingHandlersSemaphore = new SemaphoreSlim(options.MaximumParallelWorkingHandlers.Value);
+ //AwaitingHandlersQueuedEvent = new ManualResetEventSlim(false);
}
+ /*
if (Options.MaximumParallelWorkingHandlers != null)
HandlersCheckpoint();
+ */
}
///
- public void Enqueue(IEnumerable handlers)
+ public async Task Enqueue(IEnumerable handlers)
{
- handlers.ForEach(Enqueue);
- }
+ //handlers.ForEach(Enqueue);
+ Result? lastResult = null;
+ foreach (DescribedHandlerInfo handlerInfo in handlers)
+ {
+ if (lastResult?.NextType != null)
+ {
+ if (lastResult.NextType != handlerInfo.HandlerInstance.GetType())
+ continue;
+ }
+
+ if (ExecutingHandlersSemaphore != null)
+ {
+ await ExecutingHandlersSemaphore.WaitAsync();
+ }
+
+ try
+ {
+ HandlerExecuting?.Invoke(handlerInfo);
+ lastResult = await handlerInfo.Execute(GlobalCancellationToken);
+ ExecutingHandlersSemaphore?.Release(1);
+ }
+ catch (OperationCanceledException)
+ {
+ break;
+ }
+
+ if (!lastResult.RouteNext)
+ break;
+ }
+ }
+
+ /*
///
public void Enqueue(DescribedHandlerInfo handlerInfo)
{
+ throw new NotImplementedException();
+
if (Options.MaximumParallelWorkingHandlers == null)
{
Task.Run(async () => await ExecuteHandlerWrapper(handlerInfo));
@@ -111,7 +156,9 @@ namespace Telegrator.Polling
ExecutingHandlersSemaphore.Release(1);
}
}
+ */
+ /*
///
/// Main checkpoint method that manages handler execution in a loop.
/// Continuously processes queued handlers while respecting concurrency limits.
@@ -206,6 +253,7 @@ namespace Telegrator.Polling
return AwaitingHandlersQueue.TryDequeue(out enqueuedHandler);
}
}
+ */
///
/// Disposes of the handlers pool and releases all resources.
@@ -221,11 +269,13 @@ namespace Telegrator.Polling
ExecutingHandlersSemaphore = null!;
}
+ /*
if (AwaitingHandlersQueuedEvent != null)
{
AwaitingHandlersQueuedEvent.Dispose();
AwaitingHandlersQueuedEvent = null!;
}
+ */
if (SyncObj != null)
SyncObj = null!;
diff --git a/Telegrator/Polling/UpdateRouter.cs b/Telegrator/Polling/UpdateRouter.cs
index 691fc13..f75f49e 100644
--- a/Telegrator/Polling/UpdateRouter.cs
+++ b/Telegrator/Polling/UpdateRouter.cs
@@ -96,7 +96,7 @@ namespace Telegrator.Polling
/// The update to handle.
/// The cancellation token.
/// A task representing the asynchronous update handling operation.
- public virtual Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)
+ public virtual async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)
{
// Logging
Alligator.RouterWriteLine("Received Update ({0}) of type \"{1}\"", update.Id, update.Type);
@@ -109,31 +109,28 @@ namespace Telegrator.Polling
if (handlers.Any())
{
// Enqueuing found awiting handlers
- HandlersPool.Enqueue(handlers);
+ await HandlersPool.Enqueue(handlers);
// Chicking if awaiting handlers has exclusive routing
if (Options.ExclusiveAwaitingHandlerRouting)
{
Alligator.RouterWriteLine("Receiving Update ({0}) completed with only awaiting handlers", update.Id);
- return Task.CompletedTask;
+ return;
}
}
// Queuing reagular handlers for execution
- HandlersPool.Enqueue(GetHandlers(HandlersProvider, this, botClient, update, cancellationToken));
+ await HandlersPool.Enqueue(GetHandlers(HandlersProvider, this, botClient, update, cancellationToken));
Alligator.RouterWriteLine("Receiving Update ({0}) finished", update.Id);
- return Task.CompletedTask;
}
catch (OperationCanceledException)
{
Alligator.RouterWriteLine("Receiving Update ({0}) cancelled", update.Id);
- return Task.CompletedTask;
}
catch (Exception ex)
{
Alligator.RouterWriteLine("Receiving Update ({0}) finished with exception {1}", update.Id, ex.Message);
ExceptionHandler?.HandleException(botClient, ex, HandleErrorSource.PollingError, cancellationToken);
- return Task.CompletedTask;
}
}
@@ -162,10 +159,11 @@ namespace Telegrator.Polling
return [];
}
- IEnumerable described = DescribeDescriptors(provider, descriptors, updateRouter, client, update, cancellationToken);
- Alligator.RouterWriteLine("Described total of {0} handlers for Update ({1}) from {2} provider", described.Count(), update.Id, provider.GetType().Name);
- Alligator.RouterWriteLine("Described handlers : {0}", string.Join(", ", described));
- return described;
+ //IEnumerable described = DescribeDescriptors(provider, descriptors, updateRouter, client, update, cancellationToken);
+ //Alligator.RouterWriteLine("Described total of {0} handlers for Update ({1}) from {2} provider", described.Count(), update.Id, provider.GetType().Name);
+ //Alligator.RouterWriteLine("Described handlers : {0}", string.Join(", ", described));
+
+ return DescribeDescriptors(provider, descriptors, updateRouter, client, update, cancellationToken);
}
///
@@ -192,8 +190,11 @@ namespace Telegrator.Polling
continue;
yield return describedHandler;
+
+ /*
if (Options.ExecuteOnlyFirstFoundHanlder)
break;
+ */
}
}
finally
diff --git a/Telegrator/TelegratorOptions.cs b/Telegrator/TelegratorOptions.cs
index 6343b2d..0787b96 100644
--- a/Telegrator/TelegratorOptions.cs
+++ b/Telegrator/TelegratorOptions.cs
@@ -8,23 +8,24 @@ namespace Telegrator
///
public class TelegratorOptions : ITelegratorOptions
{
+ /*
///
public bool ExecuteOnlyFirstFoundHanlder { get; set; }
+ ///
+ public bool DescendDescriptorIndex { get; set; } = true;
+ */
+
///
public int? MaximumParallelWorkingHandlers { get; set; }
///
public bool ExclusiveAwaitingHandlerRouting { get; set; }
- ///
- public CancellationToken GlobalCancellationToken { get; set; }
-
- ///
- public bool DescendDescriptorIndex { get; set; } = true;
-
///
public bool ExceptIntersectingCommandAliases { get; set; } = true;
+ ///
+ public CancellationToken GlobalCancellationToken { get; set; }
}
}