Как превратить любой скрипт в Telegram-бота

от автора

Если вам нужен простенький Telegram bot, способный выполнять скрипты (написанные на любом языке) и отвечать текстом и картинками, то вам под кат. Там вы найдёте рассказ о бот-движке, который делает то, что вам надо.

Telegram bot

Краткий список возможностей движка:

  • Движок может обслуживать сразу несколько ботов
  • Бот выполняет скрипты (написанные на любом языке)
  • Сообщение попадает на вход скрипту в виде аргументов и переменных окружения
  • Вывод скрипта может быть текстом, форматированным текстом или изображением (распознаётся автоматически)
  • Движок гарантирует поочерёдный запуск скриптов (при написании скриптов можно не думать про локи и конкурентный доступ к ресурсам)
  • Бота можно дёргать по HTTP, чтобы отправлять сообщен не в ответ на запрос, а "асинхронно" (например по cron-у)

Движок максимально неприхотлив: ему не нужны базы данных, публичные IP-шники, SSL-сертификаты… Можно просто запустить на лаптопе, сидя за НАТом с наглухо закрытыми портами. В общем, начать экспериментировать вы можете прямо не сейчас, не отрываясь от чтения.

Сейчас я покажу, как это всё запустить и оживить.

Сборка

Вам понадобится язык Go. Чтобы его поставить, не нужны даже root-права. Но, для простоты, далее, я буду предполагать, что он у вас стоит в системе.

Скачиваем и собираем проект:

cd tmp git clone https://github.com/michurin/cnbot.git cd cnbot go build ./cmd/... ./cnbot

При запуске без параметров (последняя команда) вы получите ошибку, что не указан конфигурационный файл. Это значит, что всё собралось правильно.

Начинаем разговор

Первым делом, вам надо зарегистрировать бота и получить для него токен. Это совсем не сложно: инструкция на сайте Telegram.

Создаём минимальный кофигурационный файл (config.yaml):

bots:   firstBot:     token: "22222222:AAAAAAAAAAAAAA"     script: "/usr/bin/true"

Тут должен быть правильный токен и любой исполняемый файл в качестве скрипта (рекомендую выбить что-нибудь побезопасней, чем /bin/rm). Проверяем настройки (-i):

./cnbot -i -c config.yaml

Если токен правильный, вы получите отчёт о состоянии бота.

Запускаем бота (без -i)

./cnbot -c config.yaml

Пытаемся добавить его в Telegram-клиенте. В логах бота видим ошибку

user 500050880 is not allowed

Это ваш user_id (у вас он будет другой), добавляем его в конфиг

bots:   firstBot:     token: "22222222:AAAAAAAAAAAAAA"     script: "/bin/echo"     allowed_users: [500050880]

Обратите внимание, я прописал echo в параметр script. Это быстрый (хоть и кривоватый) способ сделать echo-бота. Вы уже можете поговорить с ним. Попробуйте сказать hi, Hi!, -n hi.

Из подобного разговора сразу видно как легко получить уязвимость (-n было интерпретировано как параметр echo). Так же видно как формируются аргументы скрипта: сообщение приводится к нижнему регистру; допустимыми символами считаются буквы, цифры, минус, точка и подчёркивание; все недопустимые символы считаются разделителями.

Полное сообщение тоже доступно. Давайте заменим /bin/echo на простой скрипт и посмотрим переменные окружения:

#!/bin/sh env

Если сказать этому боту Hello! Он покажет переменные окружения

BOT_TEXT=Hello! BOT_FROM_FIRSTNAME=Alexey BOT_NAME=firstBot BOT_CHAT=500050880 BOT_FROM=500050880

Видно, что доступно оригинальное сообщение, имя и ID пользователя, который отправил сообщение, название бота (согласно конфигу; напомню, что движок может обслуживать сразу несколько ботов).

Если бот получает контакт или пересылку сообщения, то к переменным окружения добавляется информация о контакте или авторе оригинального сообщения. Это удобно, когда вы хотите добавить в white list нового пользователя. Чтобы узнать его ID — просто перешлите его контакт или любое его сообщение боту. См. пример в demo.sh.

Обратите внимание, что переменной PATH не видно. Если вам нужны экзотические пути, пропишите их явно в начале скрипта или используйте полные пути.

Скрипт можно чуть усовершенствовать

#!/bin/sh echo '%!PRE' env | sort

Теперь вывод будет преформатированный. Можно использовать и markdown, см. всё тот же demo.sh.

Чтобы ответить картинкой, её достаточно просто вывалить на stdout:

#!/bin/sh curl -qfs https://golang.org/lib/godoc/images/footer-gopher.jpg

Если скрипт не выдаст ничего, то бот отправит сообщение "empty", чтобы бот действительно ничего не ответил, скрипт должен ответить одним единственным символом "точка".

Все примеры можно найти в demo-скрипте, а я бы чуть подробнее остановился бы на асинхронной нотификации.

Бот говорит сам

В боте можно включить HTTP сервер добавлением одной строки bind_address в конфиг:

bots:   firstBot:     token: "22222222:AAAAAAAAAAAAAA"     script: "/bin/echo"     allowed_users: [500050880]     bind_address: ":9091"

Теперь вы можете отправить асинхронное сообщение:

echo "ok" | curl -qfsX POST --data-binary @- "http://:9091/500050880"

То есть, пользователь получит его не в ответ на своё сообщение, а просто как нотификацию. Тело сообщения обрабатывается по тем же правилам, что и аутпут скрипта. То есть, вы можете отправлять форматированный текст и картинки.

Можно использовать и multipart/form-data:

curl -qfsX POST -F to=500050880 -F msg=ok "http://:9091"

Думаю, нет смысла обсасывать каждую деталь работы бота. У вас уже есть достаточно информации, чтобы понять, нужно оно вам или нет. Полный спектр возможностей можно посмотреть, поговорив с demo-сриптом. В конфиге можно указать таймауты для http-клиента и выполнения скрипта. Все опции есть в readme проекта, хотя, думаю, большинству будет комфортно жить и с дефолтами.

Любые вопросы, пожелания, предложения — приветствуются.

Приятного ботостроительства!

Если вы всё ещё читаете…

…, то могу рассказать, как я дошел до жизни такой.

Мы как-то делали очень глубокий редевелопмент системы. Фактически, мы запускали абсолютно новый проект сразу под огромной нагрузкой. Конечно, где могли, мы подстелили соломки. Но у нас не было ресурсов, что бы поддерживать на лету сразу два проекта такого масштаба. То есть мы не имели возможности быстрого переключения на старую версию.

В день старта я уходил домой очень поздно, но мне хотелось держать руку на пульсе постоянно. Мне не подходил сценарий: найти местечко в метро, достать ноут, поднять VPN, посмотреть логи… Хотелось иметь возможность глянуть основные вещи с телефона и, возможно, что-то подтюнить, сбегая по эскалатору.

Я гуглонул, что на это тему знает Интернет, и оказалось, что Telegram предоставляет бесплатное и великолепное API для ботов. Я написал бота-уродца в несколько строчек на bash+curl+jq, который умел выполнять буквально три команды, и поехал домой.

Бот оправдал себя полностью и идея мне очень понравилась. Только реализация полностью на шеле была уж очень кривая и неуклюжая. На досуге, я переписывал эту штуку несколько раз на ноде и питоне, но всё это были какие-то сырые поделки.

Тем временем, я начал использовать таких ботов во многих бытовых делах. У меня есть бот для учёта тренировок и отслеживания прогресса (графики), есть бот для управления домашним микротиком… В конце концов, у меня накопился очень чёткий список фичей, которыми должен обладать бот. А так же, список тупиковых идей, которые выглядят хорошо, но на деле мало полезны.

В 2018 я начал учить Go и, просто для эксперимента, заимплементил движок ботов на Go. Это был мой первый код на новом языке и он был ужасен 🙂 Но, глобально, Go оказался очень удобной штукой для подобных вещей. И вот, поднабравшись опыта в Go, я решал вернуться к этому проекту и переписать его на Go, но уже "правильно" (ну или близко к тому).

Так и появилось это поделье. Почему репа называется cnbot, я так и не смог вспомнить по прошествии лет.

Куда я планирую всё это развивать?

Я подумываю о расширении функциональности, но очень осторожно. Очень не хотелось бы переусложнять. Если вам нужно какое-то специфичное решение, — просто напишите своего бота. А этот движок я хотел бы оставить максимально простым.

Но я бы хотел развивать движок в сторону встраиваемости: выделить из него какую-то простую часть, которую можно было бы подключить библиотекой к любой Go-программе. Условно, если у вас уже есть микросервис для… для чего годно… хоть для рендеринга 3D-сцен, — вы можете в одну-две строчки встроить в него чат бота для оперативной диагностики/мониторинга/управления… Вот это, мне кажется, было бы полезно. На самом деле, вы уже сейчас можете так сделать. Просто это не очень удобно.

ссылка на оригинал статьи https://habr.com/ru/post/530412/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *