diff --git a/Telegrator.Hosting.Web/Telegrator.Hosting.Web.csproj b/Telegrator.Hosting.Web/Telegrator.Hosting.Web.csproj
index 211d0b5..ea76a57 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.0.11
+ 1.0.12
diff --git a/Telegrator.Hosting/Telegrator.Hosting.csproj b/Telegrator.Hosting/Telegrator.Hosting.csproj
index 49af79d..555872d 100644
--- a/Telegrator.Hosting/Telegrator.Hosting.csproj
+++ b/Telegrator.Hosting/Telegrator.Hosting.csproj
@@ -16,7 +16,7 @@
True
LICENSE
README.md
- 1.0.11
+ 1.0.12
diff --git a/Telegrator.Hosting/TypesExtensions.cs b/Telegrator.Hosting/TypesExtensions.cs
index d188ac8..d245c30 100644
--- a/Telegrator.Hosting/TypesExtensions.cs
+++ b/Telegrator.Hosting/TypesExtensions.cs
@@ -100,12 +100,13 @@ namespace Telegrator.Hosting
/// Adds a Microsoft.Extensions.Logging adapter to Alligator using a logger factory.
///
///
- public static void AddLoggingAdapter(this ITelegramBotHost host)
+ public static ITelegramBotHost AddLoggingAdapter(this ITelegramBotHost host)
{
ILoggerFactory loggerFactory = host.Services.GetRequiredService();
ILogger logger = loggerFactory.CreateLogger("Telegrator");
MicrosoftLoggingAdapter adapter = new MicrosoftLoggingAdapter(logger);
Alligator.AddAdapter(adapter);
+ return host;
}
}
diff --git a/Telegrator.Tests/Filters/FilterTests.cs b/Telegrator.Tests/Filters/FilterTests.cs
index 98b8f30..e764f19 100644
--- a/Telegrator.Tests/Filters/FilterTests.cs
+++ b/Telegrator.Tests/Filters/FilterTests.cs
@@ -121,7 +121,7 @@ namespace Telegrator.Tests.Filters
var filter2 = Filter.If(_ => true);
var filter3 = Filter.If(_ => false);
- var compiledFilter = CompiledFilter.Compile(filter1, filter2, filter3);
+ var compiledFilter = new CompiledFilter(filter1, filter2, filter3);
var context = new FilterExecutionContext(new TelegramBotInfo(null), new Update(), new Update(), new Dictionary(), new CompletedFiltersList());
// Act
diff --git a/Telegrator/Attributes/Components/UpdateFilterAttributeBase.cs b/Telegrator/Attributes/Components/UpdateFilterAttributeBase.cs
index f2dec42..30c74d1 100644
--- a/Telegrator/Attributes/Components/UpdateFilterAttributeBase.cs
+++ b/Telegrator/Attributes/Components/UpdateFilterAttributeBase.cs
@@ -20,7 +20,7 @@ namespace Telegrator.Attributes.Components
///
/// Gets the that processing
///
- public abstract Filter AnonymousFilter { get; protected set; }
+ public abstract IFilter AnonymousFilter { get; protected set; }
///
/// Gets or sets the filter modifiers that affect how this filter is combined with others.
diff --git a/Telegrator/Attributes/Components/UpdateHandlerAttributeBase.cs b/Telegrator/Attributes/Components/UpdateHandlerAttributeBase.cs
index 1e85896..c765d8b 100644
--- a/Telegrator/Attributes/Components/UpdateHandlerAttributeBase.cs
+++ b/Telegrator/Attributes/Components/UpdateHandlerAttributeBase.cs
@@ -35,6 +35,8 @@ namespace Telegrator.Attributes.Components
///
public int Priority { get; set; }
+ public bool FormReport { get; set; }
+
///
/// Creates a new instance of
///
diff --git a/Telegrator/Attributes/UpdateFilterAttribute.cs b/Telegrator/Attributes/UpdateFilterAttribute.cs
index 8cd145b..dfda0b0 100644
--- a/Telegrator/Attributes/UpdateFilterAttribute.cs
+++ b/Telegrator/Attributes/UpdateFilterAttribute.cs
@@ -15,12 +15,12 @@ namespace Telegrator.Attributes
///
/// Gets the compiled anonymous filter for this attribute.
///
- public override Filter AnonymousFilter { get; protected set; }
+ public override IFilter AnonymousFilter { get; protected set; }
///
/// Gets the compiled filter logic for the update target.
///
- public Filter UpdateFilter { get; protected set; }
+ public IFilter UpdateFilter { get; protected set; }
///
/// Empty constructor for internal using
@@ -38,18 +38,20 @@ namespace Telegrator.Attributes
/// The filters to compose
protected UpdateFilterAttribute(params IFilter[] filters)
{
- UpdateFilter = CompiledFilter.Compile(filters);
- AnonymousFilter = AnonymousTypeFilter.Compile(UpdateFilter, GetFilterringTarget);
+ string name = GetType().Name;
+ UpdateFilter = new CompiledFilter(name, filters);
+ AnonymousFilter = AnonymousTypeFilter.Compile(name, UpdateFilter, GetFilterringTarget);
}
///
/// Initializes the attribute with a precompiled filter for the update target.
///
/// The compiled filter
- protected UpdateFilterAttribute(Filter updateFilter)
+ protected UpdateFilterAttribute(IFilter updateFilter)
{
+ string name = GetType().Name;
UpdateFilter = updateFilter;
- AnonymousFilter = AnonymousTypeFilter.Compile(UpdateFilter, GetFilterringTarget);
+ AnonymousFilter = AnonymousTypeFilter.Compile(name, UpdateFilter, GetFilterringTarget);
}
///
@@ -60,13 +62,13 @@ namespace Telegrator.Attributes
public override sealed bool ProcessModifiers(UpdateFilterAttributeBase? previous)
{
if (Modifiers.HasFlag(FilterModifier.Not))
- AnonymousFilter = AnonymousFilter.Not();
+ AnonymousFilter = Filter.Not(AnonymousFilter);
if (previous is not null)
{
if (previous.Modifiers.HasFlag(FilterModifier.OrNext))
{
- AnonymousFilter = previous.AnonymousFilter.Or(AnonymousFilter);
+ AnonymousFilter = Filter.Or(previous.AnonymousFilter, AnonymousFilter);
}
}
diff --git a/Telegrator/Enums.cs b/Telegrator/Enums.cs
index 6c43850..ca875f2 100644
--- a/Telegrator/Enums.cs
+++ b/Telegrator/Enums.cs
@@ -70,6 +70,7 @@
Sender
}
+ /*
///
/// Messages from where this filter was originated
///
@@ -95,6 +96,7 @@
///
Regualr
}
+ */
/*
///
diff --git a/Telegrator/Filters/Components/AnonymousCompiledFilter.cs b/Telegrator/Filters/Components/AnonymousCompiledFilter.cs
index 2a7a090..2de7496 100644
--- a/Telegrator/Filters/Components/AnonymousCompiledFilter.cs
+++ b/Telegrator/Filters/Components/AnonymousCompiledFilter.cs
@@ -1,5 +1,4 @@
-using Telegram.Bot;
-using Telegram.Bot.Types;
+using Telegram.Bot.Types;
using Telegrator.Logging;
namespace Telegrator.Filters.Components
@@ -7,15 +6,26 @@ namespace Telegrator.Filters.Components
///
/// Represents a compiled filter that applies a set of filters to an anonymous target type.
///
- public sealed class AnonymousCompiledFilter : AnonymousTypeFilter
+ public class AnonymousCompiledFilter : Filter, INamedFilter
{
+ private readonly Func, object, bool> FilterAction;
+ private readonly Func GetFilterringTarget;
+ private readonly string _name;
+
+ public virtual string Name => _name;
+
///
/// Initializes a new instance of the class.
///
+ ///
/// The filter action delegate.
/// The function to get the filtering target from an update.
- private AnonymousCompiledFilter(Func, object, bool> filterAction, Func getFilterringTarget)
- : base(filterAction, getFilterringTarget) { }
+ private AnonymousCompiledFilter(string name, Func getFilterringTarget, Func, object, bool> filterAction)
+ {
+ FilterAction = filterAction;
+ GetFilterringTarget = getFilterringTarget;
+ _name = name;
+ }
///
/// Compiles a set of filters into an for a specific target type.
@@ -24,11 +34,28 @@ namespace Telegrator.Filters.Components
/// The list of filters to compile.
/// The function to get the filtering target from an update.
/// The compiled filter.
- public static AnonymousCompiledFilter Compile(IList> filters, Func getFilterringTarget) where T : class
+ public static AnonymousCompiledFilter Compile(IEnumerable> filters, Func getFilterringTarget) where T : class
{
return new AnonymousCompiledFilter(
- (context, filterringTarget) => CanPassInternal(filters, context, filterringTarget),
- getFilterringTarget);
+ string.Join("+", filters.Select(fltr => fltr.GetType().Name)),
+ getFilterringTarget,
+ (context, filterringTarget) => CanPassInternal(context, filters, filterringTarget));
+ }
+
+ ///
+ /// Compiles a set of filters into an for a specific target type.
+ ///
+ /// The type of the filtering target.
+ ///
+ /// The list of filters to compile.
+ /// The function to get the filtering target from an update.
+ /// The compiled filter.
+ public static AnonymousCompiledFilter Compile(string name, IEnumerable> filters, Func getFilterringTarget) where T : class
+ {
+ return new AnonymousCompiledFilter(
+ name,
+ getFilterringTarget,
+ (context, filterringTarget) => CanPassInternal(context, filters, filterringTarget));
}
///
@@ -39,16 +66,15 @@ namespace Telegrator.Filters.Components
/// The filter execution context.
/// The filtering target.
/// True if all filters pass; otherwise, false.
- private static bool CanPassInternal(IList> filters, FilterExecutionContext updateContext, object filterringTarget) where T : class
+ private static bool CanPassInternal(FilterExecutionContext updateContext, IEnumerable> filters, object filterringTarget) where T : class
{
FilterExecutionContext context = updateContext.CreateChild((T)filterringTarget);
-
foreach (IFilter filter in filters)
{
if (!filter.CanPass(context))
{
if (filter is not AnonymousCompiledFilter && filter is not AnonymousTypeFilter)
- Alligator.LogDebug("{0} filter of {1} didnt pass!", filter.GetType().Name, context.Data["handler_name"]);
+ Alligator.LogDebug("{0} filter of {1} didnt pass! (Compiled anonymous)", filter.GetType().Name, context.Data["handler_name"]);
return false;
}
@@ -58,5 +84,22 @@ namespace Telegrator.Filters.Components
return true;
}
+
+ ///
+ public override bool CanPass(FilterExecutionContext context)
+ {
+ try
+ {
+ object? filterringTarget = GetFilterringTarget.Invoke(context.Input);
+ if (filterringTarget == null)
+ return false;
+
+ return FilterAction.Invoke(context, filterringTarget);
+ }
+ catch
+ {
+ return false;
+ }
+ }
}
}
diff --git a/Telegrator/Filters/Components/AnonymousTypeFilter.cs b/Telegrator/Filters/Components/AnonymousTypeFilter.cs
index f2bb65e..ad13a45 100644
--- a/Telegrator/Filters/Components/AnonymousTypeFilter.cs
+++ b/Telegrator/Filters/Components/AnonymousTypeFilter.cs
@@ -6,20 +6,25 @@ namespace Telegrator.Filters.Components
///
/// Represents a filter that applies a filter action to an anonymous target type extracted from an update.
///
- public class AnonymousTypeFilter : Filter
+ public class AnonymousTypeFilter : Filter, INamedFilter
{
private readonly Func, object, bool> FilterAction;
private readonly Func GetFilterringTarget;
+ private readonly string _name;
+
+ public virtual string Name => _name;
///
/// Initializes a new instance of the class.
///
+ ///
/// The filter action delegate.
/// The function to get the filtering target from an update.
- protected AnonymousTypeFilter(Func, object, bool> filterAction, Func getFilterringTarget)
+ public AnonymousTypeFilter(string name, Func getFilterringTarget, Func, object, bool> filterAction)
{
FilterAction = filterAction;
GetFilterringTarget = getFilterringTarget;
+ _name = name;
}
///
@@ -32,8 +37,25 @@ namespace Telegrator.Filters.Components
public static AnonymousTypeFilter Compile(IFilter filter, Func getFilterringTarget) where T : class
{
return new AnonymousTypeFilter(
- (context, filterringTarget) => CanPassInternal(context, filter, filterringTarget),
- getFilterringTarget);
+ filter.GetType().Name,
+ getFilterringTarget,
+ (context, filterringTarget) => CanPassInternal(context, filter, filterringTarget));
+ }
+
+ ///
+ /// Compiles a filter for a specific target type.
+ ///
+ /// The type of the filtering target.
+ ///
+ /// The filter to apply.
+ /// The function to get the filtering target from an update.
+ /// The compiled filter.
+ public static AnonymousTypeFilter Compile(string name, IFilter filter, Func getFilterringTarget) where T : class
+ {
+ return new AnonymousTypeFilter(
+ name,
+ getFilterringTarget,
+ (context, filterringTarget) => CanPassInternal(context, filter, filterringTarget));
}
///
diff --git a/Telegrator/Filters/Components/CompiledFilter.cs b/Telegrator/Filters/Components/CompiledFilter.cs
index cbe4c97..51a5dfc 100644
--- a/Telegrator/Filters/Components/CompiledFilter.cs
+++ b/Telegrator/Filters/Components/CompiledFilter.cs
@@ -6,27 +6,32 @@ namespace Telegrator.Filters.Components
/// Represents a filter that composes multiple filters and passes only if all of them pass.
///
/// The type of the input for the filter.
- public class CompiledFilter : Filter where T : class
+ public class CompiledFilter : Filter, INamedFilter where T : class
{
private readonly IFilter[] Filters;
+ private readonly string _name;
+
+ public virtual string Name => _name;
///
/// Initializes a new instance of the class.
///
/// The filters to compose.
- private CompiledFilter(IFilter[] filters)
+ public CompiledFilter(params IFilter[] filters)
{
+ _name = string.Join("+", filters.Select(fltr => fltr.GetType().Name));
Filters = filters;
}
///
- /// Compiles multiple filters into a .
+ /// Initializes a new instance of the class.
///
+ ///
/// The filters to compose.
- /// A new instance.
- public static CompiledFilter Compile(params IFilter[] filters)
+ public CompiledFilter(string name, params IFilter[] filters)
{
- return new CompiledFilter(filters);
+ _name = name;
+ Filters = filters;
}
///
@@ -41,14 +46,14 @@ namespace Telegrator.Filters.Components
if (!filter.CanPass(context))
{
if (filter is not AnonymousCompiledFilter && filter is not AnonymousTypeFilter)
- Alligator.LogDebug("{0} filter of {1} didnt pass!", filter.GetType().Name, context.Data["handler_name"]);
+ Alligator.LogDebug("{0} filter of {1} didnt pass! (Compiled)", filter.GetType().Name, context.Data["handler_name"]);
return false;
}
context.CompletedFilters.Add(filter);
}
-
+
return true;
}
}
diff --git a/Telegrator/Filters/Components/IFilter.cs b/Telegrator/Filters/Components/IFilter.cs
index fc4c86a..4b39096 100644
--- a/Telegrator/Filters/Components/IFilter.cs
+++ b/Telegrator/Filters/Components/IFilter.cs
@@ -1,5 +1,10 @@
namespace Telegrator.Filters.Components
{
+ public interface INamedFilter
+ {
+ public string Name { get; }
+ }
+
///
/// Interface for filters that can be collected into a completed filters list.
/// Provides information about whether a filter should be tracked during execution.
diff --git a/Telegrator/Filters/Filter.cs b/Telegrator/Filters/Filter.cs
index 8417a9e..f8802e7 100644
--- a/Telegrator/Filters/Filter.cs
+++ b/Telegrator/Filters/Filter.cs
@@ -30,6 +30,14 @@ namespace Telegrator.Filters
public Filter Not()
=> new ReverseFilter(this);
+ ///
+ /// Creates a filter that inverts the result of this filter.
+ ///
+ ///
+ /// A instance.
+ public static Filter Not(IFilter filter) where Q : class
+ => new ReverseFilter(filter);
+
///
/// Creates a filter that passes only if both this and the specified filter pass.
///
@@ -46,6 +54,16 @@ namespace Telegrator.Filters
public OrFilter Or(IFilter filter)
=> new OrFilter(this, filter);
+ ///
+ /// Creates a filter that passes if either this or the specified filter pass.
+ ///
+ ///
+ ///
+ ///
+ /// An instance.
+ public static OrFilter Or(IFilter left, IFilter right) where Q : class
+ => new OrFilter(left, right);
+
///
/// Gets a value indicating whether this filter is collectible.
///
diff --git a/Telegrator/Handlers/Components/FiltersFallbackReport.cs b/Telegrator/Handlers/Components/FiltersFallbackReport.cs
new file mode 100644
index 0000000..f5d8bcf
--- /dev/null
+++ b/Telegrator/Handlers/Components/FiltersFallbackReport.cs
@@ -0,0 +1,66 @@
+using Telegram.Bot;
+using Telegram.Bot.Types;
+using Telegrator.Attributes.Components;
+using Telegrator.Filters.Components;
+using Telegrator.MadiatorCore.Descriptors;
+
+namespace Telegrator.Handlers.Components
+{
+ public class FiltersFallbackReport(HandlerDescriptor descriptor, FilterExecutionContext context)
+ {
+ public HandlerDescriptor Descriptor { get; } = descriptor;
+
+ public FilterExecutionContext Context { get; } = context;
+
+ public FilterFallbackInfo? UpdateValidator { get; set; }
+
+ public FilterFallbackInfo? StateKeeperValidator { get; set; }
+
+ public List UpdateFilters { get; } = [];
+
+ /*
+ public FilterFallbackInfo OfType(int index = 0) where T : IFilter
+ {
+ return UpdateFilters.Where(info => info.Failed is T).ElementAt(index);
+ }
+
+ public FilterFallbackInfo OfAttribute(int index = 0) where T : UpdateFilterAttributeBase
+ {
+ return UpdateFilters.Where(info => info.Name == typeof(T).Name).ElementAt(index);
+ }
+
+ public FilterFallbackInfo OfName(string name, int index = 0)
+ {
+ return UpdateFilters.Where(info => info.Name == name).ElementAt(index);
+ }
+ */
+
+ public bool ExceptAttribute(int index = 0) where T : UpdateFilterAttributeBase
+ {
+ string name = typeof(T).Name;
+ IEnumerable failed = UpdateFilters.Where(info => info.Failed);
+ if (failed.Count() > 1)
+ return false;
+
+ return failed.SingleOrDefault()?.Name == name;
+ }
+ }
+
+ public class FilterFallbackInfo(string name, IFilter filter, bool failed, Exception? exception)
+ {
+ public string Name { get; } = name;
+
+ public IFilter Filter { get; } = filter;
+
+ public bool Failed { get; } = failed;
+
+ public Exception? Exception { get; } = exception;
+ }
+
+ public enum FallbackReason
+ {
+ NullTarget,
+
+ FailedFilter
+ }
+}
diff --git a/Telegrator/MadiatorCore/Descriptors/HandlerLifetimeToken.cs b/Telegrator/Handlers/Components/HandlerLifetimeToken.cs
similarity index 93%
rename from Telegrator/MadiatorCore/Descriptors/HandlerLifetimeToken.cs
rename to Telegrator/Handlers/Components/HandlerLifetimeToken.cs
index bbafb27..8c9777e 100644
--- a/Telegrator/MadiatorCore/Descriptors/HandlerLifetimeToken.cs
+++ b/Telegrator/Handlers/Components/HandlerLifetimeToken.cs
@@ -1,4 +1,4 @@
-namespace Telegrator.MadiatorCore.Descriptors
+namespace Telegrator.Handlers.Components
{
///
/// Represents a token that tracks the lifetime of a handler instance.
diff --git a/Telegrator/Handlers/Components/UpdateHandlerBase.cs b/Telegrator/Handlers/Components/UpdateHandlerBase.cs
index f243695..fd48988 100644
--- a/Telegrator/Handlers/Components/UpdateHandlerBase.cs
+++ b/Telegrator/Handlers/Components/UpdateHandlerBase.cs
@@ -1,4 +1,5 @@
-using Telegram.Bot.Polling;
+using Telegram.Bot;
+using Telegram.Bot.Polling;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using Telegrator.Filters.Components;
@@ -41,7 +42,10 @@ namespace Telegrator.Handlers.Components
// Executing pre processor
if (aspects != null)
{
- Result? preResult = await aspects.ExecutePre(this, container, cancellationToken).ConfigureAwait(false);
+ Result? preResult = await aspects
+ .ExecutePre(this, container, cancellationToken)
+ .ConfigureAwait(false);
+
if (!preResult.Positive)
return preResult;
}
@@ -54,7 +58,10 @@ namespace Telegrator.Handlers.Components
// Executing post processor
if (aspects != null)
{
- Result postResult = await aspects.ExecutePost(this, container, cancellationToken).ConfigureAwait(false);
+ Result postResult = await aspects
+ .ExecutePost(this, container, cancellationToken)
+ .ConfigureAwait(false);
+
if (!postResult.Positive)
return postResult;
}
@@ -82,7 +89,7 @@ namespace Telegrator.Handlers.Components
}
}
- private IHandlerContainer GetContainer(DescribedHandlerInfo handlerInfo)
+ internal IHandlerContainer GetContainer(DescribedHandlerInfo handlerInfo)
{
if (this is IHandlerContainerFactory handlerDefainedContainerFactory)
return handlerDefainedContainerFactory.CreateContainer(handlerInfo);
@@ -114,14 +121,14 @@ namespace Telegrator.Handlers.Components
///
/// Handles failed filters during handler describing.
/// Use to control how router should treat this fail.
- /// to silently continue decribing.
- /// to stop\break decribing sequence.
+ /// to silently continue decribing.
+ /// to stop\break desribing sequence.
///
- ///
- ///
- ///
+ ///
+ ///
+ ///
///
- public virtual Task FiltersFallback(FilterExecutionContext context, IFilter failedFilter, FilterOrigin origin)
+ public virtual Task FiltersFallback(FiltersFallbackReport report, ITelegramBotClient client, CancellationToken cancellationToken = default)
{
return Task.FromResult(Result.Ok());
}
diff --git a/Telegrator/MadiatorCore/Descriptors/DescriptorFiltersSet.cs b/Telegrator/MadiatorCore/Descriptors/DescriptorFiltersSet.cs
index a38b48d..bf9a2e1 100644
--- a/Telegrator/MadiatorCore/Descriptors/DescriptorFiltersSet.cs
+++ b/Telegrator/MadiatorCore/Descriptors/DescriptorFiltersSet.cs
@@ -1,5 +1,7 @@
using Telegram.Bot.Types;
+using Telegrator.Filters;
using Telegrator.Filters.Components;
+using Telegrator.Handlers.Components;
using Telegrator.Logging;
namespace Telegrator.MadiatorCore.Descriptors
@@ -41,61 +43,108 @@ namespace Telegrator.MadiatorCore.Descriptors
/// Validates the filter context using all filters in the set.
///
/// The filter execution context.
- ///
- ///
+ ///
+ ///
/// True if all filters pass; otherwise, false.
- public bool Validate(FilterExecutionContext filterContext, out IFilter failedFilter, out FilterOrigin origin)
+ public Result Validate(FilterExecutionContext filterContext, bool formReport, ref FiltersFallbackReport report)
{
+ bool anyErrors = false;
+ bool anyMatches = false;
+
if (UpdateValidator != null)
{
- if (!UpdateValidator.CanPass(filterContext))
+ bool result = ExecuteFilter(UpdateValidator, filterContext, out Exception? exc);
+
+ if (formReport)
{
- Alligator.LogDebug("(E) UpdateValidator filter of {0} for Update ({1}) didnt pass!", filterContext.Data["handler_name"], filterContext.Update.Id);
- failedFilter = UpdateValidator;
- origin = FilterOrigin.Validator;
- return false;
+ report.UpdateValidator = new FilterFallbackInfo("Validator", UpdateValidator, !result, exc);
}
- //LeveledDebug.FilterWriteLine("UpdateValidator of {0} for Update ({2}) passed", filterContext.Data["handler_name"]);
- filterContext.CompletedFilters.Add(UpdateValidator);
+ if (!result)
+ {
+ anyErrors = true;
+ Alligator.LogDebug("(E) UpdateValidator filter of '{0}' for Update ({1}) didnt pass!", filterContext.Data["handler_name"], filterContext.Update.Id);
+
+ if (!formReport)
+ return Result.Fault();
+ }
+ else
+ {
+ //anyMatches = true; // DO NOT COUNT
+ filterContext.CompletedFilters.Add(UpdateValidator);
+ }
}
if (StateKeeperValidator != null)
{
- if (!StateKeeperValidator.CanPass(filterContext))
+ bool result = ExecuteFilter(StateKeeperValidator, filterContext, out Exception? exc);
+
+ if (formReport)
{
- Alligator.LogDebug("(E) StateKeeperValidator filter of {0} for Update ({1}) didnt pass!", filterContext.Data["handler_name"], filterContext.Update.Id);
- failedFilter = StateKeeperValidator;
- origin = FilterOrigin.StateKeeper;
- return false;
+ report.StateKeeperValidator = new FilterFallbackInfo("State", StateKeeperValidator, !result, exc);
}
- //LeveledDebug.FilterWriteLine("StateKeeperValidator of {0} for Update ({2}) passed", filterContext.Data["handler_name"]);
- filterContext.CompletedFilters.Add(StateKeeperValidator);
+ if (!result)
+ {
+ anyErrors = true;
+ Alligator.LogDebug("(E) StateKeeperValidator filter of '{0}' for Update ({1}) didnt pass!", filterContext.Data["handler_name"], filterContext.Update.Id);
+
+ if (!formReport)
+ return Result.Fault();
+ }
+ else
+ {
+ anyMatches = true;
+ filterContext.CompletedFilters.Add(StateKeeperValidator);
+ }
}
if (UpdateFilters != null)
{
foreach (IFilter filter in UpdateFilters)
{
- if (!filter.CanPass(filterContext))
- {
- if (filter is not AnonymousCompiledFilter && filter is not AnonymousTypeFilter)
- Alligator.LogDebug("(E) {0} filter of {1} for Update ({2}) didnt pass!", filter.GetType().Name, filterContext.Data["handler_name"], filterContext.Update.Id);
+ bool result = ExecuteFilter(filter, filterContext, out Exception? exc);
+ string filterName = filter is INamedFilter named ? named.Name : filter.GetType().Name;
- failedFilter = filter;
- origin = FilterOrigin.Regualr;
- return false;
+ if (formReport)
+ {
+ report.UpdateFilters.Add(new FilterFallbackInfo(filterName, filter, !result, exc));
}
- //LeveledDebug.FilterWriteLine("{0} filter of {1} for Update ({2}) passed", filter.GetType().Name, filterContext.Data["handler_name"]);
- filterContext.CompletedFilters.Add(filter);
+ if (!result)
+ {
+ anyErrors = true;
+ Alligator.LogDebug("(E) '{0}' filter of '{1}' for Update ({2}) didnt pass!", filterName, filterContext.Data["handler_name"], filterContext.Update.Id);
+
+ if (!formReport)
+ return Result.Fault();
+ }
+ else
+ {
+ anyMatches = true;
+ filterContext.CompletedFilters.Add(filter);
+ }
}
}
- failedFilter = null!;
- origin = FilterOrigin.None;
- return true;
+ if (!anyErrors)
+ return Result.Ok();
+
+ return formReport ? Result.Next() : Result.Fault();
+ }
+
+ private static bool ExecuteFilter(IFilter filter, FilterExecutionContext context, out Exception? exception) where T : class
+ {
+ try
+ {
+ exception = null;
+ return filter.CanPass(context);
+ }
+ catch (Exception ex)
+ {
+ exception = ex;
+ return false;
+ }
}
}
}
diff --git a/Telegrator/MadiatorCore/Descriptors/HandlerDescriptor.cs b/Telegrator/MadiatorCore/Descriptors/HandlerDescriptor.cs
index 873513a..b66dfb1 100644
--- a/Telegrator/MadiatorCore/Descriptors/HandlerDescriptor.cs
+++ b/Telegrator/MadiatorCore/Descriptors/HandlerDescriptor.cs
@@ -73,6 +73,12 @@ namespace Telegrator.MadiatorCore.Descriptors
set;
}
+ public bool FormReport
+ {
+ get;
+ set;
+ }
+
///
/// The set of filters associated with this handler.
///
@@ -163,6 +169,7 @@ namespace Telegrator.MadiatorCore.Descriptors
UpdateType = handlerAttribute.Type;
Indexer = handlerAttribute.GetIndexer();
+ FormReport = handlerAttribute.FormReport;
Filters = new DescriptorFiltersSet(handlerAttribute, stateKeeperAttribute, filters);
Aspects = HandlerInspector.GetAspects(handlerType);
DisplayString = HandlerInspector.GetDisplayName(handlerType);
diff --git a/Telegrator/Polling/UpdateRouter.cs b/Telegrator/Polling/UpdateRouter.cs
index 3e55b21..9209c8c 100644
--- a/Telegrator/Polling/UpdateRouter.cs
+++ b/Telegrator/Polling/UpdateRouter.cs
@@ -178,23 +178,21 @@ namespace Telegrator.Polling
/// A collection of described handler information
protected virtual IEnumerable DescribeDescriptors(IHandlersProvider provider, HandlerDescriptorList descriptors, ITelegramBotClient client, Update update, CancellationToken cancellationToken = default)
{
- try
+ Alligator.LogDebug("Describing descriptors of descriptorsList.HandlingType.{0} for Update ({1})", descriptors.HandlingType, update.Id);
+ foreach (HandlerDescriptor descriptor in descriptors.Reverse())
{
- Alligator.LogDebug("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, cancellationToken);
- if (describedHandler == null)
- continue;
+ cancellationToken.ThrowIfCancellationRequested();
+ DescribedHandlerInfo? describedHandler = DescribeHandler(provider, descriptor, client, update, out bool breakRouting, cancellationToken);
+ if (breakRouting)
+ yield break;
- yield return describedHandler;
- }
- }
- finally
- {
- Alligator.LogDebug("Describing for Update ({0}) finished", update.Id);
+ if (describedHandler == null)
+ continue;
+
+ yield return describedHandler;
}
+
+ Alligator.LogDebug("Describing for Update ({0}) finished", update.Id);
}
///
@@ -205,10 +203,12 @@ namespace Telegrator.Polling
/// The handler descriptor to process
/// The Telegram bot client instance
/// The incoming Telegram update to process
+ ///
///
/// The described handler info if validation passes; otherwise, null
- public virtual DescribedHandlerInfo? DescribeHandler(IHandlersProvider provider, HandlerDescriptor descriptor, ITelegramBotClient client, Update update, CancellationToken cancellationToken = default)
+ public virtual DescribedHandlerInfo? DescribeHandler(IHandlersProvider provider, HandlerDescriptor descriptor, ITelegramBotClient client, Update update, out bool breakRouting, CancellationToken cancellationToken = default)
{
+ breakRouting = false;
cancellationToken.ThrowIfCancellationRequested();
Dictionary data = new Dictionary()
{
@@ -216,15 +216,23 @@ namespace Telegrator.Polling
};
UpdateHandlerBase handlerInstance = provider.GetHandlerInstance(descriptor, cancellationToken);
-
FilterExecutionContext filterContext = new FilterExecutionContext(_botInfo, update, update, data, []);
- if (descriptor.Filters != null && !descriptor.Filters.Validate(filterContext, out IFilter failedFilter, out FilterOrigin origin))
- {
- Result fallbackResult = handlerInstance.FiltersFallback(filterContext, failedFilter, origin).Result;
- if (!fallbackResult.Positive)
- throw new BreakDescribingException();
- return null;
+ if (descriptor.Filters != null)
+ {
+ FiltersFallbackReport report = new FiltersFallbackReport(descriptor, filterContext);
+ Result filtersResult = descriptor.Filters.Validate(filterContext, descriptor.FormReport, ref report);
+
+ if (filtersResult.RouteNext)
+ {
+ Result fallbackResult = handlerInstance.FiltersFallback(report, client, cancellationToken).Result;
+ breakRouting = !fallbackResult.RouteNext;
+ return null;
+ }
+ else if (!filtersResult.Positive)
+ {
+ return null;
+ }
}
return new DescribedHandlerInfo(descriptor, this, AwaitingProvider, client, handlerInstance, filterContext, descriptor.DisplayString);
diff --git a/Telegrator/Result.cs b/Telegrator/Result.cs
index 4d025b1..ac745fb 100644
--- a/Telegrator/Result.cs
+++ b/Telegrator/Result.cs
@@ -37,7 +37,6 @@ namespace Telegrator
/// Represents 'success'
///
/// - Inside - let handler's main block be executed
- /// - Inside - let router continue describing
/// - Inside - tells that he can stop describing, as needed handler was found
///
///
@@ -49,7 +48,7 @@ namespace Telegrator
/// Represents 'fault' or 'error'. Use cases:
///
/// - Inside - interupts execution of handler, main block and wont be executed
- /// - Inside - interupts router's describing sequence
+ /// - Inside - interupts 's describing sequence
///
///
///
@@ -59,6 +58,7 @@ namespace Telegrator
///
/// Represents 'continue'. Use cases:
///
+ /// - Inside - let router continue describing
/// - Inside - Tells to continue describing handlers
///
///
diff --git a/Telegrator/Telegrator.csproj b/Telegrator/Telegrator.csproj
index 2ee8b14..7032b0a 100644
--- a/Telegrator/Telegrator.csproj
+++ b/Telegrator/Telegrator.csproj
@@ -17,7 +17,7 @@
True
True
LICENSE
- 1.0.11
+ 1.0.12