Запускаем бота
В прошлой заметке мы начали разработку нашего нового проекта на Vesp и создали тестового бота.
Сегодня мы этого бота запустим с простейшими командами /start и /help.
Напоминаю, что мы используем библиотеку longman/telegram-bot, которая предлагает очень удобный метод для написания собственных команд боту.
Команда - это файл, имя которого заканчивается на Command и расширяет абстрактный класс Longman\TelegramBot\Commands\Command - ровно также, как контроллеры Vesp расширяют основной абстрактный контроллер.
Создаём директорию /core/src/Commands и в ней файл StartCommand.php:
<?php
namespace App\Commands;
use Longman\TelegramBot\Commands\UserCommand;
use Longman\TelegramBot\Entities\ServerResponse;
class StartCommand extends UserCommand
{
protected $name = 'start';
protected $description = 'Запуск бота';
protected $usage = '/start';
public function execute(): ServerResponse
{
$user = $this->getMessage()->getFrom();
$data = [
'Привет, ' . ($user->getFirstName()) . '!',
'Это тренировочный бот, написанный в целях обучения на https://bezumkin.ru/sections/vesp-telegram.',
'На данный момент бот отвечает раз в минуту. Используй /help, чтобы увидеть все доступные команды.',
];
return $this->replyToChat(implode(PHP_EOL . PHP_EOL, $data));
}
}
Теперь нам нужно указать нашему боту место с новыми командами. Делаем это в предусмотрительно заданном сервисе core/src/Services/Telegram.php прямо в конструкторе:
public function __construct()
{
parent::__construct(getenv('BOT_API_KEY'), getenv('BOT_USERNAME'));
// Наши команды
$this->addCommandsPath(BASE_DIR . 'core/src/Commands');
}
Константа BASE_DIR объявляется в файле core/bootstrap.php и означает корень всего проекта, так что можно смело её везде использовать.
Тут нужно небольшое лирическое отступление.
Как работают боты в Телеграм
Когда вы пишете что-то боту, ваше сообщение уходит на сервер Телеграма, и дальше он уже смотрит в настройки бота. Если у него есть назначенный адрес приёма сообщение (webhook), то сервис пытается переслать ваше сообщение на этот адрес.
Если ваш сервер с ботом не отвечает, или выдаёт ошибку, Телеграм пытается доставить сообщение в течение кого-то времени, со всё более увеличивающимся промежутком попыток, чтобы вас не заспамить запросами.
Если ваш сервер ответит кодом 200, значит всё ок, вы получили сообщение. Телеграм больше ничего от вас не ждёт, и дальше ваш бот должен отправить своё сообщение серверу Телеграм, а тот его перешлёт вам в чат.
То есть, вся работа с ботом идёт не напрямую, а через посредника, в лице серверов телеги. Но вы этого не замечаете, и вам кажется, что бот очень быстро напрямую вам отвечает.
Такая скорость возможно только при наличии webhook, то есть адреса на сервере вашего бота, куда Телеграм может обратиться в любой момент. Нам же заморачиваться с хостингам пока не нужно, и мы будем забирать сообщения для бота в ручном режиме, через cron.
Обработка сообщений
Для консольных скриптов, котороми обычно и являются команды cron, у Vesp предусмотрена директория cli, то бишь Command Line Interface.
Создаём core/cli/get-updates.php
<?php
require dirname(__DIR__) . '/bootstrap.php';
try {
$telegram = new \App\Services\Telegram();
$telegram->useGetUpdatesWithoutDatabase();
$telegram->handleGetUpdates();
} catch (Throwable $e) {
echo $e->getMessage();
}
Базу данных мы использовать не будем, поэтому здесь только загрузка нашего сервиса Telegram, без Eloquent.
Команда handleGetUpdates получит все отправленные боту сообщения, сопоставит их с командами, которые в нём прописаны, и отправит ответы юзерам на сервер Телеграм.
Этот файл можно запускать в консоли вручную или добавить в менджер задач проекта.
Для добавления есть готовый файл core/cli/cron.php, куда мы пишем:
$scheduler->php(__DIR__ . '/get-updates.php', null, [], 'get_updates')
->everyMinute()
->inForeground()
->onlyOne();
как видно, запуск будет каждуюу минуту и только в одном экземпляре.
Осталось только добавить менеджер в crontab. У себя на MacOS я делаю это через EDITOR=nano crontab -e в консоле.
Внутри пишем что-то вроде этого, образая внимание на пути к файлам:
* * * * * /opt/homebrew/bin/php ~/ВашиПроекты/ExampleBot/core/cli/cron.php
Теперь команда /start уже должна работать.
Но при использовании /help, увы, ничего не будет, потому что мы такой команды не добавляли.
Исправляемся в файле core/src/Commands/HelpCommand.php:
<?php
namespace App\Commands;
use Longman\TelegramBot\Commands\UserCommand;
use Longman\TelegramBot\Entities\ServerResponse;
class HelpCommand extends UserCommand
{
protected $name = 'help';
protected $description = 'Вывод сообщения со списком команд';
protected $usage = '/help';
public function execute(): ServerResponse
{
$data = [
'Вот все доступные команды:',
'',
];
/** @var UserCommand[] $commands */
$commands = $this->telegram->getCommandsList();
foreach ($commands as $command) {
if ($command->showInHelp() && $command->getUsage()) {
$data[] = $command->getUsage() . ' ' . $command->getDescription();
}
}
return $this->replyToChat(implode(PHP_EOL, $data));
}
}
Как видно из кода, здесь мы получаем все доступные команды и выводим их описание пользователю.
Заключение
Вот и всё, бот @VespExampleBot уже работает, можно подключаться к нему в Телеграме и проверять.
Только учтите, что на данный момент он отвечает только раз в минуту, потому что выполняется на моём домашнем компьютере через cron.
Текущий исходный код можно посмотреть вот здесь. Продолжение скоро!
0
👍
👎
❤️
🔥
😮
😢
😀
😡
807
28.02.2022, 18:22:11
4 комментария
Сергей Лелеко
01.03.2022, 21:16:30
Получается под каждую команду свой скрипт и соотвественно своя логика отдельно, ну в целом наверное это и правильно
01.03.2022, 21:21:57
Да, учитывая, что каждая команда расширяет общий класс, остатётся только прописывать логику и параметры.
Точно так же как в контроллерах Vesp - лично мне такой подход очень нравится.
Сергей Лелеко
01.03.2022, 21:26:02
Да и мне! И кстати библиотека конечно очень хорошая, которую ты тут используешь при создании бота. Я их кучу перелопатил и эта лучшая на мой взгляд из тех что есть под PHP.
01.03.2022, 21:32:32
Я делал одного бота на botman/botman, но из-за своей универсальности конкретно с Телеграм на нём работать мне не понравилось.
Поэтому искал другую либу, и вот эта пока хорошая, посмотрим как будет дальше.
bezumkin.ru
Личный сайт Василия Наумкина
Прямой эфир
Василий Наумкин
01.07.2024, 11:56:41
Да, верно, именно так.
А в контроллере, скорее всего, ловить данные методом post.
Василий Наумкин
26.06.2024, 09:38:15
О, точно, вылезает если не залогинен.
Спасибо, исправил!
Василий Наумкин
09.04.2024, 04:45:01
> Ошибка 500
Это не похоже на ошибку Nginx, это скорее всего ошибка PHP - надо смотреть его логи.
...
russel gal
09.03.2024, 20:17:18
> А этот стоило написать хотя бы затем, чтобы получить комментарий от юзера, который ничего не писал...
Александр Наумов
27.01.2024, 03:06:18
Василий, спасибо!
Извини, тупанул.