60 lines
2.0 KiB
C#
60 lines
2.0 KiB
C#
namespace BotPages.Core.Routing;
|
||
|
||
using System.Text.RegularExpressions;
|
||
|
||
/// <summary>
|
||
/// Реестр команд, доступных из любого места.
|
||
/// </summary>
|
||
internal sealed class CommandsRegistry
|
||
{
|
||
private readonly List<(Regex pattern, Func<PageContext, CancellationToken, Task> handler)> _commands = new();
|
||
|
||
/// <summary>
|
||
/// Зарегистрировать команду, ведущую на страницу.
|
||
/// </summary>
|
||
public CommandsRegistry Map<TPage>(string commandTemplate) where TPage : Page
|
||
{
|
||
var pattern = ToRegex(commandTemplate);
|
||
_commands.Add((pattern, (ctx, ct) => ctx.Navigation.GoToAsync<TPage>(ctx, ct)));
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Зарегистрировать команду с кастомным обработчиком.
|
||
/// </summary>
|
||
public CommandsRegistry Map(string commandTemplate, Func<PageContext, CancellationToken, Task> handler)
|
||
{
|
||
var pattern = ToRegex(commandTemplate);
|
||
_commands.Add((pattern, handler));
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Попробовать выполнить команду.
|
||
/// </summary>
|
||
public bool TryDispatch(PageContext ctx, string command, CancellationToken ct, out Task? task)
|
||
{
|
||
foreach (var (pattern, handler) in _commands)
|
||
{
|
||
if (pattern.IsMatch(command))
|
||
{
|
||
task = handler(ctx, ct);
|
||
return true;
|
||
}
|
||
}
|
||
task = null;
|
||
return false;
|
||
}
|
||
|
||
private static Regex ToRegex(string template)
|
||
{
|
||
// Простейшее преобразование шаблона: "/open {page} {id?}" -> Regex
|
||
var escaped = Regex.Escape(template)
|
||
.Replace("\\{", "{").Replace("\\}", "}");
|
||
var pattern = "^" + escaped
|
||
.Replace("{page}", "(?<page>\\S+)")
|
||
.Replace("{id?}", "(?<id>\\S+)?") + "$";
|
||
return new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||
}
|
||
}
|