LE Blog

Инженер с поэтической душой

07.09.2016 firtree_right Телеграм-бот для Яндекс.ПДД

Введение

Увлечение чат-ботами докатилась и до меня. Как это может случиться наилучшим образом, — по необходимости. А необходимость возникла в совместном использовании Яндекс почты для домена. Оказалось, что веб-интерфейс для этого совершенно не приспособлен, но есть API. Но писать целый сайт для этого кажется накладным, а чат-бот — в самый раз. И вообще, мне кажется, это один из самых продуктивных способов использования технологии: интерфейс к API.

Ссылку на полный текст бота я приложу в конце. Сам бот не содержит в себе полного функционала всего API, а имеет лишь необходимую на данный момент часть. Сейчас хотел бы поделиться парой находок, которые пригодятся всем, кто захочет писать чат-ботов для Телеграм с помощью node.js.

Chat bot

Хуки в продакшне

У ботов Телеграм есть два способа работы: когда бот сам обращается за обновлениями по определённому адресу (polling) и с помощью веб-хуков, когда сервера сами дёргают заданный хук для передачи данных боту. В продакшне, конечно, удобнее работать с хуками, а при разработке — нет, поскольку сервер запускается на локальной машине. Кроме этого я рекомендую завести другого бота для разработки, чтобы те, кто пользуются вашим ботом в продакшне, не замечали, как вы разрабатываете. Возможность сделать это я нашёл пока только в одной библиотеке: node-telegram-bot-api с помощью недокументированной функции processUpdate. Делается это довольно просто. При инициализации бота в файле lib/bot.js:

if (process.env.NODE_ENV === 'production') {
    bot = new TelegramBot(config.botToken, {polling: false});
    bot.setWebHook(config.host + config.url);
} else {
    bot = new TelegramBot(config.devBotToken, {polling: true});
}

А затем уже в серверной части, которая, хоть и запускается всегда, имеет значение только для продакшна, в файле lib/web.js:

app.post(config.url, function (req, res) {
    options.bot.processUpdate(req.body);
    res.status(200).send({}).end();
});

Весь остальной код для бота работает в обоих случаях одинаково и в изменениях не нуждается, что совершенно прекрасно!

Оповещение об остановке

Второе, что нужно делать, как мне кажется, это оповещать хоть кого-нибудь о том, что сервер остановлен или запущен. Также это нужно, если при перезапуске бота, например, меняется кастомизированная клавиатура.

Если вы запускаете приложения с помощью pm2, то этот менеджер использует для остановки процесса тот же сигнал SIGINT, что мы используем, когда останавливаем сервер в разработке с помощью Ctrl-C. Очень удобно! В файле index.js

process.on('SIGINT', function () {
    Promise.all(config.permitUsers.map(function (userId) {
        return bot.sendMessage(userId, 'Бот временно выключается. Только спокойствие!', {
            reply_markup: {
                hide_keyboard: true
            }
        });
    })).then(gracefulClose).catch(function (err) {
        console.log(err);
        gracefulClose();
    });
});

Таким образом, останавливая наш сервер через Ctrl-C мы видим то же, что увидит пользователь, когда перезапускается приложение на сервере.

Материалы для самостоятельного изучения

  1. Полный на текущий момент код Телеграм-бота для Яндекс.ПДД;
  2. API Яндекс.ПДД;
  3. Как установить приложение node.js на ubuntu 16.04.