* Removed default filters comparison methods from 'FiltersFallbackReport'

* Added 'ReportInspector' for patterned filters diagnostic
* Moved some extension methods to corresponding namespaces and separated simple type extensions from complex types extensions
This commit is contained in:
2025-08-25 02:46:43 +04:00
parent 64950b413c
commit 70ee6eb9c1
14 changed files with 1077 additions and 1092 deletions
@@ -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
{
/// <summary>
/// Extension methods for handler builders.
/// Provides convenient methods for creating handlers and setting state keepers.
/// </summary>
public static partial class HandlerBuilderExtensions
{
/// <inheritdoc cref="HandlerBuilderBase.SetUpdateValidating(UpdateValidateAction)"/>
public static TBuilder SetUpdateValidating<TBuilder>(this TBuilder handlerBuilder, UpdateValidateAction updateValidateAction)
where TBuilder : HandlerBuilderBase
{
handlerBuilder.SetUpdateValidating(updateValidateAction);
return handlerBuilder;
}
/// <inheritdoc cref="HandlerBuilderBase.SetConcurreny(int)"/>
public static TBuilder SetConcurreny<TBuilder>(this TBuilder handlerBuilder, int concurrency)
where TBuilder : HandlerBuilderBase
{
handlerBuilder.SetConcurreny(concurrency);
return handlerBuilder;
}
/// <inheritdoc cref="HandlerBuilderBase.SetPriority(int)"/>
public static TBuilder SetPriority<TBuilder>(this TBuilder handlerBuilder, int priority)
where TBuilder : HandlerBuilderBase
{
handlerBuilder.SetPriority(priority);
return handlerBuilder;
}
/// <inheritdoc cref="HandlerBuilderBase.SetIndexer(int, int)"/>
public static TBuilder SetIndexer<TBuilder>(this TBuilder handlerBuilder, int concurrency, int priority)
where TBuilder : HandlerBuilderBase
{
handlerBuilder.SetIndexer(concurrency, priority);
return handlerBuilder;
}
/// <inheritdoc cref="HandlerBuilderBase.AddFilter(IFilter{Update})"/>
public static TBuilder AddFilter<TBuilder>(this TBuilder handlerBuilder, IFilter<Update> filter)
where TBuilder : HandlerBuilderBase
{
handlerBuilder.AddFilter(filter);
return handlerBuilder;
}
/// <inheritdoc cref="HandlerBuilderBase.AddFilters(IFilter{Update}[])"/>
public static TBuilder AddFilters<TBuilder>(this TBuilder handlerBuilder, params IFilter<Update>[] filters)
where TBuilder : HandlerBuilderBase
{
handlerBuilder.AddFilters(filters);
return handlerBuilder;
}
/// <inheritdoc cref="HandlerBuilderBase.SetStateKeeper{TKey, TState, TKeeper}(TState, IStateKeyResolver{TKey})"/>
public static TBuilder SetStateKeeper<TBuilder, TKey, TState, TKeeper>(this TBuilder handlerBuilder, TState myState, IStateKeyResolver<TKey> keyResolver)
where TBuilder : HandlerBuilderBase
where TKey : notnull
where TState : IEquatable<TState>
where TKeeper : StateKeeperBase<TKey, TState>, new()
{
handlerBuilder.SetStateKeeper<TKey, TState, TKeeper>(myState, keyResolver);
return handlerBuilder;
}
/// <inheritdoc cref="HandlerBuilderBase.SetStateKeeper{TKey, TState, TKeeper}(SpecialState, IStateKeyResolver{TKey})"/>
public static TBuilder SetStateKeeper<TBuilder, TKey, TState, TKeeper>(this TBuilder handlerBuilder, SpecialState specialState, IStateKeyResolver<TKey> keyResolver)
where TBuilder : HandlerBuilderBase
where TKey : notnull
where TState : IEquatable<TState>
where TKeeper : StateKeeperBase<TKey, TState>, new()
{
handlerBuilder.SetStateKeeper<TKey, TState, TKeeper>(specialState, keyResolver);
return handlerBuilder;
}
/// <summary>
/// Adds a targeted filter for a specific filter target type.
/// </summary>
/// <typeparam name="TBuilder"></typeparam>
/// <typeparam name="TFilterTarget">The type of the filter target.</typeparam>
/// <param name="handlerBuilder"></param>
/// <param name="getFilterringTarget">Function to get the filter target from an update.</param>
/// <param name="filter">The filter to add.</param>
/// <returns>The builder instance.</returns>
public static TBuilder AddTargetedFilter<TBuilder, TFilterTarget>(this TBuilder handlerBuilder, Func<Update, TFilterTarget?> getFilterringTarget, IFilter<TFilterTarget> filter)
where TBuilder : HandlerBuilderBase
where TFilterTarget : class
{
handlerBuilder.AddTargetedFilter(getFilterringTarget, filter);
return handlerBuilder;
}
/// <summary>
/// Adds multiple targeted filters for a specific filter target type.
/// </summary>
/// <typeparam name="TBuilder"></typeparam>
/// <typeparam name="TFilterTarget">The type of the filter target.</typeparam>
/// <param name="handlerBuilder"></param>
/// <param name="getFilterringTarget">Function to get the filter target from an update.</param>
/// <param name="filters">The filters to add.</param>
/// <returns>The builder instance.</returns>
public static TBuilder AddTargetedFilters<TBuilder, TFilterTarget>(this TBuilder handlerBuilder, Func<Update, TFilterTarget?> getFilterringTarget, params IFilter<TFilterTarget>[] filters)
where TBuilder : HandlerBuilderBase
where TFilterTarget : class
{
handlerBuilder.AddTargetedFilters(getFilterringTarget, filters);
return handlerBuilder;
}
/// <summary>
/// Sets a numeric state keeper with a custom key resolver.
/// </summary>
/// <typeparam name="TBuilder">The type of the handler builder.</typeparam>
/// <param name="handlerBuilder">The handler builder.</param>
/// <param name="myState">The numeric state value.</param>
/// <param name="keyResolver">The key resolver for the state.</param>
/// <returns>The handler builder for method chaining.</returns>
public static TBuilder SetNumericState<TBuilder>(this TBuilder handlerBuilder, int myState, IStateKeyResolver<long> keyResolver)
where TBuilder : HandlerBuilderBase
{
handlerBuilder.SetStateKeeper<long, int, NumericStateKeeper>(myState, keyResolver);
return handlerBuilder;
}
/// <summary>
/// Sets a numeric state keeper with a special state and custom key resolver.
/// </summary>
/// <typeparam name="TBuilder">The type of the handler builder.</typeparam>
/// <param name="handlerBuilder">The handler builder.</param>
/// <param name="specialState">The special state value.</param>
/// <param name="keyResolver">The key resolver for the state.</param>
/// <returns>The handler builder for method chaining.</returns>
public static TBuilder SetNumericState<TBuilder>(this TBuilder handlerBuilder, SpecialState specialState, IStateKeyResolver<long> keyResolver)
where TBuilder : HandlerBuilderBase
{
handlerBuilder.SetStateKeeper<long, int, NumericStateKeeper>(specialState, keyResolver);
return handlerBuilder;
}
/// <summary>
/// Sets a numeric state keeper with the default sender ID resolver.
/// </summary>
/// <typeparam name="TBuilder">The type of the handler builder.</typeparam>
/// <param name="handlerBuilder">The handler builder.</param>
/// <param name="myState">The numeric state value.</param>
/// <returns>The handler builder for method chaining.</returns>
public static TBuilder SetNumericState<TBuilder>(this TBuilder handlerBuilder, int myState)
where TBuilder : HandlerBuilderBase
{
handlerBuilder.SetStateKeeper<long, int, NumericStateKeeper>(myState, new SenderIdResolver());
return handlerBuilder;
}
/// <summary>
/// Sets a numeric state keeper with a special state and the default sender ID resolver.
/// </summary>
/// <typeparam name="TBuilder">The type of the handler builder.</typeparam>
/// <param name="handlerBuilder">The handler builder.</param>
/// <param name="specialState">The special state value.</param>
/// <returns>The handler builder for method chaining.</returns>
public static TBuilder SetNumericState<TBuilder>(this TBuilder handlerBuilder, SpecialState specialState)
where TBuilder : HandlerBuilderBase
{
handlerBuilder.SetStateKeeper<long, int, NumericStateKeeper>(specialState, new SenderIdResolver());
return handlerBuilder;
}
/// <summary>
/// Sets an enum state keeper with a custom key resolver.
/// </summary>
/// <typeparam name="TBuilder">The type of the handler builder.</typeparam>
/// <typeparam name="TEnum">The type of the enum state.</typeparam>
/// <param name="handlerBuilder">The handler builder.</param>
/// <param name="myState">The enum state value.</param>
/// <param name="keyResolver">The key resolver for the state.</param>
/// <returns>The handler builder for method chaining.</returns>
public static TBuilder SetEnumState<TBuilder, TEnum>(this TBuilder handlerBuilder, TEnum myState, IStateKeyResolver<long> keyResolver)
where TBuilder : HandlerBuilderBase
where TEnum : Enum, IEquatable<TEnum>
{
handlerBuilder.SetStateKeeper<long, TEnum, EnumStateKeeper<TEnum>>(myState, keyResolver);
return handlerBuilder;
}
/// <summary>
/// Sets an enum state keeper with a special state and custom key resolver.
/// </summary>
/// <typeparam name="TBuilder">The type of the handler builder.</typeparam>
/// <typeparam name="TEnum">The type of the enum state.</typeparam>
/// <param name="handlerBuilder">The handler builder.</param>
/// <param name="specialState">The special state value.</param>
/// <param name="keyResolver">The key resolver for the state.</param>
/// <returns>The handler builder for method chaining.</returns>
public static TBuilder SetEnumState<TBuilder, TEnum>(this TBuilder handlerBuilder, SpecialState specialState, IStateKeyResolver<long> keyResolver)
where TBuilder : HandlerBuilderBase
where TEnum : Enum, IEquatable<TEnum>
{
handlerBuilder.SetStateKeeper<long, TEnum, EnumStateKeeper<TEnum>>(specialState, keyResolver);
return handlerBuilder;
}
/// <summary>
/// Sets an enum state keeper with the default sender ID resolver.
/// </summary>
/// <typeparam name="TBuilder">The type of the handler builder.</typeparam>
/// <typeparam name="TEnum">The type of the enum state.</typeparam>
/// <param name="handlerBuilder">The handler builder.</param>
/// <param name="myState">The enum state value.</param>
/// <returns>The handler builder for method chaining.</returns>
public static TBuilder SetEnumState<TBuilder, TEnum>(this TBuilder handlerBuilder, TEnum myState)
where TBuilder : HandlerBuilderBase
where TEnum : Enum, IEquatable<TEnum>
{
handlerBuilder.SetStateKeeper<long, TEnum, EnumStateKeeper<TEnum>>(myState, new SenderIdResolver());
return handlerBuilder;
}
/// <summary>
/// Sets an enum state keeper with a special state and the default sender ID resolver.
/// </summary>
/// <typeparam name="TBuilder">The type of the handler builder.</typeparam>
/// <typeparam name="TEnum">The type of the enum state.</typeparam>
/// <param name="handlerBuilder">The handler builder.</param>
/// <param name="specialState">The special state value.</param>
/// <returns>The handler builder for method chaining.</returns>
public static TBuilder SetEnumState<TBuilder, TEnum>(this TBuilder handlerBuilder, SpecialState specialState)
where TBuilder : HandlerBuilderBase
where TEnum : Enum, IEquatable<TEnum>
{
handlerBuilder.SetStateKeeper<long, TEnum, EnumStateKeeper<TEnum>>(specialState, new SenderIdResolver());
return handlerBuilder;
}
}
}
@@ -1,164 +0,0 @@
using Telegram.Bot.Types;
using Telegrator.Attributes.Components;
using Telegrator.Filters.Components;
using Telegrator.MadiatorCore.Descriptors;
namespace Telegrator.Handlers.Components
{
/// <summary>
/// Represents a report of filter fallback information for debugging and error handling.
/// Contains detailed information about which filters failed and why during handler execution.
/// </summary>
/// <param name="descriptor">The handler descriptor that generated this report.</param>
/// <param name="context">The filter execution context.</param>
public class FiltersFallbackReport(HandlerDescriptor descriptor, FilterExecutionContext<Update> context)
{
/// <summary>
/// Gets the handler descriptor associated with this fallback report.
/// </summary>
public HandlerDescriptor Descriptor { get; } = descriptor;
/// <summary>
/// Gets the filter execution context that generated this report.
/// </summary>
public FilterExecutionContext<Update> Context { get; } = context;
/// <summary>
/// Gets or sets the fallback information for the update validator filter.
/// </summary>
public FilterFallbackInfo? UpdateValidator { get; set; }
/// <summary>
/// Gets or sets the fallback information for the state keeper validator filter.
/// </summary>
public FilterFallbackInfo? StateKeeperValidator { get; set; }
/// <summary>
/// Gets the list of fallback information for update filters that failed.
/// </summary>
public List<FilterFallbackInfo> UpdateFilters { get; } = [];
/// <summary>
/// Checks if the failure is due to a specific filter.
/// </summary>
/// <param name="index"></param>
/// <param name="name"></param>
/// <returns></returns>
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);
}
/// <summary>
/// Checks if the failure is due to a specific filter.
/// </summary>
/// <param name="names"></param>
/// <returns></returns>
public bool Only(string[] names)
{
return UpdateFilters
.Where(info => info.Failed)
.Select(info => info.Name)
.SequenceEqual(names);
}
/// <summary>
/// Checks if the failure is due to all filters except one.
/// </summary>
/// <param name="index"></param>
/// <param name="name"></param>
/// <returns></returns>
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);
}
/// <summary>
/// Checks if the failure is due to all filters except one.
/// </summary>
/// <param name="names"></param>
/// <returns></returns>
public bool Except(string[] names)
{
return UpdateFilters
.Where(info => !info.Failed)
.Select(info => info.Name)
.SequenceEqual(names);
}
/// <summary>
/// Checks if the failure is due to aall attribute type, excluding one.
/// </summary>
/// <typeparam name="T">The attribute type to check for.</typeparam>
/// <param name="index">The index of the filter to check (default: 0).</param>
/// <returns>True if the failure is exclusively due to the specified attribute type; otherwise, false.</returns>
public bool ExceptAttribute<T>(int index = 0) where T : UpdateFilterAttributeBase
=> Except(nameof(T), index);
/// <summary>
/// Checks if the failure is due to a specific attribute type, excluding other failures.
/// </summary>
/// <typeparam name="T">The attribute type to check for.</typeparam>
/// <param name="index">The index of the filter to check (default: 0).</param>
/// <returns>True if the failure is exclusively due to the specified attribute type; otherwise, false.</returns>
public bool OnlyAttribute<T>(int index = 0) where T : UpdateFilterAttributeBase
=> Only(nameof(T), index);
}
/// <summary>
/// Contains information about a filter that failed during execution.
/// Provides details about the filter, its failure status, and any associated exception.
/// </summary>
/// <param name="name">The name of the filter.</param>
/// <param name="filter">The filter instance that failed.</param>
/// <param name="failed">Whether the filter failed.</param>
/// <param name="exception">The exception that occurred during filter execution, if any.</param>
public class FilterFallbackInfo(string name, IFilter<Update> filter, bool failed, Exception? exception)
{
/// <summary>
/// Gets the name of the filter.
/// </summary>
public string Name { get; } = name;
/// <summary>
/// Gets the filter instance that failed.
/// </summary>
public IFilter<Update> Filter { get; } = filter;
/// <summary>
/// Gets a value indicating whether the filter failed.
/// </summary>
public bool Failed { get; } = failed;
/// <summary>
/// Gets the exception that occurred during filter execution, if any.
/// </summary>
public Exception? Exception { get; } = exception;
}
/// <summary>
/// Specifies the reason for a filter fallback.
/// </summary>
public enum FallbackReason
{
/// <summary>
/// The filter target was null.
/// </summary>
NullTarget,
/// <summary>
/// The filter failed to pass.
/// </summary>
FailedFilter
}
}
@@ -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
@@ -0,0 +1,36 @@
using Telegram.Bot.Types;
using Telegrator.Filters.Components;
namespace Telegrator.Handlers.Diagnostics
{
/// <summary>
/// Contains information about a filter that failed during execution.
/// Provides details about the filter, its failure status, and any associated exception.
/// </summary>
/// <param name="name">The name of the filter.</param>
/// <param name="filter">The filter instance that failed.</param>
/// <param name="failed">Whether the filter failed.</param>
/// <param name="exception">The exception that occurred during filter execution, if any.</param>
public class FilterFallbackInfo(string name, IFilter<Update> filter, bool failed, Exception? exception)
{
/// <summary>
/// Gets the name of the filter.
/// </summary>
public string Name { get; } = name;
/// <summary>
/// Gets the filter instance that failed.
/// </summary>
public IFilter<Update> Filter { get; } = filter;
/// <summary>
/// Gets a value indicating whether the filter failed.
/// </summary>
public bool Failed { get; } = failed;
/// <summary>
/// Gets the exception that occurred during filter execution, if any.
/// </summary>
public Exception? Exception { get; } = exception;
}
}
@@ -0,0 +1,65 @@
using Telegram.Bot.Types;
using Telegrator.Filters.Components;
using Telegrator.MadiatorCore.Descriptors;
namespace Telegrator.Handlers.Diagnostics
{
/// <summary>
/// Represents a report of filter fallback information for debugging and error handling.
/// Contains detailed information about which filters failed and why during handler execution.
/// </summary>
/// <param name="descriptor">The handler descriptor that generated this report.</param>
/// <param name="context">The filter execution context.</param>
public class FiltersFallbackReport(HandlerDescriptor descriptor, FilterExecutionContext<Update> context)
{
/// <summary>
/// Gets the handler descriptor associated with this fallback report.
/// </summary>
public HandlerDescriptor Descriptor { get; } = descriptor;
/// <summary>
/// Gets the filter execution context that generated this report.
/// </summary>
public FilterExecutionContext<Update> Context { get; } = context;
/// <summary>
/// Gets or sets the fallback information for the update validator filter.
/// </summary>
public FilterFallbackInfo? UpdateValidator { get; set; }
/// <summary>
/// Gets or sets the fallback information for the state keeper validator filter.
/// </summary>
public FilterFallbackInfo? StateKeeperValidator { get; set; }
/// <summary>
/// Gets the list of fallback information for update filters that failed.
/// </summary>
public List<FilterFallbackInfo> UpdateFilters { get; } = [];
/// <summary>
/// Checks filter fail status by name
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public bool this[string name] => UpdateFilters.FirstOrDefault(f => f.Name == name)?.Failed ?? false;
/// <summary>
/// Creates new instance of <see cref="ReportInspector"/> with default filter state as FAILED.
/// </summary>
/// <returns></returns>
public ReportInspector AllFailed()
{
return new ReportInspector(this, false);
}
/// <summary>
/// Creates new instance of <see cref="ReportInspector"/> with default filter state as PASSED.
/// </summary>
/// <returns></returns>
public ReportInspector AllPassed()
{
return new ReportInspector(this, true);
}
}
}
@@ -0,0 +1,73 @@
namespace Telegrator.Handlers.Diagnostics
{
/// <summary>
/// A class builder for pattern checking of <see cref="FiltersFallbackReport"/>
/// </summary>
/// <param name="report"></param>
/// <param name="defaulState"></param>
public sealed class ReportInspector(FiltersFallbackReport report, bool defaulState)
{
private readonly FiltersFallbackReport _report = report;
private readonly bool _defaulState = defaulState;
private readonly List<string> _ignore = [];
private readonly List<string> _excepts = [];
/// <summary>
/// Adds a filter to the exclusion list.
/// Excluded filters are compared oppositely with the default state.
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public ReportInspector Except(string name)
{
_excepts.Add(name);
return this;
}
/// <summary>
/// Adds a filter to the ignore list.
/// Ignored filters are not checked and do not affect the final result.
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public ReportInspector Whenever(string name)
{
_ignore.Add(name);
return this;
}
/// <summary>
/// It goes through the report and compares it with the specified filter pattern.
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// Casts inspector by executing <see cref="Match"/>
/// </summary>
/// <param name="inspector"></param>
public static implicit operator bool(ReportInspector inspector) => inspector.Match();
}
}
@@ -0,0 +1,18 @@
using Telegrator.Attributes.Components;
namespace Telegrator.Handlers.Diagnostics
{
/// <summary>
/// Provides extension methods for <see cref="ReportInspector"/>
/// </summary>
public static partial class ReportInspectorExtensions
{
/// <inheritdoc cref="ReportInspector.Whenever(string)"/>
public static ReportInspector Whenever<TAttribute>(this ReportInspector inspector) where TAttribute : UpdateFilterAttributeBase
=> inspector.Whenever(nameof(TAttribute));
/// <inheritdoc cref="ReportInspector.Except(string)"/>
public static ReportInspector Except<TAttribute>(this ReportInspector inspector) where TAttribute : UpdateFilterAttributeBase
=> inspector.Except(nameof(TAttribute));
}
}
+284
View File
@@ -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
{
/// <summary>
/// Provides usefull helper methods for abstract handler containers
/// </summary>
public static class AbstractHandlerContainerExtensions
{
/// <summary>
/// Changes bot's reaction to message
/// </summary>
/// <param name="container"></param>
/// <param name="reaction"></param>
/// <param name="isBig"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task React(
this IAbstractHandlerContainer<Message> container,
ReactionType reaction,
bool isBig = false,
CancellationToken cancellationToken = default)
=> await container.Client.SetMessageReaction(
container.ActualUpdate.Chat,
container.ActualUpdate.Id,
[reaction], isBig, cancellationToken);
/// <summary>
/// Changes bot's reaction to message
/// </summary>
/// <param name="container"></param>
/// <param name="reactions"></param>
/// <param name="isBig"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task React(
this IAbstractHandlerContainer<Message> container,
IEnumerable<ReactionType> reactions,
bool isBig = false,
CancellationToken cancellationToken = default)
=> await container.Client.SetMessageReaction(
container.ActualUpdate.Chat,
container.ActualUpdate.Id,
reactions, isBig, cancellationToken);
/// <summary>
/// Sends a reply message to the current message.
/// </summary>
/// <param name="container"></param>
/// <param name="text">The text of the message to send.</param>
/// <param name="parseMode">The parse mode for the message text.</param>
/// <param name="replyMarkup">The reply markup for the message.</param>
/// <param name="linkPreviewOptions">Options for link preview generation.</param>
/// <param name="messageThreadId">The thread ID for forum topics.</param>
/// <param name="entities">The message entities to include.</param>
/// <param name="disableNotification">Whether to disable notification for the message.</param>
/// <param name="protectContent">Whether to protect the message content.</param>
/// <param name="messageEffectId">The message effect ID.</param>
/// <param name="businessConnectionId">The business connection ID.</param>
/// <param name="allowPaidBroadcast">Whether to allow paid broadcast.</param>
/// <param name="directMessageTopicId"></param>
/// <param name="suggestedPostParameters"></param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The sent message.</returns>
public static async Task<Message> Reply(
this IAbstractHandlerContainer<Message> container,
string text,
ParseMode parseMode = ParseMode.None,
ReplyMarkup? replyMarkup = null,
LinkPreviewOptions? linkPreviewOptions = null,
int? messageThreadId = null,
IEnumerable<MessageEntity>? 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);
/// <summary>
/// Sends a response message to the current chat.
/// </summary>
/// <param name="container"></param>
/// <param name="text">The text of the message to send.</param>
/// <param name="parseMode">The parse mode for the message text.</param>
/// <param name="replyParameters">The reply parameters for the message.</param>
/// <param name="replyMarkup">The reply markup for the message.</param>
/// <param name="linkPreviewOptions">Options for link preview generation.</param>
/// <param name="messageThreadId">The thread ID for forum topics.</param>
/// <param name="entities">The message entities to include.</param>
/// <param name="disableNotification">Whether to disable notification for the message.</param>
/// <param name="protectContent">Whether to protect the message content.</param>
/// <param name="messageEffectId">The message effect ID.</param>
/// <param name="businessConnectionId">The business connection ID.</param>
/// <param name="allowPaidBroadcast">Whether to allow paid broadcast.</param>
/// <param name="directMessageTopicId"></param>
/// <param name="suggestedPostParameters"></param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The sent message.</returns>
public static async Task<Message> Responce(
this IAbstractHandlerContainer<Message> container,
string text,
ParseMode parseMode = ParseMode.None,
ReplyParameters? replyParameters = null,
ReplyMarkup? replyMarkup = null,
LinkPreviewOptions? linkPreviewOptions = null,
int? messageThreadId = null,
IEnumerable<MessageEntity>? 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);
/// <summary>
/// Responnces to message that this CallbackQuery was originated from
/// </summary>
/// <param name="container"></param>
/// <param name="text"></param>
/// <param name="parseMode"></param>
/// <param name="replyParameters"></param>
/// <param name="replyMarkup"></param>
/// <param name="linkPreviewOptions"></param>
/// <param name="messageThreadId"></param>
/// <param name="entities"></param>
/// <param name="disableNotification"></param>
/// <param name="protectContent"></param>
/// <param name="messageEffectId"></param>
/// <param name="businessConnectionId"></param>
/// <param name="allowPaidBroadcast"></param>
/// <param name="directMessageTopicId"></param>
/// <param name="suggestedPostParameters"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static async Task<Message> Responce(
this IAbstractHandlerContainer<CallbackQuery> container,
string text,
ParseMode parseMode = ParseMode.None,
ReplyParameters? replyParameters = null,
ReplyMarkup? replyMarkup = null,
LinkPreviewOptions? linkPreviewOptions = null,
int? messageThreadId = null,
IEnumerable<MessageEntity>? 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);
}
/// <summary>
/// Edits message text that this CallbackQuery was originated from
/// </summary>
/// <param name="container"></param>
/// <param name="text"></param>
/// <param name="parseMode"></param>
/// <param name="replyMarkup"></param>
/// <param name="entities"></param>
/// <param name="linkPreviewOptions"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static async Task<Message> EditMessage(
this IAbstractHandlerContainer<CallbackQuery> container,
string text,
ParseMode parseMode = ParseMode.None,
InlineKeyboardMarkup? replyMarkup = null,
IEnumerable<MessageEntity>? 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);
}
/// <summary>
/// Use this method to send answers to callback queries sent from <a href="https://core.telegram.org/bots/features#inline-keyboards">inline keyboards</a>.
/// The answer will be displayed to the user as a notification at the top of the chat screen or as an alert
/// </summary>
/// <remarks>
/// 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 <a href="https://t.me/botfather">@BotFather</a> and accept the terms.
/// Otherwise, you may use links like <c>t.me/your_bot?start=XXXX</c> that open your bot with a parameter.
/// </remarks>
/// <param name="container"></param>
/// <param name="text"></param>
/// <param name="showAlert"></param>
/// <param name="url"></param>
/// <param name="cacheTime"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task AnswerCallbackQuery(
this IAbstractHandlerContainer<CallbackQuery> 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);
/// <summary>
/// Answers inline query
/// </summary>
/// <param name="container"></param>
/// <param name="results"></param>
/// <param name="cacheTime"></param>
/// <param name="isPersonal"></param>
/// <param name="nextOffset"></param>
/// <param name="button"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task AnswerInlineQuery(
this IAbstractHandlerContainer<InlineQuery> container,
IEnumerable<InlineQueryResult> 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);
}
}
}