Простой телеграмм бот на sh, или ещё одно применение старому роутеру

в 12:16, , рубрики: OpenWrt, shell-скрипт, telegrambot

Лежит старый роутер без дела. Почему бы ему не стать сервером для простого телеграмм бота?

В моём случае роутер — копеечный tp link tl-wr740N 4/32 мегабайта, поэтому наш бот не будет использовать каких-либо фреймворков или библиотек. Благодоря telegram api нам достаточно уметь отправлять и принимать https запросы. Поэтому вместо использования какого-либо ЯП мы будем использовать обычный скрипт(однако я изначально планировал использовать с++, потому что мне он роднее по синтаксису чем sh).

Как мы будем взаимодействовать с telegram api?

Как я сказал выше, кроме https нам по факту ничего не надо. А чтобы работать с https есть много различных утилит, но остановимся на wget. Почему на wget, вы узнаете ниже.

Протоколы http и https отличаются только буковкой в названии(с).

Как следует из цитаты выше, https это тот же http. А как работает http? Правильно, http просто отсылает по tcp строки и какие-нибудь пары ключ-значение. Конечно, это не полное описание работы протокола, но для общего понимания процесса этого достаточно.

Делаем простой https запрос в telegram api и получаем полезную информацию

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

#!/bin/sh
TOKEN="ваштокен"
wget "https://api.telegram.org/bot$TOKEN/getMe"
cat getMe

Запускаем скрипт, у нас скачивается файл getMe. Не пугаемся, это ответ на наш запрос. Далее мы должны увидеть следущее:

{"ok":true,"result":{"id":4220331631,"is_bot":true,"first_name":"test","username":"some_bot","can_join_groups":true,"can_read_all_group_messages":false,"supports_inline_queries":false,"can_connect_to_business":false,"has_main_web_app":false}}

это и есть собственно ответ на запрос. Теперь мы знаем про нашего бота чуть больше чем ничего. Кстати, это json, а значит можно удобно с ним работать. Но в этой статье такого не будет))

Непосредственно к сути бота

Наш бот будет очень простым. Если мы напишем определённое слово, бот будет писать сообщение в ответ.

В telegram api есть метод getUpdates, который даёт нам информацию о том, кто нашему боту написал и т.д. Заменим в нашем скрипте getMe на getUpdates, зайдём в телеграмм и напишем в личку нашему боту что-нибудь, далее запустим скрипт и получим примерно такой результат:

"message":{"message_id":1,"from":{"id":53773747,"is_bot":false,"first_name":"sigma","last_name":"petrovich","username":"ladno","language_code":"ru"},"chat":{"id":598727336,"first_name":"sigma","last_name":"petrovich","username":"ladno","type":"private"},"date":1732132307,"text":"sayhello"}}]}

Это отрывок из всего ответа, однако сути это не меняет. Тут мы видим, что боту какой-то юзер написал сообщение sayhello. Мы уже можем проверить, совпадает ли сообщение с заданным или нет. Также нам понадобится chat_id, чтобы послать ответ тому, кому нужно.

Чтобы послать сообщение, нам нужен метод sendMessage, однако нам нужно послать и chat_id и текст сообщения, поэтому мы используем опцию --post-data

wget --post-data="chat_id=idчата&text=сообщение" "https://api.telegram.org/bot$TOKEN/sendMessage"

получаем следущий ответ:

{"ok":true,"result":{"message_id":11119,"from":{"id":79999991,"is_bot":true,"first_name":"test","username":"some_bot"},"chat":{"id":59000036,"first_name":"sigma","last_name":"petrovich","username":"ladno","type":"private"},"date":173211984,"text":"fard"}}

Этот ответ говорит нам о том, что сообщение отправлено успешно. Однако мы в скрипте не будем читать это сообщение для простоты.

Теперь можно описать логику работы бота:

  1. вызываем getUpdates

  2. отбрасываем из ответа ненужное с помощью tail -n1(оставляем последнюю строку)

  3. если текст сообщения соответствует заданой строке, посылаем ответ(вычленяя перед этим chat_id)

  4. повторяем

Заставляем это всё работать на роутере

Основная проблема дешёвых роутеров — нехватка памяти. В openwrt по-умолчанию нет curl, но есть wget, поэтому используем именно его. Однако и тут проблема: по дефолду wget на Openwrt не умеет в https, нам нужно установить libustream-openssl. И тут очередная проблема — мы не можем эту либу поставить т.к нет места. Ладно, выбрасываем дефолдный образ с luci, ищем imagebuilder и собираем минимальный образ без лишних(для нас) пакетов. Перекидываем скрипт на роутер и запускаем, всё должно заработать. Далее нужно наладить запуск скрипта по нажатию кнопки. Можно конечно сделать чтобы скрипт сразу стартовал после загрузки openwrt, но безопаснее будет запуск скрипта по нажатию определённой кнопки, благо даже на таком дешёвом роутере как tp link tl-wr740N есть кнопка wps. Открываем оф, сайт openwrt и смотрим hotplug.d. Пишем-пишем и всё тестируем. Работает — прекрасно. Теперь у вас есть бот, который будет отвечать на сообщения

Вывод

Мы сделали маленького и простого тг бота без фреймворков и умудрились это всё запустить на роутере. Далее можно этого бота научить делать более сложные вещи, например парсить инфу с каких-нибудь сайтов(например, расписание занятий). Да, алгоритм работы этого бота ужасен: бот уже с двумя пользователями будет работать плохо, а именно может не ответить на сообщение. Однако у нас тут не цель переписать фреймворк на шелл скрипт, основная наша цель — простота и минималистичность. Вот, кстати, ссылка на репозиторий с ботом.

Автор: erfty

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js