Работа с пошаговыми командами
PRTelegramBot бот предоставляет функционал пошагового выполнения команд. Допустим нужно чтобы пользователь прошел по следующим этапам:
Ввод имени
Ввод даты рождения
Для создание следующего шага используется класс StepTelegram.
/// <summary>
/// Позволяет выполнить пользователю команды пошагово
/// </summary>
public class StepTelegram : IExecuteStep
{
/// <summary>
/// Дочерние шаги
/// </summary>
public List<StepTelegram> Steps { get; private set; } = new List<StepTelegram>();
/// <summary>
/// Ссылка на метод который должен быть выполнен
/// </summary>
public Func<ITelegramBotClient, Update, Task> CommandDelegate { get; set; }
/// <summary>
/// Срок когда команда еще актуальна для выполнения
/// </summary>
public DateTime? ExpiredTime { get; set; }
/// <summary>
/// Кэш данных
/// </summary>
private ITelegramCache cache { get; set; }
/// <summary>
/// Создает новый шаг
/// </summary>
/// <param name="command">Команда для выполнения</param>
public StepTelegram(Func<ITelegramBotClient,Update, Task> command, ITelegramCache cache = null)
{
CommandDelegate = command;
this.cache = cache;
}
/// <summary>
/// Создает новый шаг
/// </summary>
/// <param name="command">Команда для выполнения</param>
/// <param name="steps">Коллекция шагов</param>
public StepTelegram(Func<ITelegramBotClient, Update, Task> command, List<StepTelegram> steps, ITelegramCache cache = null)
{
CommandDelegate = command;
Steps = steps;
this.cache = cache;
}
/// <summary>
/// Создает новый шаг
/// </summary>
/// <param name="command">Команда для выполнения</param>
/// <param name="expiriedTime">Максимальный срок выполнения команды</param>
public StepTelegram(Func<ITelegramBotClient, Update, Task> command, DateTime expiriedTime, ITelegramCache cache = null)
{
CommandDelegate = command;
ExpiredTime = expiriedTime;
this.cache = cache;
}
/// <summary>
/// Создает новый шаг
/// </summary>
/// <param name="command">Команда для выполнения</param>
/// <param name="expiriedTime">Максимальный срок выполнения команды</param>
/// <param name="steps">Коллекция шагов</param>
public StepTelegram(Func<ITelegramBotClient, Update, Task> command, DateTime expiriedTime, List<StepTelegram> steps)
{
CommandDelegate = command;
ExpiredTime = expiriedTime;
Steps = steps;
}
/// <summary>
/// Выполнение шага
/// </summary>
/// <param name="botClient">telegram клиент</param>
/// <param name="update">Update пользователя</param>
/// <returns>Результат обработки</returns>
public async Task<ResultExecuteStep> ExecuteStep(ITelegramBotClient botClient, Update update)
{
if (ExpiredTime != null && DateTime.Now > ExpiredTime)
{
update.ClearStepUserHandler();
return ResultExecuteStep.ExpiredTime;
}
try
{
await CommandDelegate.Invoke(botClient, update);
return ResultExecuteStep.Success;
}
catch(Exception ex)
{
botClient.GetBotDataOrNull()!.InvokeErrorLog(ex);
return ResultExecuteStep.Failure;
}
}
/// <summary>
/// Получение текущей команды
/// </summary>
/// <returns>Ссылка на метод обработки</returns>
public Func<ITelegramBotClient, Update, Task> GetExecuteMethod()
{
return CommandDelegate;
}
/// <summary>
/// Регистрация следующего шага
/// </summary>
/// <param name="nextStep">Метод для следующей обработки</param>
/// <param name="expiriedTime">До какого времени команду можно выполнить</param>
public void RegisterNextStep(Func<ITelegramBotClient, Update, Task> nextStep, DateTime? expiriedTime = null)
{
CommandDelegate = nextStep;
ExpiredTime = expiriedTime;
}
/// <summary>
/// Регистрация следующего шага
/// </summary>
/// <param name="nextStep">Метод для следующей обработки</param>
/// <param name="addTime">До какого времени команду можно выполнить</param>
public void RegisterNextStep(Func<ITelegramBotClient, Update, Task> nextStep, TimeSpan addTime)
{
CommandDelegate = nextStep;
ExpiredTime = DateTime.Now.Add(addTime);
}
/// <summary>
/// Получение текущего кэша
/// </summary>
/// <typeparam name="T">Класс для хранения кэша</typeparam>
/// <returns>Кэш</returns>
public T GetCache<T>() where T : ITelegramCache
{
return cache is T resultCache ? resultCache : default(T);
}
}
Для работы с шагами используется следующие методы расширения StepExtension:
Пользователь может прервать пошаговое выполнение команд в любой момент, для этого ему требуется вызвать ранее зарегистрированную команду. Допустим написать в чате Тест, в наших примерам можно было увидеть, что используется команда Тест.
Для хранение кэша (промежуточных данных) создадим класс StepCache.
public class StepCache : ITelegramCache
{
public string Name { get; set; }
public string BirthDay { get; set; }
public bool ClearData()
{
this.BirthDay = string.Empty;
this.Name = string.Empty;
return true;
}
}
Пример
/// <summary>
/// Пример работы пошагового выполнения команд
/// </summary>
public class ExampleStepCommand
{
/// <summary>
/// Напишите в чате "stepstart"
/// Метод регистрирует следующий шаг пользователя
/// </summary>
[ReplyMenuHandler("stepstart")]
public static async Task StepStart(ITelegramBotClient botClient, Update update)
{
string msg = "Тестирование функции пошагового выполнения\nНапишите ваше имя";
//Регистрация обработчика для последовательной обработки шагов и сохранение данных
update.RegisterStepHandler(new StepTelegram(StepOne, new StepCache()));
await Helpers.Message.Send(botClient, update, msg);
}
/// <summary>
/// При написание любого текста сообщения или нажатие на любую кнопку из reply для пользователя будет выполнен этот метод.
/// Метод регистрирует следующий шаг с максимальным времени выполнения
/// </summary>
public static async Task StepOne(ITelegramBotClient botClient, Update update)
{
string msg = $"Шаг 1 - Ваше имя {update.Message.Text}" +
$"\nВведите дату рождения";
//Получаем текущий обработчик
var handler = update.GetStepHandler<StepTelegram>();
//Записываем имя пользователя в кэш
handler!.GetCache<StepCache>().Name = update.Message.Text;
//Регистрация следующего шага
handler.RegisterNextStep(StepTwo);
await Helpers.Message.Send(botClient, update, msg);
}
/// <summary>
/// Напишите в чат любой текст и будет выполнена эта команда если у пользователя был записан следующий шаг
/// </summary>
public static async Task StepTwo(ITelegramBotClient botClient, Update update)
{
string msg = $"Шаг 2 - дата рождения {update.Message.Text}" +
$"\nНапиши любой текст, чтобы увидеть результат";
//Получаем текущий обработчик
var handler = update.GetStepHandler<StepTelegram>();
//Записываем дату рождения
handler!.GetCache<StepCache>().BirthDay = update.Message.Text;
//Регистрация следующего шага с максимальным ожиданием выполнения этого шага 5 минут от момента регистрации
handler.RegisterNextStep(StepThree, DateTime.Now.AddMinutes(5));
//Настройки для сообщения
var option = new OptionMessage();
//Добавление пустого reply меню с кнопкой "Главное меню"
//Функция является приоритетной, если пользователь нажмет эту кнопку будет выполнена функция главного меню, а не следующего шага.
option.MenuReplyKeyboardMarkup = MenuGenerator.ReplyKeyboard(1, new List<string>(), true, new DictionaryJSON().GetButton(nameof(ReplyKeys.RP_MAIN_MENU)));
await Helpers.Message.Send(botClient, update, msg, option);
}
/// <summary>
/// Напишите в чат любой текст и будет выполнена эта команда если у пользователя был записан следующий шаг
/// </summary>
public static async Task StepThree(ITelegramBotClient botClient, Update update)
{
//Получение текущего обработчика
var handler = update.GetStepHandler<StepTelegram>();
//Получение текущего кэша
var cache = handler!.GetCache<StepCache>(); ;
string msg = $"Шаг 3 - Результат: Имя:{cache.Name} дата рождения:{cache.BirthDay}" +
$"\nПоследовательность шагов очищена.";
//Последний шаг
update.ClearStepUserHandler();
await Helpers.Message.Send(botClient, update, msg);
}
/// <summary>
/// Если есть следующий шаг, он будет проигнорирован при выполнение данной команды
/// Потому что в ReplyMenuHandler значение первого аргумента установлено в true, что значит приоритетная команда
/// </summary>
[ReplyMenuHandler("ignorestep")]
public static async Task IngoreStep(ITelegramBotClient botClient, Update update)
{
string msg = update.HasStepHandler()
? "Следующий шаг проигнорирован"
: "Следующий шаг отсутствовал";
await Helpers.Message.Send(botClient, update, msg);
}
}
Завершение пошагового выполнение команд на последнем шаге
Начиная с версии 0.6 есть возможность взвести флаг, который оповестит, что это последний шаг в системе и пошаговое выполнение нужно завершить.
Пример:
var handler = update.GetStepHandler<StepTelegram>();
handler.LastStepExecuted = true;
Игнорирование базовых команд при выполнение пошаговых команд
Начиная с версии 0.6 есть возможность взвести флаг, который оповестит систему, что в данный момент нужно игнорировать все команды, кроме пошаговых.
Пример:
var handler = update.GetStepHandler<StepTelegram>();
handler.IgnoreBasicCommands = true;
Last updated