Files
2026-05-27 09:55:11 +09:00

7.6 KiB
Raw Permalink Blame History

Как мы делали мост между Telegram и MAX: боль, баги и 385 рестартов

Привет, Пикабу! Хочу рассказать про наш опыт создания бота-моста между Telegram и MAX (бывший VK Teams). Может кому-то пригодится — или хотя бы посмеётесь.

Зачем это вообще нужно

MAX — это новый российский мессенджер от VK. Многие компании и сообщества начали туда переезжать, но часть людей осталась в Telegram. Нужно было связать чаты так, чтобы сообщения из одного мессенджера автоматически пересылались в другой. Написали бота на Go, задеплоили — и понеслось.

Проблема 1: Видео приходит как «document» без расширения

Когда кто-то отправляет видео в Telegram без сжатия (как файл), оно приходит не как Video, а как Document с MIME-типом video/mp4. Наш бот честно пересылал его в MAX как файл с именем «document». Без расширения. MAX показывал это как непонятный файл, который нельзя посмотреть.

Решение: проверяем MIME-тип документа. Если video/* — загружаем как видео, а не как файл. Плюс генерируем нормальное имя из MIME-типа, если оригинальное отсутствует.

Проблема 2: MAX API ложится, бот встаёт колом

MAX API периодически тайматутится. Причём не на всё, а на конкретные запросы — отправка сообщений зависает на минуту и возвращает timeout. Наш бот обрабатывал сообщения синхронно — один зависший запрос блокировал ВСЮ очередь. Пока один чат тайматутился, остальные 60+ чатов стояли. Даже /start не отвечал.

Решение: перенесли пересылку в горутины. Добавили circuit breaker — после 3 фейлов подряд чат блокируется на 5 минут. И retry-очередь в SQLite — если сообщение не отправилось, оно сохраняется в базу и отправляется позже.

Проблема 3: 385 рестартов за ночь

Добавили подробное логирование для отладки. В логах писали msg.From.ID — ID отправителя. Всё работало... пока не пришёл пост из канала. У канальных постов в Telegram нет поля From — оно nil. nil.ID = panic. Бот упал, systemd перезапустил, пришёл следующий пост из канала — опять panic. И так 385 раз за ночь.

Решение: банальная проверка на nil. Теперь используем safe getter: if msg.From != nil { return msg.From.ID }. Стыдно, но факт — одна строка уронила продакшн.

Проблема 4: Любой мог удалить чужие связки каналов

Команда /crosspost показывала ВСЕ связки каналов ВСЕМ пользователям. С кнопками «Удалить». Любой, кто написал боту в личку, мог увидеть и удалить чужие связки. Мы обнаружили это когда у пользователя «пропали» 5 каналов. Сначала думали — баг. Оказалось — кто-то просто нажал кнопку.

Решение: добавили owner_id — кто создал связку, тот ей и управляет. Причём пришлось хранить два ID (TG и MAX), потому что у одного человека разные ID в разных мессенджерах. Плюс soft delete — теперь удалённые связки не стираются, а помечаются. Всегда можно посмотреть кто и когда удалил.

Проблема 5: Замедление Telegram API

Telegram API из России работает с задержками. Файлы скачиваются медленно, запросы тайматутятся. Подняли свой Telegram Bot API сервер (https://github.com/tdlib/telegram-bot-api) на зарубежном сервере. Но тут начались приключения:

  • Без флага --local файлы не отдаёт (404)
  • С флагом --local файлы сохраняются на диск, но API возвращает локальный путь вместо URL
  • Docker создаёт файлы с ограниченными правами — nginx не может их прочитать
  • Webhook зарегистрировался одновременно и на api.telegram.org, и на наш сервер — каждое сообщение приходило дважды

Решение: nginx на том же сервере раздаёт файлы с диска, Bot API на соседнем порту. Для MAX→TG пришлось скачивать файлы на наш сервер и загружать в TG как bytes — потому что наш TG Bot API сервер не видит MAX CDN.

Проблема 6: MAX webhook не присылает сообщения

Переключились с polling на webhook для мгновенной доставки. Всё настроили, webhook зарегистрировался, nginx проксирует — а сообщения не приходят. Приходят только удаления и события входа/выхода. Оказалось, MAX API при подписке без явного списка типов обновлений НЕ включает message_created по умолчанию. Нужно явно указывать.

Решение: передаём полный список типов при подписке: message_created, message_edited, message_removed, message_callback и т.д.

Что в итоге

Бот работает, пересылает текст, фото, видео, GIF, стикеры, голосовые, файлы, кружки. Поддерживает редактирование, удаление, ответы, форматирование. Кросспостинг каналов в обе стороны. 70+ связанных чатов.

Стек: Go, SQLite, MAX Bot API SDK, Telegram Bot API, systemd, nginx.

Исходники открыты: https://github.com/BEARlogin/max-telegram-bridge-bot (CC BY-NC 4.0)

Если кому нужно связать свои TG и MAX чаты — боты:

Главный вывод: мессенджер-мосты — это не «просто пересылка текста». Это зоопарк edge-кейсов, кривых API, таймаутов и nil pointer'ов. Но работает!