Бот для Telegram
В Telegram с 24 июня 2015 появились боты, а точнее Telegram Bot API. То есть, теперь мою прошлую задачу получения статуса сервера можно решить гораздо удобнее.
This article in english 🇺🇸.
Бот не является “пользовательским аккаунтом”, ему не нужен номер телефона, и самое главное - не нужно ставить клиентское приложение для Telegram на сервере или где вы хотите его использовать. Бот для Telegram - это ну как бы и есть API - веб-запросы к серверам Telegram. Механизм обработки запросов и отправки ответов лежит на вас, как на владельце бота.
Официальная документация по ботам здесь: https://core.telegram.org/bots
Создание бота
Нужно написать самому главному боту - BotFather:
…и уважительно попросить создать нового бота:
После этого бот будет создан. Обратите внимание на токен - по нему осуществляется доступ к боту, так что светить этот токен нельзя, иначе кто угодно сможет получить доступ к сообщениям бота (перехватывать запросы и отправлять свои ответы).
Сейчас, когда у вас уже создан бот и получен токен, я могу на примере продемонстрировать, что конкретно имел в виду под словами “это ну как бы и есть API”. Откройте браузер и перейдите по такому адресу:
https://api.telegram.org/botТУТВАШТОКЕН/getMe
В браузере отобразится примерно такое:
{"ok":true,"result":{"id":ТУТБУДЕТID,"first_name":"someTestBot","username":"someTestBot"}}`
Для большей наглядности, вот скриншот браузера:
Вот что такое бот в Telegram. Вы отправляете веб-запрос и получаете на него JSON-ответ.
Разумеется, нам нужно автоматизировать как отправку запросов, так и разбор JSON-ответов, потому нужна программная реализация бота, которая будет работать на каком-нибудь сервере (можно и на домашнем компе, но тогда, очевидно, бот будет доступен только когда будет включен компьютер). И для этой цели можно выбрать абсолютно любой язык программирования, поддерживающий отправку веб-запросов, ведь, как я уже сказал и продемонстировал - работа с ботом это всего лишь отправка веб-запросов и разбор ответов.
Реализация бота
Я выбрал язык Python. Выбор далеко не случаен. Дело в том, что для Python уже есть готовая библиотека, существенно облегчающая реализацию бота - это pyTelegramBotAPI. Собственно, в ней сделано уже всё, что требуется для отправки веб-запросов и получения ответов, вам остаётся только описать команды, которые ваш бот будет уметь выполнять. Однако, какое-то понимание всё же потребуется, потому настоятельно рекомендую изучить документацию по API: https://core.telegram.org/bots/api
Итак, вам нужно поставить Python и какую-нибудь IDE (хотя, конечно, можно и в Блокноте). Вот что у меня:
Итак, у вас установлен Python и pip, ставим pyTelegramBotAPI:
pip install pyTelegramBotAPI
Теперь создаём файл someTestBot.py
, в котором и будет описан функционал бота. Я определил две обязательных команды /start
и /help
, а также команду отправки статуса сервера /server
(забегая вперёд, она предназначена для запуска в Linux, так что при тестировании на Windows её вызов зафейлится):
import telebot # подключение библиотеки pyTelegramBotAPI
import logging # библиотека журнала
# для запуска скриптов
from subprocess import call
# настройки для журнала
logger = logging.getLogger('log')
logger.setLevel(logging.INFO)
fh = logging.FileHandler('someTestBot.log')
fh.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s | %(levelname)-7s | %(message)s")
fh.setFormatter(formatter)
logger.addHandler(fh)
# создание бота с его токеном API
bot = telebot.TeleBot("ТУТВАШТОКЕНОТBOTFATHER")
# текст справки
help_string = []
help_string.append("Это простой *тестовый бот*, созданный в обучающих целях.\n\n")
help_string.append("/start - выводит приветствие;\n")
help_string.append("/help - отображает эту справку;\n")
help_string.append("/server - присылает статус сервера.")
# --- команды
@bot.message_handler(commands=['start'])
def send_start(message):
# отправка простого сообщения
bot.send_message(message.chat.id, "Привет, я тестовый бот! Отправьте мне /help для вывод справки.")
@bot.message_handler(commands=['help'])
def send_help(message):
# отправка сообщения с поддержкой разметки Markdown
bot.send_message(message.chat.id, "".join(help_string), parse_mode="Markdown")
@bot.message_handler(commands=['server'])
def send_server(message):
try:
# по этому пути на сервере лежит скрипт сбора информации по статусу сервера
call(["/root/scrps/status.sh"])
# читает файл с результатами выполнения скрипта
status = open("/root/scrps/status.txt", "rb").read()
bot.send_message(message.chat.id, status, parse_mode="Markdown")
except Exception as e:
logger.exception(str(e))
bot.send_message(message.chat.id, "Ошибка при получении статуса сервера. Подробности в журнале.")
# запуск приёма сообщений
bot.polling()
Скрипт сбора информации о статусе сервера status.sh
я взял из прошлой статьи и немного изменил:
#!/bin/bash
scrps_path=/root/scrps
info_web="*Web-servers*
----------------------
$(service apache2 status | sed -r "s/[*]+/-/g")
$(service nginx status | sed -r "s/[*]+/-/g")
"
info_mysql="*MySQL*
----------------------
$(mysqladmin ping)
$(mysqladmin status)
"
info_cpu="*CPU*
----------------------
$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1" of 100 percents"}')
"
info_ram="*RAM*
----------------------
free: $(free -m | grep Mem | awk '{print $4}') MB of $(free -m | grep Mem | awk '{print $2}') MB total
"
info_space="*HDD*
----------------------
$(df -h --output=source,size,used,avail | head -n2)
"
text=$(printf "$info_web$info_mysql$info_cpu$info_ram$info_space")
printf '%s\n' "$text" > ${scrps_path}/status.txt
Его надо поместить на сервере по пути /root/scrps/status.sh
, либо каком другом, но тогда надо не забыть изменить его и в исходниках бота.
На этом реализация бота закончена.
Возвращаемся к BotFather, указываем ему команды, которые знает бот:
Размещение и запуск бота на сервере
Ну, во-первых, вы уже можете запустить бота у себя на компьютере - нужно открыть командную строку в том каталоге, где лежит someTestBot.py
, и выполнить python someTestBot.py
. Если это Windows, появится “чёрное окно”, которое будет означать, что бот уже работает. Найдите в Telegram пользователя @someTestBot (у вас своё имя, очевидно), и можно уже с ним переписываться:
Как я и говорил, команду /server
в Windows он обработать не смог, и пойманное исключение записалось в журнал.
Кстати, обратите внимание - приложение показывает подсказки о всех командах бота, которые мы добавили через BotFather:
Теперь задача, как сделать так, чтобы бот работал постоянно. Идём на сервер с Linux, создаём каталог /usr/local/bin/someTestBot/
, кладём в него наш someTestBot.py
. Кстати, на сервере тоже должен быть установлен pyTelegramBotAPI (разумеется, Python и pip тоже).
Я расскажу о двух способах, как запустить скрипт в качестве сервиса: Supervisor
и systemd
.
Supervisor
Устанавливаем Supervisor:
sudo apt-get install supervisor
Создаём конфиг для процесса (/etc/supervisor/conf.d/someTestBot.conf
):
[program:someTestBot]
directory=/usr/local/bin/someTestBot
command=python someTestBot.py
autostart=true
autorestart=true
С таким конфигом, надо полагать, бот будет “выполняться” с root
правами, что некруто. Скорее всего, можно задать, с какими правами это будет работать. Ну да ладно, нам же надо скорее в продакшн, так что запускаем:
supervisorctl update
supervisorctl restart someTestBot
systemd
А можно ничего и не устанавливать, если в системе используется systemd
.
Создаём конфиг:
vi /etc/systemd/system/telegram-bot-sometestbot.service
С таким содержанием:
[Unit]
Description=Telegram bot someTestBot
[Service]
WorkingDirectory=/usr/local/bin/someTestBot
ExecStart=/usr/bin/python3 /usr/local/bin/someTestBot/someTestBot.py
Restart=always
RestartSec=10
SyslogIdentifier=python-someTestBot
User=someTestBot
[Install]
WantedBy=multi-user.target
В User=someTestBot
можно и root
указать, но я рекомендовал бы создать под это отдельного юзера. Правда, тогда чтобы работали скрипты, надо будет дать этому пользователю доступ к mysqladmin
.
Включаем нашу только что созданную службу:
systemctl enable telegram-bot-sometestbot.service
systemctl start telegram-bot-sometestbot.service
Ну всё, бот работает, проверяем:
Тестового бота @someTestBot, используемого для статьи, я удалил. Если кто-то в будущем займёт этот юзернейм, то это не я.
Что ещё можно сделать? Ну, вот эта строка - bot.polling()
- в общем-то, означает бесконечно выполняющийся цикл запросов к серверам Telegram, что не очень правильно в плане потребления ресурсов на обеих сторонах. Лучше сделать так, чтобы приложение бота ожидало сообщения от Telegram. Это можно сделать, реализовав webhook. Когда доберусь до этого, дополню статью.
Наконец-то запилил инструкцию на webhook. Решил не добавлять здесь, а запостить новую статью.
Social networks
Zuck: Just ask
Zuck: I have over 4,000 emails, pictures, addresses, SNS
smb: What? How'd you manage that one?
Zuck: People just submitted it.
Zuck: I don't know why.
Zuck: They "trust me"
Zuck: Dumb fucks