diff --git a/Telegrator/Attributes/FilterAnnotation.cs b/Telegrator/Attributes/FilterAnnotation.cs
index 40bd0b5..4a87767 100644
--- a/Telegrator/Attributes/FilterAnnotation.cs
+++ b/Telegrator/Attributes/FilterAnnotation.cs
@@ -9,7 +9,7 @@ namespace Telegrator.Attributes
/// Reactive way to implement a new of type
///
///
- public abstract class FilterAnnotation : UpdateFilterAttribute, IFilter where T : class
+ public abstract class FilterAnnotation : UpdateFilterAttribute, IFilter, INamedFilter where T : class
{
///
public virtual bool IsCollectible { get; } = false;
@@ -17,6 +17,9 @@ namespace Telegrator.Attributes
///
public override UpdateType[] AllowedTypes { get; } = typeof(T).GetAllowedUpdateTypes();
+ ///
+ public string Name => GetType().Name;
+
///
/// Initializes new instance of
///
diff --git a/Telegrator/Handlers/Building/TypesExtensions.cs b/Telegrator/Handlers/Building/TypesExtensions.cs
new file mode 100644
index 0000000..5e6bb5a
--- /dev/null
+++ b/Telegrator/Handlers/Building/TypesExtensions.cs
@@ -0,0 +1,245 @@
+using Telegram.Bot.Types;
+using Telegrator.Annotations.StateKeeping;
+using Telegrator.Filters.Components;
+using Telegrator.Handlers.Building.Components;
+using Telegrator.StateKeeping;
+using Telegrator.StateKeeping.Abstracts;
+using Telegrator.StateKeeping.Components;
+
+namespace Telegrator.Handlers.Building
+{
+ ///
+ /// Extension methods for handler builders.
+ /// Provides convenient methods for creating handlers and setting state keepers.
+ ///
+ public static partial class HandlerBuilderExtensions
+ {
+ ///
+ public static TBuilder SetUpdateValidating(this TBuilder handlerBuilder, UpdateValidateAction updateValidateAction)
+ where TBuilder : HandlerBuilderBase
+ {
+ handlerBuilder.SetUpdateValidating(updateValidateAction);
+ return handlerBuilder;
+ }
+
+ ///
+ public static TBuilder SetConcurreny(this TBuilder handlerBuilder, int concurrency)
+ where TBuilder : HandlerBuilderBase
+ {
+ handlerBuilder.SetConcurreny(concurrency);
+ return handlerBuilder;
+ }
+
+ ///
+ public static TBuilder SetPriority(this TBuilder handlerBuilder, int priority)
+ where TBuilder : HandlerBuilderBase
+ {
+ handlerBuilder.SetPriority(priority);
+ return handlerBuilder;
+ }
+
+ ///
+ public static TBuilder SetIndexer(this TBuilder handlerBuilder, int concurrency, int priority)
+ where TBuilder : HandlerBuilderBase
+ {
+ handlerBuilder.SetIndexer(concurrency, priority);
+ return handlerBuilder;
+ }
+
+ ///
+ public static TBuilder AddFilter(this TBuilder handlerBuilder, IFilter filter)
+ where TBuilder : HandlerBuilderBase
+ {
+ handlerBuilder.AddFilter(filter);
+ return handlerBuilder;
+ }
+
+ ///
+ public static TBuilder AddFilters(this TBuilder handlerBuilder, params IFilter[] filters)
+ where TBuilder : HandlerBuilderBase
+ {
+ handlerBuilder.AddFilters(filters);
+ return handlerBuilder;
+ }
+
+ ///
+ public static TBuilder SetStateKeeper(this TBuilder handlerBuilder, TState myState, IStateKeyResolver keyResolver)
+ where TBuilder : HandlerBuilderBase
+ where TKey : notnull
+ where TState : IEquatable
+ where TKeeper : StateKeeperBase, new()
+ {
+ handlerBuilder.SetStateKeeper(myState, keyResolver);
+ return handlerBuilder;
+ }
+
+ ///
+ public static TBuilder SetStateKeeper(this TBuilder handlerBuilder, SpecialState specialState, IStateKeyResolver keyResolver)
+ where TBuilder : HandlerBuilderBase
+ where TKey : notnull
+ where TState : IEquatable
+ where TKeeper : StateKeeperBase, new()
+ {
+ handlerBuilder.SetStateKeeper(specialState, keyResolver);
+ return handlerBuilder;
+ }
+
+ ///
+ /// Adds a targeted filter for a specific filter target type.
+ ///
+ ///
+ /// The type of the filter target.
+ ///
+ /// Function to get the filter target from an update.
+ /// The filter to add.
+ /// The builder instance.
+ public static TBuilder AddTargetedFilter(this TBuilder handlerBuilder, Func getFilterringTarget, IFilter filter)
+ where TBuilder : HandlerBuilderBase
+ where TFilterTarget : class
+ {
+ handlerBuilder.AddTargetedFilter(getFilterringTarget, filter);
+ return handlerBuilder;
+ }
+
+ ///
+ /// Adds multiple targeted filters for a specific filter target type.
+ ///
+ ///
+ /// The type of the filter target.
+ ///
+ /// Function to get the filter target from an update.
+ /// The filters to add.
+ /// The builder instance.
+ public static TBuilder AddTargetedFilters(this TBuilder handlerBuilder, Func getFilterringTarget, params IFilter[] filters)
+ where TBuilder : HandlerBuilderBase
+ where TFilterTarget : class
+ {
+ handlerBuilder.AddTargetedFilters(getFilterringTarget, filters);
+ return handlerBuilder;
+ }
+
+ ///
+ /// Sets a numeric state keeper with a custom key resolver.
+ ///
+ /// The type of the handler builder.
+ /// The handler builder.
+ /// The numeric state value.
+ /// The key resolver for the state.
+ /// The handler builder for method chaining.
+ public static TBuilder SetNumericState(this TBuilder handlerBuilder, int myState, IStateKeyResolver keyResolver)
+ where TBuilder : HandlerBuilderBase
+ {
+ handlerBuilder.SetStateKeeper(myState, keyResolver);
+ return handlerBuilder;
+ }
+
+ ///
+ /// Sets a numeric state keeper with a special state and custom key resolver.
+ ///
+ /// The type of the handler builder.
+ /// The handler builder.
+ /// The special state value.
+ /// The key resolver for the state.
+ /// The handler builder for method chaining.
+ public static TBuilder SetNumericState(this TBuilder handlerBuilder, SpecialState specialState, IStateKeyResolver keyResolver)
+ where TBuilder : HandlerBuilderBase
+ {
+ handlerBuilder.SetStateKeeper(specialState, keyResolver);
+ return handlerBuilder;
+ }
+
+ ///
+ /// Sets a numeric state keeper with the default sender ID resolver.
+ ///
+ /// The type of the handler builder.
+ /// The handler builder.
+ /// The numeric state value.
+ /// The handler builder for method chaining.
+ public static TBuilder SetNumericState(this TBuilder handlerBuilder, int myState)
+ where TBuilder : HandlerBuilderBase
+ {
+ handlerBuilder.SetStateKeeper(myState, new SenderIdResolver());
+ return handlerBuilder;
+ }
+
+ ///
+ /// Sets a numeric state keeper with a special state and the default sender ID resolver.
+ ///
+ /// The type of the handler builder.
+ /// The handler builder.
+ /// The special state value.
+ /// The handler builder for method chaining.
+ public static TBuilder SetNumericState(this TBuilder handlerBuilder, SpecialState specialState)
+ where TBuilder : HandlerBuilderBase
+ {
+ handlerBuilder.SetStateKeeper(specialState, new SenderIdResolver());
+ return handlerBuilder;
+ }
+
+ ///
+ /// Sets an enum state keeper with a custom key resolver.
+ ///
+ /// The type of the handler builder.
+ /// The type of the enum state.
+ /// The handler builder.
+ /// The enum state value.
+ /// The key resolver for the state.
+ /// The handler builder for method chaining.
+ public static TBuilder SetEnumState(this TBuilder handlerBuilder, TEnum myState, IStateKeyResolver keyResolver)
+ where TBuilder : HandlerBuilderBase
+ where TEnum : Enum, IEquatable
+ {
+ handlerBuilder.SetStateKeeper>(myState, keyResolver);
+ return handlerBuilder;
+ }
+
+ ///
+ /// Sets an enum state keeper with a special state and custom key resolver.
+ ///
+ /// The type of the handler builder.
+ /// The type of the enum state.
+ /// The handler builder.
+ /// The special state value.
+ /// The key resolver for the state.
+ /// The handler builder for method chaining.
+ public static TBuilder SetEnumState(this TBuilder handlerBuilder, SpecialState specialState, IStateKeyResolver keyResolver)
+ where TBuilder : HandlerBuilderBase
+ where TEnum : Enum, IEquatable
+ {
+ handlerBuilder.SetStateKeeper>(specialState, keyResolver);
+ return handlerBuilder;
+ }
+
+ ///
+ /// Sets an enum state keeper with the default sender ID resolver.
+ ///
+ /// The type of the handler builder.
+ /// The type of the enum state.
+ /// The handler builder.
+ /// The enum state value.
+ /// The handler builder for method chaining.
+ public static TBuilder SetEnumState(this TBuilder handlerBuilder, TEnum myState)
+ where TBuilder : HandlerBuilderBase
+ where TEnum : Enum, IEquatable
+ {
+ handlerBuilder.SetStateKeeper>(myState, new SenderIdResolver());
+ return handlerBuilder;
+ }
+
+ ///
+ /// Sets an enum state keeper with a special state and the default sender ID resolver.
+ ///
+ /// The type of the handler builder.
+ /// The type of the enum state.
+ /// The handler builder.
+ /// The special state value.
+ /// The handler builder for method chaining.
+ public static TBuilder SetEnumState(this TBuilder handlerBuilder, SpecialState specialState)
+ where TBuilder : HandlerBuilderBase
+ where TEnum : Enum, IEquatable
+ {
+ handlerBuilder.SetStateKeeper>(specialState, new SenderIdResolver());
+ return handlerBuilder;
+ }
+ }
+}
diff --git a/Telegrator/Handlers/Components/FiltersFallbackReport.cs b/Telegrator/Handlers/Components/FiltersFallbackReport.cs
deleted file mode 100644
index 9a0ab6b..0000000
--- a/Telegrator/Handlers/Components/FiltersFallbackReport.cs
+++ /dev/null
@@ -1,164 +0,0 @@
-using Telegram.Bot.Types;
-using Telegrator.Attributes.Components;
-using Telegrator.Filters.Components;
-using Telegrator.MadiatorCore.Descriptors;
-
-namespace Telegrator.Handlers.Components
-{
- ///
- /// Represents a report of filter fallback information for debugging and error handling.
- /// Contains detailed information about which filters failed and why during handler execution.
- ///
- /// The handler descriptor that generated this report.
- /// The filter execution context.
- public class FiltersFallbackReport(HandlerDescriptor descriptor, FilterExecutionContext context)
- {
- ///
- /// Gets the handler descriptor associated with this fallback report.
- ///
- public HandlerDescriptor Descriptor { get; } = descriptor;
-
- ///
- /// Gets the filter execution context that generated this report.
- ///
- public FilterExecutionContext Context { get; } = context;
-
- ///
- /// Gets or sets the fallback information for the update validator filter.
- ///
- public FilterFallbackInfo? UpdateValidator { get; set; }
-
- ///
- /// Gets or sets the fallback information for the state keeper validator filter.
- ///
- public FilterFallbackInfo? StateKeeperValidator { get; set; }
-
- ///
- /// Gets the list of fallback information for update filters that failed.
- ///
- public List UpdateFilters { get; } = [];
-
- ///
- /// Checks if the failure is due to a specific filter.
- ///
- ///
- ///
- ///
- public bool Only(string name, int index = 0)
- {
- FilterFallbackInfo? info = UpdateFilters.SingleSafe(info => info.Failed);
- if (info != null && info.Name != name)
- return false;
-
- FilterFallbackInfo? target = UpdateFilters.ElementAtOrDefault(index);
- return ReferenceEquals(target, info);
- }
-
- ///
- /// Checks if the failure is due to a specific filter.
- ///
- ///
- ///
- public bool Only(string[] names)
- {
- return UpdateFilters
- .Where(info => info.Failed)
- .Select(info => info.Name)
- .SequenceEqual(names);
- }
-
- ///
- /// Checks if the failure is due to all filters except one.
- ///
- ///
- ///
- ///
- public bool Except(string name, int index = 0)
- {
- FilterFallbackInfo? info = UpdateFilters.SingleSafe(info => !info.Failed);
- if (info != null && info.Name != name)
- return false;
-
- FilterFallbackInfo? target = UpdateFilters.ElementAtOrDefault(index);
- return ReferenceEquals(target, info);
- }
-
- ///
- /// Checks if the failure is due to all filters except one.
- ///
- ///
- ///
- public bool Except(string[] names)
- {
- return UpdateFilters
- .Where(info => !info.Failed)
- .Select(info => info.Name)
- .SequenceEqual(names);
- }
-
- ///
- /// Checks if the failure is due to aall attribute type, excluding one.
- ///
- /// The attribute type to check for.
- /// The index of the filter to check (default: 0).
- /// True if the failure is exclusively due to the specified attribute type; otherwise, false.
- public bool ExceptAttribute(int index = 0) where T : UpdateFilterAttributeBase
- => Except(nameof(T), index);
-
- ///
- /// Checks if the failure is due to a specific attribute type, excluding other failures.
- ///
- /// The attribute type to check for.
- /// The index of the filter to check (default: 0).
- /// True if the failure is exclusively due to the specified attribute type; otherwise, false.
- public bool OnlyAttribute(int index = 0) where T : UpdateFilterAttributeBase
- => Only(nameof(T), index);
- }
-
- ///
- /// Contains information about a filter that failed during execution.
- /// Provides details about the filter, its failure status, and any associated exception.
- ///
- /// The name of the filter.
- /// The filter instance that failed.
- /// Whether the filter failed.
- /// The exception that occurred during filter execution, if any.
- public class FilterFallbackInfo(string name, IFilter filter, bool failed, Exception? exception)
- {
- ///
- /// Gets the name of the filter.
- ///
- public string Name { get; } = name;
-
- ///
- /// Gets the filter instance that failed.
- ///
- public IFilter Filter { get; } = filter;
-
- ///
- /// Gets a value indicating whether the filter failed.
- ///
- public bool Failed { get; } = failed;
-
- ///
- /// Gets the exception that occurred during filter execution, if any.
- ///
- public Exception? Exception { get; } = exception;
- }
-
- ///
- /// Specifies the reason for a filter fallback.
- ///
- public enum FallbackReason
- {
- ///
- /// The filter target was null.
- ///
- NullTarget,
-
- ///
- /// The filter failed to pass.
- ///
- FailedFilter
- }
-}
diff --git a/Telegrator/Handlers/Components/UpdateHandlerBase.cs b/Telegrator/Handlers/Components/UpdateHandlerBase.cs
index e3970de..9cb79b9 100644
--- a/Telegrator/Handlers/Components/UpdateHandlerBase.cs
+++ b/Telegrator/Handlers/Components/UpdateHandlerBase.cs
@@ -4,6 +4,7 @@ using Telegram.Bot.Polling;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using Telegrator.Filters.Components;
+using Telegrator.Handlers.Diagnostics;
using Telegrator.MadiatorCore.Descriptors;
namespace Telegrator.Handlers.Components
diff --git a/Telegrator/Handlers/Diagnostics/FilterFallbackInfo.cs b/Telegrator/Handlers/Diagnostics/FilterFallbackInfo.cs
new file mode 100644
index 0000000..73b874d
--- /dev/null
+++ b/Telegrator/Handlers/Diagnostics/FilterFallbackInfo.cs
@@ -0,0 +1,36 @@
+using Telegram.Bot.Types;
+using Telegrator.Filters.Components;
+
+namespace Telegrator.Handlers.Diagnostics
+{
+ ///
+ /// Contains information about a filter that failed during execution.
+ /// Provides details about the filter, its failure status, and any associated exception.
+ ///
+ /// The name of the filter.
+ /// The filter instance that failed.
+ /// Whether the filter failed.
+ /// The exception that occurred during filter execution, if any.
+ public class FilterFallbackInfo(string name, IFilter filter, bool failed, Exception? exception)
+ {
+ ///
+ /// Gets the name of the filter.
+ ///
+ public string Name { get; } = name;
+
+ ///
+ /// Gets the filter instance that failed.
+ ///
+ public IFilter Filter { get; } = filter;
+
+ ///
+ /// Gets a value indicating whether the filter failed.
+ ///
+ public bool Failed { get; } = failed;
+
+ ///
+ /// Gets the exception that occurred during filter execution, if any.
+ ///
+ public Exception? Exception { get; } = exception;
+ }
+}
diff --git a/Telegrator/Handlers/Diagnostics/FiltersFallbackReport.cs b/Telegrator/Handlers/Diagnostics/FiltersFallbackReport.cs
new file mode 100644
index 0000000..8a4e3c1
--- /dev/null
+++ b/Telegrator/Handlers/Diagnostics/FiltersFallbackReport.cs
@@ -0,0 +1,65 @@
+using Telegram.Bot.Types;
+using Telegrator.Filters.Components;
+using Telegrator.MadiatorCore.Descriptors;
+
+namespace Telegrator.Handlers.Diagnostics
+{
+ ///
+ /// Represents a report of filter fallback information for debugging and error handling.
+ /// Contains detailed information about which filters failed and why during handler execution.
+ ///
+ /// The handler descriptor that generated this report.
+ /// The filter execution context.
+ public class FiltersFallbackReport(HandlerDescriptor descriptor, FilterExecutionContext context)
+ {
+ ///
+ /// Gets the handler descriptor associated with this fallback report.
+ ///
+ public HandlerDescriptor Descriptor { get; } = descriptor;
+
+ ///
+ /// Gets the filter execution context that generated this report.
+ ///
+ public FilterExecutionContext Context { get; } = context;
+
+ ///
+ /// Gets or sets the fallback information for the update validator filter.
+ ///
+ public FilterFallbackInfo? UpdateValidator { get; set; }
+
+ ///
+ /// Gets or sets the fallback information for the state keeper validator filter.
+ ///
+ public FilterFallbackInfo? StateKeeperValidator { get; set; }
+
+ ///
+ /// Gets the list of fallback information for update filters that failed.
+ ///
+ public List UpdateFilters { get; } = [];
+
+ ///
+ /// Checks filter fail status by name
+ ///
+ ///
+ ///
+ public bool this[string name] => UpdateFilters.FirstOrDefault(f => f.Name == name)?.Failed ?? false;
+
+ ///
+ /// Creates new instance of with default filter state as FAILED.
+ ///
+ ///
+ public ReportInspector AllFailed()
+ {
+ return new ReportInspector(this, false);
+ }
+
+ ///
+ /// Creates new instance of with default filter state as PASSED.
+ ///
+ ///
+ public ReportInspector AllPassed()
+ {
+ return new ReportInspector(this, true);
+ }
+ }
+}
diff --git a/Telegrator/Handlers/Diagnostics/ReportInspector.cs b/Telegrator/Handlers/Diagnostics/ReportInspector.cs
new file mode 100644
index 0000000..afcc8cc
--- /dev/null
+++ b/Telegrator/Handlers/Diagnostics/ReportInspector.cs
@@ -0,0 +1,73 @@
+namespace Telegrator.Handlers.Diagnostics
+{
+ ///
+ /// A class builder for pattern checking of
+ ///
+ ///
+ ///
+ public sealed class ReportInspector(FiltersFallbackReport report, bool defaulState)
+ {
+ private readonly FiltersFallbackReport _report = report;
+ private readonly bool _defaulState = defaulState;
+
+ private readonly List _ignore = [];
+ private readonly List _excepts = [];
+
+ ///
+ /// Adds a filter to the exclusion list.
+ /// Excluded filters are compared oppositely with the default state.
+ ///
+ ///
+ ///
+ public ReportInspector Except(string name)
+ {
+ _excepts.Add(name);
+ return this;
+ }
+
+ ///
+ /// Adds a filter to the ignore list.
+ /// Ignored filters are not checked and do not affect the final result.
+ ///
+ ///
+ ///
+ public ReportInspector Whenever(string name)
+ {
+ _ignore.Add(name);
+ return this;
+ }
+
+ ///
+ /// It goes through the report and compares it with the specified filter pattern.
+ ///
+ ///
+ public bool Match()
+ {
+ foreach (FilterFallbackInfo info in _report.UpdateFilters)
+ {
+ if (_ignore.Contains(info.Name))
+ continue;
+
+ if (_excepts.Contains(info.Name))
+ {
+ if (_defaulState == true && !info.Failed)
+ return false;
+
+ if (_defaulState == false && info.Failed)
+ return false;
+ }
+
+ if (!info.Failed != _defaulState)
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Casts inspector by executing
+ ///
+ ///
+ public static implicit operator bool(ReportInspector inspector) => inspector.Match();
+ }
+}
diff --git a/Telegrator/Handlers/Diagnostics/TypesExtensions.cs b/Telegrator/Handlers/Diagnostics/TypesExtensions.cs
new file mode 100644
index 0000000..eb6ee0e
--- /dev/null
+++ b/Telegrator/Handlers/Diagnostics/TypesExtensions.cs
@@ -0,0 +1,18 @@
+using Telegrator.Attributes.Components;
+
+namespace Telegrator.Handlers.Diagnostics
+{
+ ///
+ /// Provides extension methods for
+ ///
+ public static partial class ReportInspectorExtensions
+ {
+ ///
+ public static ReportInspector Whenever(this ReportInspector inspector) where TAttribute : UpdateFilterAttributeBase
+ => inspector.Whenever(nameof(TAttribute));
+
+ ///
+ public static ReportInspector Except(this ReportInspector inspector) where TAttribute : UpdateFilterAttributeBase
+ => inspector.Except(nameof(TAttribute));
+ }
+}
diff --git a/Telegrator/Handlers/TypesExtensions.cs b/Telegrator/Handlers/TypesExtensions.cs
new file mode 100644
index 0000000..9d1ba9f
--- /dev/null
+++ b/Telegrator/Handlers/TypesExtensions.cs
@@ -0,0 +1,284 @@
+using Telegram.Bot;
+using Telegram.Bot.Types;
+using Telegram.Bot.Types.Enums;
+using Telegram.Bot.Types.InlineQueryResults;
+using Telegram.Bot.Types.ReplyMarkups;
+
+namespace Telegrator.Handlers
+{
+ ///
+ /// Provides usefull helper methods for abstract handler containers
+ ///
+ public static class AbstractHandlerContainerExtensions
+ {
+ ///
+ /// Changes bot's reaction to message
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task React(
+ this IAbstractHandlerContainer container,
+ ReactionType reaction,
+ bool isBig = false,
+ CancellationToken cancellationToken = default)
+ => await container.Client.SetMessageReaction(
+ container.ActualUpdate.Chat,
+ container.ActualUpdate.Id,
+ [reaction], isBig, cancellationToken);
+
+ ///
+ /// Changes bot's reaction to message
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task React(
+ this IAbstractHandlerContainer container,
+ IEnumerable reactions,
+ bool isBig = false,
+ CancellationToken cancellationToken = default)
+ => await container.Client.SetMessageReaction(
+ container.ActualUpdate.Chat,
+ container.ActualUpdate.Id,
+ reactions, isBig, cancellationToken);
+
+ ///
+ /// Sends a reply message to the current message.
+ ///
+ ///
+ /// The text of the message to send.
+ /// The parse mode for the message text.
+ /// The reply markup for the message.
+ /// Options for link preview generation.
+ /// The thread ID for forum topics.
+ /// The message entities to include.
+ /// Whether to disable notification for the message.
+ /// Whether to protect the message content.
+ /// The message effect ID.
+ /// The business connection ID.
+ /// Whether to allow paid broadcast.
+ ///
+ ///
+ /// The cancellation token.
+ /// The sent message.
+ public static async Task Reply(
+ this IAbstractHandlerContainer container,
+ string text,
+ ParseMode parseMode = ParseMode.None,
+ ReplyMarkup? replyMarkup = null,
+ LinkPreviewOptions? linkPreviewOptions = null,
+ int? messageThreadId = null,
+ IEnumerable? entities = null,
+ bool disableNotification = false,
+ bool protectContent = false,
+ string? messageEffectId = null,
+ string? businessConnectionId = null,
+ bool allowPaidBroadcast = false,
+ int? directMessageTopicId = null,
+ SuggestedPostParameters? suggestedPostParameters = null,
+ CancellationToken cancellationToken = default)
+ => await container.Client.SendMessage(
+ container.ActualUpdate.Chat, text, parseMode, container.ActualUpdate,
+ replyMarkup, linkPreviewOptions,
+ messageThreadId, entities,
+ disableNotification, protectContent,
+ messageEffectId, businessConnectionId,
+ allowPaidBroadcast, directMessageTopicId,
+ suggestedPostParameters, cancellationToken);
+
+ ///
+ /// Sends a response message to the current chat.
+ ///
+ ///
+ /// The text of the message to send.
+ /// The parse mode for the message text.
+ /// The reply parameters for the message.
+ /// The reply markup for the message.
+ /// Options for link preview generation.
+ /// The thread ID for forum topics.
+ /// The message entities to include.
+ /// Whether to disable notification for the message.
+ /// Whether to protect the message content.
+ /// The message effect ID.
+ /// The business connection ID.
+ /// Whether to allow paid broadcast.
+ ///
+ ///
+ /// The cancellation token.
+ /// The sent message.
+ public static async Task Responce(
+ this IAbstractHandlerContainer container,
+ string text,
+ ParseMode parseMode = ParseMode.None,
+ ReplyParameters? replyParameters = null,
+ ReplyMarkup? replyMarkup = null,
+ LinkPreviewOptions? linkPreviewOptions = null,
+ int? messageThreadId = null,
+ IEnumerable? entities = null,
+ bool disableNotification = false,
+ bool protectContent = false,
+ string? messageEffectId = null,
+ string? businessConnectionId = null,
+ bool allowPaidBroadcast = false,
+ int? directMessageTopicId = null,
+ SuggestedPostParameters? suggestedPostParameters = null,
+ CancellationToken cancellationToken = default)
+ => await container.Client.SendMessage(
+ container.ActualUpdate.Chat, text, parseMode, replyParameters,
+ replyMarkup, linkPreviewOptions,
+ messageThreadId, entities,
+ disableNotification, protectContent,
+ messageEffectId, businessConnectionId,
+ allowPaidBroadcast, directMessageTopicId,
+ suggestedPostParameters, cancellationToken);
+
+ ///
+ /// Responnces to message that this CallbackQuery was originated from
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task Responce(
+ this IAbstractHandlerContainer container,
+ string text,
+ ParseMode parseMode = ParseMode.None,
+ ReplyParameters? replyParameters = null,
+ ReplyMarkup? replyMarkup = null,
+ LinkPreviewOptions? linkPreviewOptions = null,
+ int? messageThreadId = null,
+ IEnumerable? entities = null,
+ bool disableNotification = false,
+ bool protectContent = false,
+ string? messageEffectId = null,
+ string? businessConnectionId = null,
+ bool allowPaidBroadcast = false,
+ int? directMessageTopicId = null,
+ SuggestedPostParameters? suggestedPostParameters = null,
+ CancellationToken cancellationToken = default)
+ {
+ CallbackQuery query = container.ActualUpdate;
+ if (query.Message == null)
+ throw new Exception("Callback origin message not found!");
+
+ return await container.Client.SendMessage(
+ query.Message.Chat, text, parseMode, replyParameters,
+ replyMarkup, linkPreviewOptions,
+ messageThreadId, entities,
+ disableNotification, protectContent,
+ messageEffectId, businessConnectionId,
+ allowPaidBroadcast, directMessageTopicId,
+ suggestedPostParameters, cancellationToken);
+ }
+
+ ///
+ /// Edits message text that this CallbackQuery was originated from
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task EditMessage(
+ this IAbstractHandlerContainer container,
+ string text,
+ ParseMode parseMode = ParseMode.None,
+ InlineKeyboardMarkup? replyMarkup = null,
+ IEnumerable? entities = null,
+ LinkPreviewOptions? linkPreviewOptions = null,
+ CancellationToken cancellationToken = default)
+ {
+ CallbackQuery query = container.ActualUpdate;
+ if (query.Message == null)
+ throw new Exception("Callback origin message not found!");
+
+ return await container.Client.EditMessageText(
+ query.Message.Chat,
+ query.Message.MessageId,
+ text: text,
+ parseMode: parseMode,
+ replyMarkup: replyMarkup,
+ entities: entities,
+ linkPreviewOptions: linkPreviewOptions,
+ cancellationToken: cancellationToken);
+ }
+
+ ///
+ /// Use this method to send answers to callback queries sent from inline keyboards.
+ /// The answer will be displayed to the user as a notification at the top of the chat screen or as an alert
+ ///
+ ///
+ /// Alternatively, the user can be redirected to the specified Game URL.
+ /// For this option to work, you must first create a game for your bot via @BotFather and accept the terms.
+ /// Otherwise, you may use links like t.me/your_bot?start=XXXX that open your bot with a parameter.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task AnswerCallbackQuery(
+ this IAbstractHandlerContainer container,
+ string? text = null,
+ bool showAlert = false,
+ string? url = null,
+ int cacheTime = 0,
+ CancellationToken cancellationToken = default)
+ => await container.Client.AnswerCallbackQuery(
+ callbackQueryId: container.ActualUpdate.Id,
+ text: text,
+ showAlert: showAlert,
+ url: url,
+ cacheTime: cacheTime,
+ cancellationToken: cancellationToken);
+
+ ///
+ /// Answers inline query
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task AnswerInlineQuery(
+ this IAbstractHandlerContainer container,
+ IEnumerable results,
+ int? cacheTime = null,
+ bool isPersonal = false,
+ string? nextOffset = null,
+ InlineQueryResultsButton? button = null,
+ CancellationToken cancellationToken = default)
+ {
+ string id = container.ActualUpdate.Id;
+ await container.Client.AnswerInlineQuery(id, results.Take(50), cacheTime, isPersonal, nextOffset, button, cancellationToken);
+ }
+ }
+}
diff --git a/Telegrator/MadiatorCore/Descriptors/DescriptorFiltersSet.cs b/Telegrator/MadiatorCore/Descriptors/DescriptorFiltersSet.cs
index ff9cffe..9da76af 100644
--- a/Telegrator/MadiatorCore/Descriptors/DescriptorFiltersSet.cs
+++ b/Telegrator/MadiatorCore/Descriptors/DescriptorFiltersSet.cs
@@ -1,6 +1,6 @@
using Telegram.Bot.Types;
using Telegrator.Filters.Components;
-using Telegrator.Handlers.Components;
+using Telegrator.Handlers.Diagnostics;
using Telegrator.Logging;
namespace Telegrator.MadiatorCore.Descriptors
diff --git a/Telegrator/Polling/UpdateRouter.cs b/Telegrator/Polling/UpdateRouter.cs
index e6088a6..5091f0e 100644
--- a/Telegrator/Polling/UpdateRouter.cs
+++ b/Telegrator/Polling/UpdateRouter.cs
@@ -6,6 +6,7 @@ using Telegram.Bot.Types.Enums;
using Telegrator.Configuration;
using Telegrator.Filters.Components;
using Telegrator.Handlers.Components;
+using Telegrator.Handlers.Diagnostics;
using Telegrator.Logging;
using Telegrator.MadiatorCore;
using Telegrator.MadiatorCore.Descriptors;
diff --git a/Telegrator/Result.cs b/Telegrator/Result.cs
index 98d9be1..86846b0 100644
--- a/Telegrator/Result.cs
+++ b/Telegrator/Result.cs
@@ -3,6 +3,7 @@ using Telegrator.Aspects;
using Telegrator.Handlers.Components;
using Telegrator.Filters.Components;
using Telegrator.MadiatorCore;
+using Telegrator.Handlers.Diagnostics;
namespace Telegrator
{
diff --git a/Telegrator/SimpleTypesExtensions.cs b/Telegrator/SimpleTypesExtensions.cs
new file mode 100644
index 0000000..06374c9
--- /dev/null
+++ b/Telegrator/SimpleTypesExtensions.cs
@@ -0,0 +1,347 @@
+using System.Collections.ObjectModel;
+using System.Reflection;
+using Telegrator.Filters.Components;
+using Telegrator.Handlers.Components;
+using Telegrator.Providers;
+
+namespace Telegrator
+{
+ ///
+ /// Provides extension methods for working with collections.
+ ///
+ public static partial class ColletionsExtensions
+ {
+ ///
+ /// Creates a from an
+ /// according to a specified key selector function.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static ReadOnlyDictionary ToReadOnlyDictionary(this IEnumerable source, Func keySelector) where TKey : notnull
+ {
+ Dictionary dictionary = source.ToDictionary(keySelector);
+ return new ReadOnlyDictionary(dictionary);
+ }
+
+ ///
+ /// Enumerates objects in a and executes an on each one
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IEnumerable ForEach(this IEnumerable source, Action action)
+ {
+ foreach (TValue value in source)
+ action.Invoke(value);
+
+ return source;
+ }
+
+ ///
+ /// Sets the value of a key in a dictionary, or if the key does not exist, adds it
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static void Set(this IDictionary source, TKey key, TValue value)
+ {
+ if (source.ContainsKey(key))
+ source[key] = value;
+ else
+ source.Add(key, value);
+ }
+
+ ///
+ /// Sets the value of a key in a dictionary, or if the key does not exist, adds its default value.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static void Set(this IDictionary source, TKey key, TValue value, TValue defaultValue)
+ {
+ if (source.ContainsKey(key))
+ source[key] = value;
+ else
+ source.Add(key, defaultValue);
+ }
+
+ ///
+ /// Return the random object from
+ ///
+ ///
+ ///
+ ///
+ public static TSource Random(this IEnumerable source)
+ => source.Random(new Random());
+
+ ///
+ /// Return the random object from
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static TSource Random(this IEnumerable source, Random random)
+ => source.ElementAt(random.Next(0, source.Count() - 1));
+
+ ///
+ /// Adds a range of elements to collection if they dont already exist using default equality comparer
+ ///
+ ///
+ ///
+ ///
+ public static void UnionAdd(this IList list, params IEnumerable elements)
+ {
+ foreach (TSource item in elements)
+ {
+ if (!list.Contains(item, EqualityComparer.Default))
+ list.Add(item);
+ }
+ }
+
+ ///
+ /// Return index of first element that satisfies the condition
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int IndexOf(this IEnumerable source, Func predicate)
+ {
+ int index = 0;
+ foreach (T item in source)
+ {
+ if (predicate.Invoke(item))
+ return index;
+
+ index++;
+ }
+
+ return -1;
+ }
+
+ ///
+ /// Returns an enumerable that repeats the item multiple times.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IEnumerable Repeat(this T item, int times)
+ => Enumerable.Range(0, times).Select(_ => item);
+
+ ///
+ /// Returns the only element of a sequence, or a default value if the sequence is empty.
+ /// This method returns default if there is more than one element in the sequence.
+ ///
+ ///
+ ///
+ ///
+ public static T? SingleSafe(this IEnumerable source)
+ => source.Count() == 1 ? source.ElementAt(0) : default;
+
+ ///
+ /// Returns the only element of a sequence that satisfies a specified condition or a default value if no such element exists.
+ /// This method return default if more than one element satisfies the condition.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static T? SingleSafe(this IEnumerable source, Func predicate)
+ {
+ source = source.Where(predicate);
+ return source.Count() == 1 ? source.ElementAt(0) : default;
+ }
+ }
+
+ ///
+ /// Provides extension methods for reflection and type inspection.
+ ///
+ public static partial class ReflectionExtensions
+ {
+ ///
+ /// Checks if a type implements the interface.
+ ///
+ /// The type to check.
+ /// True if the type implements ICustomDescriptorsProvider; otherwise, false.
+ public static bool IsCustomDescriptorsProvider(this Type type)
+ => type.GetInterface(nameof(ICustomDescriptorsProvider)) != null;
+
+ ///
+ /// Checks if is a
+ ///
+ ///
+ ///
+ public static bool IsFilterType(this Type type)
+ => type.IsAssignableToGenericType(typeof(IFilter<>));
+
+ ///
+ /// Checks if is a descendant of class
+ ///
+ ///
+ ///
+ public static bool IsHandlerAbstract(this Type type)
+ => type.IsAbstract && typeof(UpdateHandlerBase).IsAssignableFrom(type);
+
+ ///
+ /// Checks if is an implementation of class or its descendants
+ ///
+ ///
+ ///
+ public static bool IsHandlerRealization(this Type type)
+ => !type.IsAbstract && type != typeof(UpdateHandlerBase) && typeof(UpdateHandlerBase).IsAssignableFrom(type);
+
+ ///
+ /// Checks if has a parameterless constructor
+ ///
+ ///
+ ///
+ public static bool HasParameterlessCtor(this Type type)
+ => type.GetConstructors().Any(ctor => ctor.GetParameters().Length == 0);
+
+ ///
+ /// Checks is has public properties
+ ///
+ ///
+ ///
+ public static bool HasPublicProperties(this Type type)
+ => type.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(prop => prop.Name != "IsCollectible").Any();
+
+ ///
+ /// Determines whether an instance of a specified type can be assigned to an instance of the current type
+ ///
+ ///
+ ///
+ ///
+ public static bool IsAssignableToGenericType(this Type givenType, Type genericType)
+ {
+ if (givenType.GetInterfaces().Any(inter => inter.IsGenericType && inter.GetGenericTypeDefinition() == genericType))
+ return true;
+
+ if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
+ return true;
+
+ if (givenType.BaseType == null)
+ return false;
+
+ return givenType.BaseType.IsAssignableToGenericType(genericType);
+ }
+ }
+
+ ///
+ /// Provides extension methods for string manipulation.
+ ///
+ public static partial class StringExtensions
+ {
+ ///
+ /// Slices a string into a array of substrings of fixed
+ ///
+ ///
+ ///
+ ///
+ public static IEnumerable SliceBy(this string source, int length)
+ {
+ for (int start = 0; start < source.Length; start += length + 1)
+ {
+ int tillEnd = source.Length - start;
+ int toSlice = tillEnd < length + 1 ? tillEnd : length + 1;
+
+ ReadOnlySpan chunk = source.AsSpan().Slice(start, toSlice);
+ yield return chunk.ToString();
+ }
+ }
+
+ ///
+ /// Return new string with first found letter set to upper case
+ ///
+ ///
+ ///
+ public static string FirstLetterToUpper(this string target)
+ {
+ char[] chars = target.ToCharArray();
+ int index = chars.IndexOf(char.IsLetter);
+ chars[index] = char.ToUpper(chars[index]);
+ return new string(chars);
+ }
+
+ ///
+ /// Return new string with first found letter set to lower case
+ ///
+ ///
+ ///
+ public static string FirstLetterToLower(this string target)
+ {
+ char[] chars = target.ToCharArray();
+ int index = chars.IndexOf(char.IsLetter);
+ chars[index] = char.ToLower(chars[index]);
+ return new string(chars);
+ }
+
+ ///
+ /// Checks if string contains a 'word'.
+ /// 'Word' must be a separate member of the text, and not have any alphabetic characters next to it.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static bool ContainsWord(this string source, string word, StringComparison comparison = StringComparison.InvariantCulture, int startIndex = 0)
+ {
+ int index = source.IndexOf(word, startIndex, comparison);
+ if (index == -1)
+ return false;
+
+ if (index > 0)
+ {
+ char prev = source[index - 1];
+ if (char.IsLetter(prev))
+ return false;
+ }
+
+ if (index + word.Length < source.Length)
+ {
+ char post = source[index + word.Length];
+ if (char.IsLetter(post))
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ ///
+ /// Contains extension method for number types
+ ///
+ public static class NumbersExtensions
+ {
+ ///
+ /// Check if int value has int flag using bit compare
+ ///
+ ///
+ ///
+ ///
+ public static bool HasFlag(this int value, int flag)
+ => (value & flag) == flag;
+
+ ///
+ /// Check if int value has enum flag using bit compare
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static bool HasFlag(this int value, T flag) where T : Enum
+ => value.HasFlag(Convert.ToInt32(flag));
+ }
+}
diff --git a/Telegrator/TypesExtensions.cs b/Telegrator/TypesExtensions.cs
index 2d91ab6..06c4fa0 100644
--- a/Telegrator/TypesExtensions.cs
+++ b/Telegrator/TypesExtensions.cs
@@ -1,17 +1,9 @@
-using System;
-using System.Collections.ObjectModel;
-using System.Reflection;
-using Telegram.Bot;
+using System.Reflection;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
-using Telegram.Bot.Types.InlineQueryResults;
using Telegram.Bot.Types.Payments;
-using Telegram.Bot.Types.ReplyMarkups;
using Telegrator.Annotations;
-using Telegrator.Annotations.StateKeeping;
using Telegrator.Attributes;
-using Telegrator.Filters.Components;
-using Telegrator.Handlers;
using Telegrator.Handlers.Building;
using Telegrator.Handlers.Building.Components;
using Telegrator.Handlers.Components;
@@ -20,8 +12,6 @@ using Telegrator.MadiatorCore.Descriptors;
using Telegrator.Providers;
using Telegrator.StateKeeping;
using Telegrator.StateKeeping.Abstracts;
-using Telegrator.StateKeeping.Components;
-using static System.Net.Mime.MediaTypeNames;
namespace Telegrator
{
@@ -171,282 +161,6 @@ namespace Telegrator
=> StateKeeperAttribute.Shared;
}
- ///
- /// Provides usefull helper methods for abstract handler containers
- ///
- public static class AbstractHandlerContainerExtensions
- {
- ///
- /// Changes bot's reaction to message
- ///
- ///
- ///
- ///
- ///
- ///
- public static async Task React(
- this IAbstractHandlerContainer container,
- ReactionType reaction,
- bool isBig = false,
- CancellationToken cancellationToken = default)
- => await container.Client.SetMessageReaction(
- container.ActualUpdate.Chat,
- container.ActualUpdate.Id,
- [reaction], isBig, cancellationToken);
-
- ///
- /// Changes bot's reaction to message
- ///
- ///
- ///
- ///
- ///
- ///
- public static async Task React(
- this IAbstractHandlerContainer container,
- IEnumerable reactions,
- bool isBig = false,
- CancellationToken cancellationToken = default)
- => await container.Client.SetMessageReaction(
- container.ActualUpdate.Chat,
- container.ActualUpdate.Id,
- reactions, isBig, cancellationToken);
-
- ///
- /// Sends a reply message to the current message.
- ///
- ///
- /// The text of the message to send.
- /// The parse mode for the message text.
- /// The reply markup for the message.
- /// Options for link preview generation.
- /// The thread ID for forum topics.
- /// The message entities to include.
- /// Whether to disable notification for the message.
- /// Whether to protect the message content.
- /// The message effect ID.
- /// The business connection ID.
- /// Whether to allow paid broadcast.
- ///
- ///
- /// The cancellation token.
- /// The sent message.
- public static async Task Reply(
- this IAbstractHandlerContainer container,
- string text,
- ParseMode parseMode = ParseMode.None,
- ReplyMarkup? replyMarkup = null,
- LinkPreviewOptions? linkPreviewOptions = null,
- int? messageThreadId = null,
- IEnumerable? entities = null,
- bool disableNotification = false,
- bool protectContent = false,
- string? messageEffectId = null,
- string? businessConnectionId = null,
- bool allowPaidBroadcast = false,
- int? directMessageTopicId = null,
- SuggestedPostParameters? suggestedPostParameters = null,
- CancellationToken cancellationToken = default)
- => await container.Client.SendMessage(
- container.ActualUpdate.Chat, text, parseMode, container.ActualUpdate,
- replyMarkup, linkPreviewOptions,
- messageThreadId, entities,
- disableNotification, protectContent,
- messageEffectId, businessConnectionId,
- allowPaidBroadcast, directMessageTopicId,
- suggestedPostParameters, cancellationToken);
-
- ///
- /// Sends a response message to the current chat.
- ///
- ///
- /// The text of the message to send.
- /// The parse mode for the message text.
- /// The reply parameters for the message.
- /// The reply markup for the message.
- /// Options for link preview generation.
- /// The thread ID for forum topics.
- /// The message entities to include.
- /// Whether to disable notification for the message.
- /// Whether to protect the message content.
- /// The message effect ID.
- /// The business connection ID.
- /// Whether to allow paid broadcast.
- ///
- ///
- /// The cancellation token.
- /// The sent message.
- public static async Task Responce(
- this IAbstractHandlerContainer container,
- string text,
- ParseMode parseMode = ParseMode.None,
- ReplyParameters? replyParameters = null,
- ReplyMarkup? replyMarkup = null,
- LinkPreviewOptions? linkPreviewOptions = null,
- int? messageThreadId = null,
- IEnumerable? entities = null,
- bool disableNotification = false,
- bool protectContent = false,
- string? messageEffectId = null,
- string? businessConnectionId = null,
- bool allowPaidBroadcast = false,
- int? directMessageTopicId = null,
- SuggestedPostParameters? suggestedPostParameters = null,
- CancellationToken cancellationToken = default)
- => await container.Client.SendMessage(
- container.ActualUpdate.Chat, text, parseMode, replyParameters,
- replyMarkup, linkPreviewOptions,
- messageThreadId, entities,
- disableNotification, protectContent,
- messageEffectId, businessConnectionId,
- allowPaidBroadcast, directMessageTopicId,
- suggestedPostParameters, cancellationToken);
-
- ///
- /// Responnces to message that this CallbackQuery was originated from
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static async Task Responce(
- this IAbstractHandlerContainer container,
- string text,
- ParseMode parseMode = ParseMode.None,
- ReplyParameters? replyParameters = null,
- ReplyMarkup? replyMarkup = null,
- LinkPreviewOptions? linkPreviewOptions = null,
- int? messageThreadId = null,
- IEnumerable? entities = null,
- bool disableNotification = false,
- bool protectContent = false,
- string? messageEffectId = null,
- string? businessConnectionId = null,
- bool allowPaidBroadcast = false,
- int? directMessageTopicId = null,
- SuggestedPostParameters? suggestedPostParameters = null,
- CancellationToken cancellationToken = default)
- {
- CallbackQuery query = container.ActualUpdate;
- if (query.Message == null)
- throw new Exception("Callback origin message not found!");
-
- return await container.Client.SendMessage(
- query.Message.Chat, text, parseMode, replyParameters,
- replyMarkup, linkPreviewOptions,
- messageThreadId, entities,
- disableNotification, protectContent,
- messageEffectId, businessConnectionId,
- allowPaidBroadcast, directMessageTopicId,
- suggestedPostParameters, cancellationToken);
- }
-
- ///
- /// Edits message text that this CallbackQuery was originated from
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static async Task EditMessage(
- this IAbstractHandlerContainer container,
- string text,
- ParseMode parseMode = ParseMode.None,
- InlineKeyboardMarkup? replyMarkup = null,
- IEnumerable? entities = null,
- LinkPreviewOptions? linkPreviewOptions = null,
- CancellationToken cancellationToken = default)
- {
- CallbackQuery query = container.ActualUpdate;
- if (query.Message == null)
- throw new Exception("Callback origin message not found!");
-
- return await container.Client.EditMessageText(
- query.Message.Chat,
- query.Message.MessageId,
- text: text,
- parseMode: parseMode,
- replyMarkup: replyMarkup,
- entities: entities,
- linkPreviewOptions: linkPreviewOptions,
- cancellationToken: cancellationToken);
- }
-
- ///
- /// Use this method to send answers to callback queries sent from inline keyboards.
- /// The answer will be displayed to the user as a notification at the top of the chat screen or as an alert
- ///
- ///
- /// Alternatively, the user can be redirected to the specified Game URL.
- /// For this option to work, you must first create a game for your bot via @BotFather and accept the terms.
- /// Otherwise, you may use links like t.me/your_bot?start=XXXX that open your bot with a parameter.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static async Task AnswerCallbackQuery(
- this IAbstractHandlerContainer container,
- string? text = null,
- bool showAlert = false,
- string? url = null,
- int cacheTime = 0,
- CancellationToken cancellationToken = default)
- => await container.Client.AnswerCallbackQuery(
- callbackQueryId: container.ActualUpdate.Id,
- text: text,
- showAlert: showAlert,
- url: url,
- cacheTime: cacheTime,
- cancellationToken: cancellationToken);
-
- ///
- /// Answers inline query
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static async Task AnswerInlineQuery(
- this IAbstractHandlerContainer container,
- IEnumerable results,
- int? cacheTime = null,
- bool isPersonal = false,
- string? nextOffset = null,
- InlineQueryResultsButton? button = null,
- CancellationToken cancellationToken = default)
- {
- string id = container.ActualUpdate.Id;
- await container.Client.AnswerInlineQuery(id, results.Take(50), cacheTime, isPersonal, nextOffset, button, cancellationToken);
- }
- }
-
///
/// Extensions methods for Awaiter Handler Builders
///
@@ -673,620 +387,6 @@ namespace Telegrator
}
}
- ///
- /// Extension methods for handler builders.
- /// Provides convenient methods for creating handlers and setting state keepers.
- ///
- public static partial class HandlerBuilderExtensions
- {
- ///
- public static TBuilder SetUpdateValidating(this TBuilder handlerBuilder, UpdateValidateAction updateValidateAction)
- where TBuilder : HandlerBuilderBase
- {
- handlerBuilder.SetUpdateValidating(updateValidateAction);
- return handlerBuilder;
- }
-
- ///
- public static TBuilder SetConcurreny(this TBuilder handlerBuilder, int concurrency)
- where TBuilder : HandlerBuilderBase
- {
- handlerBuilder.SetConcurreny(concurrency);
- return handlerBuilder;
- }
-
- ///
- public static TBuilder SetPriority(this TBuilder handlerBuilder, int priority)
- where TBuilder : HandlerBuilderBase
- {
- handlerBuilder.SetPriority(priority);
- return handlerBuilder;
- }
-
- ///
- public static TBuilder SetIndexer(this TBuilder handlerBuilder, int concurrency, int priority)
- where TBuilder : HandlerBuilderBase
- {
- handlerBuilder.SetIndexer(concurrency, priority);
- return handlerBuilder;
- }
-
- ///
- public static TBuilder AddFilter(this TBuilder handlerBuilder, IFilter filter)
- where TBuilder : HandlerBuilderBase
- {
- handlerBuilder.AddFilter(filter);
- return handlerBuilder;
- }
-
- ///
- public static TBuilder AddFilters(this TBuilder handlerBuilder, params IFilter[] filters)
- where TBuilder : HandlerBuilderBase
- {
- handlerBuilder.AddFilters(filters);
- return handlerBuilder;
- }
-
- ///
- public static TBuilder SetStateKeeper(this TBuilder handlerBuilder, TState myState, IStateKeyResolver keyResolver)
- where TBuilder : HandlerBuilderBase
- where TKey : notnull
- where TState : IEquatable
- where TKeeper : StateKeeperBase, new()
- {
- handlerBuilder.SetStateKeeper(myState, keyResolver);
- return handlerBuilder;
- }
-
- ///
- public static TBuilder SetStateKeeper(this TBuilder handlerBuilder, SpecialState specialState, IStateKeyResolver keyResolver)
- where TBuilder : HandlerBuilderBase
- where TKey : notnull
- where TState : IEquatable
- where TKeeper : StateKeeperBase, new()
- {
- handlerBuilder.SetStateKeeper(specialState, keyResolver);
- return handlerBuilder;
- }
-
- ///
- /// Adds a targeted filter for a specific filter target type.
- ///
- ///
- /// The type of the filter target.
- ///
- /// Function to get the filter target from an update.
- /// The filter to add.
- /// The builder instance.
- public static TBuilder AddTargetedFilter(this TBuilder handlerBuilder, Func getFilterringTarget, IFilter filter)
- where TBuilder : HandlerBuilderBase
- where TFilterTarget : class
- {
- handlerBuilder.AddTargetedFilter(getFilterringTarget, filter);
- return handlerBuilder;
- }
-
- ///
- /// Adds multiple targeted filters for a specific filter target type.
- ///
- ///
- /// The type of the filter target.
- ///
- /// Function to get the filter target from an update.
- /// The filters to add.
- /// The builder instance.
- public static TBuilder AddTargetedFilters(this TBuilder handlerBuilder, Func getFilterringTarget, params IFilter[] filters)
- where TBuilder : HandlerBuilderBase
- where TFilterTarget : class
- {
- handlerBuilder.AddTargetedFilters(getFilterringTarget, filters);
- return handlerBuilder;
- }
-
- ///
- /// Sets a numeric state keeper with a custom key resolver.
- ///
- /// The type of the handler builder.
- /// The handler builder.
- /// The numeric state value.
- /// The key resolver for the state.
- /// The handler builder for method chaining.
- public static TBuilder SetNumericState(this TBuilder handlerBuilder, int myState, IStateKeyResolver keyResolver)
- where TBuilder : HandlerBuilderBase
- {
- handlerBuilder.SetStateKeeper(myState, keyResolver);
- return handlerBuilder;
- }
-
- ///
- /// Sets a numeric state keeper with a special state and custom key resolver.
- ///
- /// The type of the handler builder.
- /// The handler builder.
- /// The special state value.
- /// The key resolver for the state.
- /// The handler builder for method chaining.
- public static TBuilder SetNumericState(this TBuilder handlerBuilder, SpecialState specialState, IStateKeyResolver keyResolver)
- where TBuilder : HandlerBuilderBase
- {
- handlerBuilder.SetStateKeeper(specialState, keyResolver);
- return handlerBuilder;
- }
-
- ///
- /// Sets a numeric state keeper with the default sender ID resolver.
- ///
- /// The type of the handler builder.
- /// The handler builder.
- /// The numeric state value.
- /// The handler builder for method chaining.
- public static TBuilder SetNumericState(this TBuilder handlerBuilder, int myState)
- where TBuilder : HandlerBuilderBase
- {
- handlerBuilder.SetStateKeeper(myState, new SenderIdResolver());
- return handlerBuilder;
- }
-
- ///
- /// Sets a numeric state keeper with a special state and the default sender ID resolver.
- ///
- /// The type of the handler builder.
- /// The handler builder.
- /// The special state value.
- /// The handler builder for method chaining.
- public static TBuilder SetNumericState(this TBuilder handlerBuilder, SpecialState specialState)
- where TBuilder : HandlerBuilderBase
- {
- handlerBuilder.SetStateKeeper(specialState, new SenderIdResolver());
- return handlerBuilder;
- }
-
- ///
- /// Sets an enum state keeper with a custom key resolver.
- ///
- /// The type of the handler builder.
- /// The type of the enum state.
- /// The handler builder.
- /// The enum state value.
- /// The key resolver for the state.
- /// The handler builder for method chaining.
- public static TBuilder SetEnumState(this TBuilder handlerBuilder, TEnum myState, IStateKeyResolver keyResolver)
- where TBuilder : HandlerBuilderBase
- where TEnum : Enum, IEquatable
- {
- handlerBuilder.SetStateKeeper>(myState, keyResolver);
- return handlerBuilder;
- }
-
- ///
- /// Sets an enum state keeper with a special state and custom key resolver.
- ///
- /// The type of the handler builder.
- /// The type of the enum state.
- /// The handler builder.
- /// The special state value.
- /// The key resolver for the state.
- /// The handler builder for method chaining.
- public static TBuilder SetEnumState(this TBuilder handlerBuilder, SpecialState specialState, IStateKeyResolver keyResolver)
- where TBuilder : HandlerBuilderBase
- where TEnum : Enum, IEquatable
- {
- handlerBuilder.SetStateKeeper>(specialState, keyResolver);
- return handlerBuilder;
- }
-
- ///
- /// Sets an enum state keeper with the default sender ID resolver.
- ///
- /// The type of the handler builder.
- /// The type of the enum state.
- /// The handler builder.
- /// The enum state value.
- /// The handler builder for method chaining.
- public static TBuilder SetEnumState(this TBuilder handlerBuilder, TEnum myState)
- where TBuilder : HandlerBuilderBase
- where TEnum : Enum, IEquatable
- {
- handlerBuilder.SetStateKeeper>(myState, new SenderIdResolver());
- return handlerBuilder;
- }
-
- ///
- /// Sets an enum state keeper with a special state and the default sender ID resolver.
- ///
- /// The type of the handler builder.
- /// The type of the enum state.
- /// The handler builder.
- /// The special state value.
- /// The handler builder for method chaining.
- public static TBuilder SetEnumState(this TBuilder handlerBuilder, SpecialState specialState)
- where TBuilder : HandlerBuilderBase
- where TEnum : Enum, IEquatable
- {
- handlerBuilder.SetStateKeeper>(specialState, new SenderIdResolver());
- return handlerBuilder;
- }
- }
-
- ///
- /// Provides extension methods for working with collections.
- ///
- public static partial class ColletionsExtensions
- {
- ///
- /// Creates a from an
- /// according to a specified key selector function.
- ///
- ///
- ///
- ///
- ///
- ///
- public static ReadOnlyDictionary ToReadOnlyDictionary(this IEnumerable source, Func keySelector) where TKey : notnull
- {
- Dictionary dictionary = source.ToDictionary(keySelector);
- return new ReadOnlyDictionary(dictionary);
- }
-
- ///
- /// Enumerates objects in a and executes an on each one
- ///
- ///
- ///
- ///
- ///
- public static IEnumerable ForEach(this IEnumerable source, Action action)
- {
- foreach (TValue value in source)
- action.Invoke(value);
-
- return source;
- }
-
- ///
- /// Sets the value of a key in a dictionary, or if the key does not exist, adds it
- ///
- ///
- ///
- ///
- ///
- ///
- public static void Set(this IDictionary source, TKey key, TValue value)
- {
- if (source.ContainsKey(key))
- source[key] = value;
- else
- source.Add(key, value);
- }
-
- ///
- /// Sets the value of a key in a dictionary, or if the key does not exist, adds its default value.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static void Set(this IDictionary source, TKey key, TValue value, TValue defaultValue)
- {
- if (source.ContainsKey(key))
- source[key] = value;
- else
- source.Add(key, defaultValue);
- }
-
- ///
- /// Return the random object from
- ///
- ///
- ///
- ///
- public static TSource Random(this IEnumerable source)
- => source.Random(new Random());
-
- ///
- /// Return the random object from
- ///
- ///
- ///
- ///
- ///
- public static TSource Random(this IEnumerable source, Random random)
- => source.ElementAt(random.Next(0, source.Count() - 1));
-
- ///
- /// Adds a range of elements to collection if they dont already exist using default equality comparer
- ///
- ///
- ///
- ///
- public static void UnionAdd(this IList list, params IEnumerable elements)
- {
- foreach (TSource item in elements)
- {
- if (!list.Contains(item, EqualityComparer.Default))
- list.Add(item);
- }
- }
-
- ///
- /// Return index of first element that satisfies the condition
- ///
- ///
- ///
- ///
- ///
- public static int IndexOf(this IEnumerable source, Func predicate)
- {
- int index = 0;
- foreach (T item in source)
- {
- if (predicate.Invoke(item))
- return index;
-
- index++;
- }
-
- return -1;
- }
-
- ///
- /// Returns an enumerable that repeats the item multiple times.
- ///
- ///
- ///
- ///
- ///
- public static IEnumerable Repeat(this T item, int times)
- => Enumerable.Range(0, times).Select(_ => item);
-
- ///
- /// Returns the only element of a sequence, or a default value if the sequence is empty.
- /// This method returns default if there is more than one element in the sequence.
- ///
- ///
- ///
- ///
- public static T? SingleSafe(this IEnumerable source)
- => source.Count() == 1 ? source.ElementAt(0) : default;
-
- ///
- /// Returns the only element of a sequence that satisfies a specified condition or a default value if no such element exists.
- /// This method return default if more than one element satisfies the condition.
- ///
- ///
- ///
- ///
- ///
- public static T? SingleSafe(this IEnumerable source, Func predicate)
- {
- source = source.Where(predicate);
- return source.Count() == 1 ? source.ElementAt(0) : default;
- }
- }
-
- ///
- /// Provides extension methods for reflection and type inspection.
- ///
- public static partial class ReflectionExtensions
- {
- ///
- /// Checks if a type implements the interface.
- ///
- /// The type to check.
- /// True if the type implements ICustomDescriptorsProvider; otherwise, false.
- public static bool IsCustomDescriptorsProvider(this Type type)
- => type.GetInterface(nameof(ICustomDescriptorsProvider)) != null;
-
- ///
- /// Checks if is a
- ///
- ///
- ///
- public static bool IsFilterType(this Type type)
- => type.IsAssignableToGenericType(typeof(IFilter<>));
-
- ///
- /// Checks if is a descendant of class
- ///
- ///
- ///
- public static bool IsHandlerAbstract(this Type type)
- => type.IsAbstract && typeof(UpdateHandlerBase).IsAssignableFrom(type);
-
- ///
- /// Checks if is an implementation of class or its descendants
- ///
- ///
- ///
- public static bool IsHandlerRealization(this Type type)
- => !type.IsAbstract && type != typeof(UpdateHandlerBase) && typeof(UpdateHandlerBase).IsAssignableFrom(type);
-
- ///
- /// Checks if has a parameterless constructor
- ///
- ///
- ///
- public static bool HasParameterlessCtor(this Type type)
- => type.GetConstructors().Any(ctor => ctor.GetParameters().Length == 0);
-
- /*
- ///
- /// Invokes a "" method of an object
- ///
- ///
- ///
- ///
- ///
- public static object? InvokeMethod(this object obj, string methodName, params object[]? args)
- => obj.GetType().GetMethod(methodName, BindAll).InvokeMethod(obj, args);
-
- ///
- /// Invokes a method of
- ///
- ///
- ///
- ///
- ///
- public static object? InvokeMethod(this MethodInfo methodInfo, object obj, params object[]? args)
- => methodInfo.Invoke(obj, args);
-
- ///
- /// Invokes a static method of
- ///
- ///
- ///
- ///
- public static object? InvokeStaticMethod(this MethodInfo methodInfo, params object[]? parameters)
- => methodInfo.Invoke(null, parameters);
-
- ///
- /// Invokes a static "" method of an object
- ///
- ///
- ///
- ///
- ///
- ///
- public static T? InvokeStaticMethod(this object obj, string methodName, params object[]? parameters)
- => (T?)obj.GetType().GetMethod(methodName, BindAll).InvokeStaticMethod(parameters);
-
- ///
- /// Invokes a generic method of with generic types in
- ///
- ///
- ///
- ///
- ///
- ///
- public static object InvokeGenericMethod(this MethodInfo methodInfo, object obj, Type[] genericParameters, params object[]? parameters)
- => methodInfo.MakeGenericMethod(genericParameters).Invoke(obj, parameters);
-
- ///
- /// Invokes a generic method with generic types in
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static T? InvokeGenericMethod(this object obj, string methodName, Type[] genericParameters, params object[]? parameters)
- => (T?)obj.GetType().GetMethod(methodName).InvokeGenericMethod(obj, genericParameters, parameters);
- */
-
- ///
- /// Checks is has public properties
- ///
- ///
- ///
- public static bool HasPublicProperties(this Type type)
- => type.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(prop => prop.Name != "IsCollectible").Any();
-
- ///
- /// Determines whether an instance of a specified type can be assigned to an instance of the current type
- ///
- ///
- ///
- ///
- public static bool IsAssignableToGenericType(this Type givenType, Type genericType)
- {
- if (givenType.GetInterfaces().Any(inter => inter.IsGenericType && inter.GetGenericTypeDefinition() == genericType))
- return true;
-
- if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
- return true;
-
- if (givenType.BaseType == null)
- return false;
-
- return givenType.BaseType.IsAssignableToGenericType(genericType);
- }
- }
-
- ///
- /// Provides extension methods for string manipulation.
- ///
- public static partial class StringExtensions
- {
- ///
- /// Slices a string into a array of substrings of fixed
- ///
- ///
- ///
- ///
- public static IEnumerable SliceBy(this string source, int length)
- {
- for (int start = 0; start < source.Length; start += length + 1)
- {
- int tillEnd = source.Length - start;
- int toSlice = tillEnd < length + 1 ? tillEnd : length + 1;
-
- ReadOnlySpan chunk = source.AsSpan().Slice(start, toSlice);
- yield return chunk.ToString();
- }
- }
-
- ///
- /// Return new string with first found letter set to upper case
- ///
- ///
- ///
- public static string FirstLetterToUpper(this string target)
- {
- char[] chars = target.ToCharArray();
- int index = chars.IndexOf(char.IsLetter);
- chars[index] = char.ToUpper(chars[index]);
- return new string(chars);
- }
-
- ///
- /// Return new string with first found letter set to lower case
- ///
- ///
- ///
- public static string FirstLetterToLower(this string target)
- {
- char[] chars = target.ToCharArray();
- int index = chars.IndexOf(char.IsLetter);
- chars[index] = char.ToLower(chars[index]);
- return new string(chars);
- }
-
- ///
- /// Checks if string contains a 'word'.
- /// 'Word' must be a separate member of the text, and not have any alphabetic characters next to it.
- ///
- ///
- ///
- ///
- ///
- ///
- public static bool ContainsWord(this string source, string word, StringComparison comparison = StringComparison.InvariantCulture, int startIndex = 0)
- {
- int index = source.IndexOf(word, startIndex, comparison);
- if (index == -1)
- return false;
-
- if (index > 0)
- {
- char prev = source[index - 1];
- if (char.IsLetter(prev))
- return false;
- }
-
- if (index + word.Length < source.Length)
- {
- char post = source[index + word.Length];
- if (char.IsLetter(post))
- return false;
- }
-
- return true;
- }
- }
-
///
/// Provides extension methods for working with Telegram Update objects.
///
@@ -1509,29 +609,4 @@ namespace Telegrator
};
}
}
-
- ///
- /// Contains extension method for number types
- ///
- public static class NumbersExtensions
- {
- ///
- /// Check if int value has int flag using bit compare
- ///
- ///
- ///
- ///
- public static bool HasFlag(this int value, int flag)
- => (value & flag) == flag;
-
- ///
- /// Check if int value has enum flag using bit compare
- ///
- ///
- ///
- ///
- ///
- public static bool HasFlag(this int value, T flag) where T : Enum
- => value.HasFlag(Convert.ToInt32(flag));
- }
}