Перейти к содержанию

Создание обработчика новой команды компонента для отправки через tadmin

В данном разделе приведён пример создания клиентского обработчика новой команды управления компонентами, отправляемой из tadmin.

Как отмечалось в описании команд tadmin SendCommand и tadmin SendCommandClient, они позволяют отправить компоненту любую произвольную команду. Однако, для более сложных случаев и специальной обработки входных аргументов, передаваемых в аргументе командной строки -pp, может потребоваться написание собственного обработчика, нужным образом переводящего входные аргументы консольной команды tadmin в поле Arguments отправляемой компоненту команды. Для этой цели и служат обработчики отправляемых команд.

Обработчиком команды является любой корректно зарегистрированный в Unity контейнере класс, реализующий интерфейс IDiscoverySenderCommandHandler. Однако для написания собственных обработчиков рекомендуется использовать базовый класс DiscoverySenderCommandHandlerBase.

Рассмотрим существующие обработчики и выполняемые ими действия.

Обработчик Применяется к команде Порядок Назначение
CommonDiscoverySenderCommandHandler все команды 0 Применяется в начале выполнения цепочки обработчиков, устанавливает общие данные для всех команд:
- идентификатор команды,
- дату и время создания команды,
- дату и время истечения действия команды,
- перечень компонентов адресатов (целей) команды, если они не были явно заданы пользователем,
- права выполнения команды, заданные пользователем
PublishKeyDiscoverySenderCommandHandler PublishKey DiscoverySenderHelper.BaseHandlerOrder Устанавливает команде необходимые аргументы. Если права выполнения не заданы пользователем, устанавливает нужные для выполнения команды права.
В случае, если применяется в рамках команды SendCommand, регистрирует публичный ключ в Redis
CheckKeyDiscoverySenderCommandHandler CheckKey DiscoverySenderHelper.BaseHandlerOrder Устанавливает команде необходимые аргументы. Если права выполнения не заданы пользователем, устанавливает нужные для выполнения команды права
DeleteKeyDiscoverySenderCommandHandler DeleteKey DiscoverySenderHelper.BaseHandlerOrder Устанавливает команде необходимые аргументы. Если права выполнения не заданы пользователем, устанавливает нужные для выполнения команды права.
В случае, если применяется в рамках команды SendCommand, удаляет публичный ключ из Redis
MaintenanceDiscoverySenderCommandHandler Maintenance DiscoverySenderHelper.BaseHandlerOrder Устанавливает команде необходимые аргументы. Если права выполнения не заданы пользователем, устанавливает нужные для выполнения команды права. Если перечень компонентов адресатов (целей) команды не задан пользователем, устанавливает требуемых для команды адресатов
EnableTracingDiscoverySenderCommandHandler EnableTracing DiscoverySenderHelper.BaseHandlerOrder Устанавливает команде необходимые аргументы
DisableTracingDiscoverySenderCommandHandler DisableTracing DiscoverySenderHelper.BaseHandlerOrder Устанавливает команде необходимые аргументы
UnknownDiscoverySenderCommandHandler все команды int.MaxValue Применяется только к тем командам, которые не были обработаны предыдущими обработчиками. Переносит все аргументы, заданные в командной строке и начинающиеся с префикса -pp: в поле Arguments отправляемой компоненту команды

Каждому классу обработчику рекомендуется устанавливать соответствующий порядок использования при помощи использования атрибута Order(int order). Чем меньше порядок, тем выше приоритет и обработчик будет вызван раньше.

Note

Рекомендуется свои обработчики регистрировать с порядком DiscoverySenderHelper.BaseHandlerOrder или выше.

При помощи такого подхода можно зарегистрировать свой обработчик для всех команд, чтобы изменить заполнение запроса для команды.

Вначале рассмотрим пример создания обработчика общего назначения, который бы задавал команде все права выполнения, содержащиеся в ключе, которым она подписана. В проекте Tessa.Extensions.Console в директории SendCommandHandlers необходимо создать файл CustomizedCommonDiscoverySenderCommandHandler.cs следующего содержания:

#nullable enable using System.Threading; using System.Threading.Tasks; using Tessa.Discovery.Senders; using Tessa.Platform;

namespace Tessa.Extensions.Console.SendCommandHandlers { /// <summary> /// Customized common request handler, coping /// </summary> [Order(1)] public sealed class CustomizedCommonDiscoverySenderCommandHandler: DiscoverySenderCommandHandlerBase { #region Base Overrides

/// <inheritdoc/> public override bool IsApplicable(string commandTypeName) => true; // applies to all commands

/// <inheritdoc/> public override ValueTask PrepareRequestAsync(DiscoverySendCommandContext context, CancellationToken cancellationToken = default) { ThrowIfNull(context); // check that user not provided any scopes for command if (context.InitialScopes is not { Length: > 0 }) { // set command scopes them from signing key context.Request.Scopes = context.SigningKey.Scopes[..]; } return ValueTask.CompletedTask; }

#endregion } }

Здесь команда специально не помечается как обработанная, поскольку обработчик применяется ко всем командам. Также обработчику устанавливается порядок выполнения 1, чтобы он отработал после стандартного обработчика CommonDiscoverySenderCommandHandler и лишь немного скорректировал базовую инициализацию команды.

Теперь рассмотрим обработчик для новой команды Ping, которая должна поместить в аргументы команды либо содержимое аргумента -pp:say=some string, либо если аргумент не задан Hello!. Для этого необходимо создать класс PingDiscoverySenderCommandHandler.cs в той же директории, со следующим содержимым:

#nullable enable using System; using System.Threading; using System.Threading.Tasks; using Tessa.Discovery.Senders; using Tessa.Platform;

namespace Tessa.Extensions.Console.SendCommandHandlers { /// <summary> /// Sample Ping command handler. /// </summary> [Order(DiscoverySenderHelper.BaseHandlerOrder)] public sealed class PingDiscoverySenderCommandHandler : DiscoverySenderCommandHandlerBase { #region Fields

/// <summary> /// Our command type. /// </summary> private const string CommandType = "Ping";

#endregion

#region Base Overrides

/// <inheritdoc/> public override bool IsApplicable(string commandTypeName) => string.Equals(commandTypeName, CommandType, StringComparison.OrdinalIgnoreCase);

/// <inheritdoc/> public override async ValueTask PrepareRequestAsync(DiscoverySendCommandContext context, CancellationToken cancellationToken = default) { // mark as handled to prevent catch all handlers to handle this type of command context.Handled = true; // do this cause of command type is typed by hand, here we need case sensitive command type context.Request.Type = CommandType; // set some rights if (context.InitialScopes is not { Length: > 0 }) { context.Request.Scopes = new[] { "ping" }; } // set some args context.InitialArguments.TryGetValue("say", out var message); context.Request.Arguments["Say"] = message ?? "Hello!"; return ValueTask.CompletedTask; }

#endregion } }

Поскольку это обработчик для конкретной команды, поэтому команда сразу помечается как обработанная, чтобы исключить возможные побочные эффекты от обработчиков, перехватывающих все необработанные команды в конце цепочки обработчиков. Далее явным образом устанавливается тип команды, поскольку изначально тип вводится пользователем в командной строке, он может быть не в том регистре, что требуется серверным обработчикам, поэтому здесь выполняется приведение типа команды к нужному регистру. Затем проверяется были ли установлены пользователем права на выполнение команды и, если не были, устанавливаются нужные - ping. Далее производится попытка получить значение аргумента -pp:say. В результирующие аргументы команды помещается либо полученное значение, либо, если его не удалось получить, строка Hello!.

Финальным шагом для использования рассмотренных обработчиков является их регистрация. Для этого необходимо создать класс Registrator.cs в той же директории, со следующим содержимым:

#nullable enable using Tessa.Discovery.Senders; using Unity; using Unity.Lifetime;

namespace Tessa.Extensions.Console.SendCommandHandlers { public sealed class Registrator: RegistratorBase { public override void RegisterUnity() { this.UnityContainer // Register handlers .RegisterType<IDiscoverySenderCommandHandler, CustomizedCommonDiscoverySenderCommandHandler>(nameof(CustomizedCommonDiscoverySenderCommandHandler), new ContainerControlledLifetimeManager()) .RegisterType<IDiscoverySenderCommandHandler, PingDiscoverySenderCommandHandler>(nameof(PingDiscoverySenderCommandHandler), new ContainerControlledLifetimeManager()) ; } } }

Таким образом, рассмотрены базовые возможности по расширению цепочки обработки команд и введению поддержки новых команд для отправки компонентам в tadmin.

Back to top