Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Идея
Написать telegram бота-помощника на Rust, который будет работать на Raspberry Pi. Идея была давно. До этого изучал Rust и решил применить его здесь.
Существуют разные сервисы, вроде перевода раскладки с одного языка на другой, конвертера unix timestamp в форматированную дату, base64 кодирования, jwt, json validator/prettifier, bin2hex и так далее. Почему бы не переместить эти функции в телеграм бота и пользоваться из одного приложения вместо посещения нескольких ресурсов. Реализовать вроде не сложно. При этом давно валяется без дела Raspberry Pi 2, купленная у коллеги за символическую сумму.
Подготовка и выбор инструментов
Вижу три фронта работ: работа с железом, написание программы и интеграция.
Начнём с железяки aka малинка aka Raspberry PI 2 Model B. Вначале нужно было установить на неё ОС. Делается это с помощью записи образа на карту памяти. Этот процесс описан тут. Выбрал Debian. Подключил малинку к монитору, настроил ssh. После того как ssh настроен, можно убрать плату подальше со стола (поближе к роутеру).
Далее переместился к своему прекрасному, мощному, удивительному и неповторимому компьютеру, где я столько раз проливал чай и кофе, теперь можно подключиться по ssh, и творить дела удалённо. Удалил ненужные пакеты и отключил службы, которые не планирую использовать. Хотел удалить python, но подумал и не стал. Не удаляй python - не совершай ошибку. Python используют другие утилиты и удаление python сделает систему не пригодной для работы. С железякой закончили.
Дальше надо написать простейшее приложение (hello world) на рабочей машине, скомпилировать под платформу arm, выгрузить на Raspberry Pi и запустить. Добавлю подробностей. Рабочий компьютер это x86 архитектура, а Raspberry Pi это arm. Если коротко то, нельзя просто так скомпилировать программу на одной архитектуре, а исполнить на другой. Умные люди придумали кросс-компиляторы. Это программы, которые собирают программу под целевую (target) платформу. Помучавшись со сборкой libc и openssl, нашёл проект cross - zero setup cross compilation and cross testing, который решил все проблемы.
cross build --release --target arm-unknown-linux-musleabihf
так выглядит команда на сборку под Raspberry Pi. Под капотом у cross работает docker. Указываете target и cross выкачивает нужный образ и собирает проект. Изящно, не правда ли?
Есть ряд настроек, которые позволяют уменьшить размер бинарника.
[profile.release]
strip = true
opt-level = "z"
lto = true
codegen-units = 1
теперь можно быстрее выгружать бинарник по ssh. Деплоить Rust приложение - одно удовольствие. Бинарник достаточно перенести на платформу и запустить. Также добавил .env файл, чтобы задать переменные окружения. В systemd файле конфигурации /etc/systemd/system/bezzabot.service указал .env файл. Из него будут загружены пeременные окружения, необходимые для работы приложения.
[Service]
ExecStart=/srv/bezzabot/bezzabot
ExecReload=bash -c "/srv/bezzabot/bezzabot"
User=radio
EnvironmentFile=/srv/bezzabot/.env
Restart=always
RestartSec=2
Считаем, что вопрос со сборкой и deploy приложения временно решен.
Регистрация telegram бота
Перейдём к регистрации бота, домена, сертификатам. Это была самая ненавистная часть, но, как оказалось, зря я её ненавидел. Выбрал webhooks вместо long-polling как способ коммуникации бота. В таком случае telegram требует https со всеми вытекающими. Я являюсь счастливым обладателем роутера keenetic zyxel и в dashboard обнаружил пункт меню Domain name. Оказалось Keenetic предоставляет доменное имя 4-го уровня. Вместе с сертификатом. Кайф. Зарегистрировал доменное имя и пробросил порты до raspberry. Ещё одна проблема решена малой кровью.
Как регистрировать бота в телеграм рассказывать не буду, а оставлю ссылку.
Бот зарегистрирован, webhook настроен, https работает. Переходим к созданию бота.
Создание бота
Сэкономить время можно на реализации клиента для API. Несмотря на то, что для текущей задачи не нужна большая функциональность я бы не хотел ограничивать себя в будущем. Первой ссылкой по теме telegram bot rust выпадает teloxide. Пример с командами это почти все, что мне нужно.
Определяете набор команд. Определяете реакцию на команды. Теперь к деталям. По-умолчанию teloxide работает в long-polling режиме, и поэтому надо (мне надо) перенастроить на webhook-mode. Смотрите пример здесь. А дальше пишем логику. Единственное, что хочу отметить это парсинг аргументов. В моем случае команды содержат обязательные и необязательные параметры. Пользователь может задать лишние параметры, перепутать, ввести ерунду. Я использую поле parse_with макроса BotCommand, в которой указываю собственную функцию для разбора аргументов.
#[derive(BotCommands, Debug, Clone)]
#[command(rename_rule = "lowercase", description = "Доступные команды:")]
pub enum BotCommand {
#[command(description = "Отображает этот текст")]
Help,
#[command(parse_with = skb_parser, description = "йцукен -> qwerty")]
Skb(
String,
Layout,
FromLanguage,
ToLanguage
),
...
}
Доступны 3 команды, не считая help:
/skb — Превращает йцукен в qwerty. Пример: /skb йцукен
/utime — Превращает unix timestamp в дату в формате %Y-%m-%d %H:%M:%S
/winner — Выбирает случайный id из списка. Пример: /winner 1 2 3 4 5
В планах добавить ещё. Кстати, если есть идеи команд - буду рад рассмотреть и реализовать. В завершении отмечу, что создать dev-окружение для бота не составило труда. Я создал второго бота, ещё один домен и пробросил порт до рабочей машины.
В качестве заключения хочется сказать, что создание простого telegram бота на Raspberry Pi это совсем не сложно и даже весело.
Ссылки
Код проекта Bezzabot - Helper for developers
Bezzabot - Telegram
Teloxide - library to build Telegram bots on Rust
How Do I Create a Bot?
Botfather
Asynchronous Programming in Rust
How to Set Up a Raspberry Pi for the First Time
Minimizing Rust Binary Size
Telegram Bot API
Cross - zero setup cross compilation
Rust
Характеристики Raspberry Pi