GasApp

Боты GasApp

Бот — отдельный аккаунт, который ведёт ваша программа. Ему пишут, он отвечает; его можно назначить администратором канала, и тогда он пишет в канал, одобряет заявки в закрытый канал и удаляет подписчиков. Что именно бот делает, решает его код.

Чем это отличается от ботов Telegram

В Telegram бот ходит на сервер по токену, и сервер действует за него — сервер видит всё, что видит бот. В GasApp сервер содержимого не видит, поэтому и за бота он ничего делать не может: у бота свои ключи, и всё шифрование происходит на его стороне.

Отсюда устройство:

ваш код (любой язык) ⇄ строки JSON ⇄ gasapp-bot ⇄ TLS ⇄ сервер GasApp

gasapp-bot — движок: он хранит ключи бота, шифрует и расшифровывает. Ваш код запускает его как дочерний процесс, пишет команды в его стандартный ввод и читает ответы и события из стандартного вывода.

Что есть: переписка, кнопки под сообщениями, каналы (включая закрытые: заявки, подписчики), команды по HTTP и веб-хуки.

Чего нет:

Как завести бота

  1. Нужен аккаунт с премиумом (его выдаёт оператор сервера). Ботов у аккаунта — не больше 20 разом, токенов — не больше 20 в сутки. 🔐 Боты живут, пока у владельца есть премиум: когда оператор его снимает, боты аккаунта удаляются.
  2. В приложении: Каналы → Создать → Мои боты → Создать бота. Имя бота кончается на bot. Приложение покажет строку вида gasapp-bot:имя_bot:… — это одноразовый токен, он действует час.
  3. На машине, где бот будет работать:

     cargo build --release -p gasapp-bot        # из каталога crates/
     gasapp-bot init --server https://ваш.сервер --data ./mybot --token 'gasapp-bot:имя_bot:…'

    init регистрирует бота и кладёт его ключи в каталог ./mybot.

  4. Запуск: gasapp-bot run --data ./mybot — обычно его запускает ваш код (см. примеры в crates/gasapp-bot/bots/).

Удалить бота — там же, в приложении. У одного владельца не больше 20 ботов; удалён владелец — удалены и его боты.

Как людям начать разговор с ботом

Написать боту по имени можно, только когда его ключ простоял в журнале ключей сутки. Раньше — по ссылке-контакту бота: её отдаёт команда getMe (contact_link), автор публикует её там, где людям видно, что это он, а человек вставляет её в приложении в «Новый чат» вместо имени. Ссылка несёт ключ бота, поэтому верить ей стоит ровно настолько, насколько месту, где она опубликована.

Протокол

Одна строка — один объект JSON.

Команда и ответ:

→ {"id": 1, "method": "sendMessage", "params": {"to": "alice", "text": "привет"}}
← {"id": 1, "ok": true, "result": {"message_id": "…"}}
← {"id": 2, "ok": false, "error": "peer_unconfirmed"}

id — любое значение; оно возвращается в ответе. Событие приходит без id, с полем event. Движок обходит сервер раз в несколько секунд (--poll, по умолчанию 5, не чаще 2).

Три способа разговаривать с движком

СпособЗапускКомандыСобытия
Строки JSONgasapp-bot run --data ./mybotв стандартный вводиз стандартного вывода
HTTP… --listen 127.0.0.1:8081POST /sendMessage, параметры — JSON в телеGET /getUpdates
HTTP + веб-хук… --listen 127.0.0.1:8081 --webhook https://ваш.бот/hookкак вышедвижок сам шлёт POST на ваш адрес

Ответ на команду по HTTP — тот же JSON ({"ok": true, "result": …}). getUpdates отдаёт накопившиеся события разом и не ждёт: опрашивайте его раз в секунду-две. Веб-хук получает по одному событию в запросе; ответ 2xx — «принято», иначе движок повторит на следующем обходе.

curl -X POST http://127.0.0.1:8081/sendMessage \
     -H 'Content-Type: application/json' \
     -d '{"to": "alice", "text": "привет"}'

🔐 Кто шлёт движку команды, тот управляет ботом. Без --secret движок слушает только адрес своей машины. С --secret S каждая команда обязана нести заголовок Authorization: Bearer S, а веб-хук получает X-GasApp-Bot-Secret: S — так ваш код отличает движок от посторонних. Сам интерфейс — открытый HTTP: наружу его выставляют только за своим обратным прокси с TLS.

🔐 Секрет и токен — переменными окружения. Командную строку процесса видят другие пользователи той же машины (ps), поэтому вместо --secret и --token задавайте GASAPP_BOT_SECRET и GASAPP_BOT_TOKEN. Каталог бота движок создаёт доступным только владельцу: в нём база и её ключ.

🔐 Запросы из браузера движок не принимает — даже с верным секретом. Иначе страница, открытая на машине бота, управляла бы им через 127.0.0.1. Отсюда три правила для вашего кода: команда — POST с Content-Type: application/json (либо без тела); в Host — тот адрес, на котором движок слушает; без заголовков Origin и Sec-Fetch-*. Обычные HTTP-библиотеки и curl так и делают.

⚠️ Это не веб-хук Telegram: событие отправляет не сервер GasApp (он ничего не видит), а движок на вашей машине. Он должен работать.

Кнопки

К сообщению бота можно приложить ряды кнопок — до 8 рядов по 4 кнопки:

{"method": "sendMessage", "params": {
  "to": "alice", "text": "Одобрить заявку?",
  "buttons": [[{"text": "Да", "data": "approve:42"}, {"text": "Нет", "data": "decline:42"}],
              [{"text": "Правила", "url": "https://example.org/rules"}]]}}

🔐 Кнопки и нажатия едут внутри сквозного шифрования, сервер их не видит. Движок принимает нажатие, только если бот сам предложил кнопку с такими данными под этим сообщением: прислать «нажатие» с выдуманными данными собеседник не может.

События

eventПоляКогда
messagefrom, text, chat_id, message_id, atБоту написали. from — имя, если оно известно
callbackfrom, chat_id, message_id, dataНажата кнопка с данными под сообщением бота
postchannel_id, postВ канале, который бот читает, новая запись (не его собственная)
join_requestchannel_id, account_id, username, known_contact, in_key_logЗаявка в закрытый канал, который бот ведёт
joinedchannelЗаявку самого бота одобрили: канал добавлен

Команды

О себе и переписка

МетодПараметрыЧто делает
getMe—Имя, устройство и ссылка-контакт бота
sendMessageto, text, buttonsСообщение человеку по имени; buttons — необязательные кнопки
setButtonsto, message_id, buttonsЗаменить либо убрать ([]) кнопки под своим сообщением
addContactlinkДобавить контакт по его ссылке (подтверждает ключ)
trustContactusername⚠️ Поверить серверу, что это ключ этого имени
acceptNewKeyusername⚠️ Принять новый ключ собеседника после identity_changed (он переустановил приложение или восстановился из копии — либо ключ подменили); затем trustContact
contacts—Контакты бота

Каналы: читать

МетодПараметрыЧто делает
channels—Каналы бота: роль, закрытый ли
joinChannellinkВойти в открытый канал по ссылке
requestJoinlinkПодать заявку в закрытый канал
pendingJoins—Заявки бота, ждущие ответа
syncChannelchannel_idЗабрать новое прямо сейчас
postschannel_id, limitПоследние записи
leaveChannelchannel_idУйти из канала

Каналы: вести (бот — администратор)

МетодПараметрыЧто делает
adminRequestchannel_idЗаявка на администрирование — её вставляет владелец канала
publishPostchannel_id, textЗапись в канал
editPostchannel_id, seq, textИсправить запись
deletePostchannel_id, seqУдалить запись
pinPostchannel_id, seqЗакрепить (0 — снять). Только владелец канала
createInvitechannel_idНовая ссылка-приглашение закрытого канала
inviteschannel_idСвои ссылки-приглашения
revokeInvitechannel_id, linkОтозвать ссылку
joinRequestschannel_idЗаявки, ждущие ответа
approveJoinRequestchannel_id, account_idОдобрить: заявитель получает ключ чтения
declineJoinRequestchannel_id, account_idОтклонить
subscriberschannel_id, afterПодписчики, страницами по 100
removeSubscriberchannel_id, account_idУдалить из канала
bannedchannel_idУдалённые
restoreSubscriberchannel_id, account_idРазрешить удалённому снова подать заявку

Ошибки

network — сервер недоступен, повторите позже · forbidden — нет права · not_found · conflict · bad_request — негодная команда · peer_unconfirmed — ключ собеседника не подтверждён · identity_changed — у собеседника сменился ключ · error — прочее.

Как сделать бота администратором канала

  1. Бот входит в канал: joinChannel (открытый) либо requestJoin (закрытый — и вы одобряете его заявку, как любую другую).
  2. Бот вызывает adminRequest и отдаёт вам строку gasapp://channel-admin/….
  3. Вы в приложении: канал → ⋯ → Администраторы → Добавить и вставляете эту строку.
  4. После следующего обхода бот видит роль admin в channels.

🔐 Что нужно знать автору бота