Запускаем бота

В прошлой заметке мы начали разработку нашего нового проекта на 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.

Текущий исходный код можно посмотреть вот здесь. Продолжение скоро!

Комментарии (4)
Сергей Лелеко
01.03.2022 15:16

Получается под каждую команду свой скрипт и соотвественно своя логика отдельно, ну в целом наверное это и правильно

bezumkinВасилий Наумкин
01.03.2022 15:21

Да, учитывая, что каждая команда расширяет общий класс, остатётся только прописывать логику и параметры.

Точно так же как в контроллерах Vesp - лично мне такой подход очень нравится.

Сергей Лелеко
01.03.2022 15:26

Да и мне! И кстати библиотека конечно очень хорошая, которую ты тут используешь при создании бота. Я их кучу перелопатил и эта лучшая на мой взгляд из тех что есть под PHP.

bezumkinВасилий Наумкин
01.03.2022 15:32

Я делал одного бота на botman/botman, но из-за своей универсальности конкретно с Телеграм на нём работать мне не понравилось.

Поэтому искал другую либу, и вот эта пока хорошая, посмотрим как будет дальше.

ЕвгенийК
09.04.2022 03:35
Это хорошо, что такая возможность есть и может быть использована. А то тенденция, мания, что-то в по...
begoodco1
07.04.2022 05:49
Зарегистрировался чтобы выразить благодарность за доступное и подробное описание процесса. Была возм...
bezumkin
Василий Наумкин
18.03.2022 12:35
Авторизация есть из коробки, для входа в базовую админку. Можно установить через composer и собрать ...
bezumkin
Василий Наумкин
10.03.2022 12:08
Ну, я имел в виду, что по закону можно =) А в реальности с валютой очевидные проблемы.
Сергей Лелеко
04.03.2022 06:12
О как! не знал! спасибо
bezumkin
Василий Наумкин
01.03.2022 15:32
Я делал одного бота на botman/botman, но из-за своей универсальности конкретно с Телеграм на нём раб...
bezumkin
Василий Наумкин
25.02.2022 09:22
P.S. Кажется цитаты у тебя никак не стилизуются в комментариях... Спасибо, поправил!
Electrica
Михаил
08.02.2022 11:19
Работает!
Алексей
09.01.2019 10:55
Насыщенный год ) От души поздравляю с ДР! Счастья, успехов и семейного благополучия! Жаль лимит заме...
septa rose
28.05.2018 22:16
hmmm, keren abis