Files
obsidian-vault/personal/projects/zulip-router.md
T

4.7 KiB
Raw Blame History

Zulip Router

Последнее обновление: 2026-06-16

Цель

Event-роутер между Zulip и balda-ботами (Валера, Клавдий). Решает проблему конкурентного получения событий — сейчас оба бота видят все сообщения одновременно.

Проблема (root cause)

  • Каждый balda-бот регистрирует собственную event queue в Zulip Events API
  • Без роутера оба получают все сообщения, и каждый может ответить на @mention другого
  • extractOtherMention() патч в коде — костыль, не решает проблему полностью

Как сейчас (до роутера)

Zulip
  ├── Events API ← Валера (valera-bot, poll на :8091) — отключён
  ├── Events API ← Клавдий (claudio-bot, poll на :8092) — отключён
  └── Webhook    → оба (outgoing webhook через @mention)

Архитектура (с роутером)

Zulip Event Queue
    ↓ poll (credentials Eagle из ~/.hermes/config.yaml)
[zulip-router]           (~/Docker/zulip-router/)
    ├── @Валера / @Valera          → POST http://balda-agent-valera-1:8091/zulip/webhook
    ├── @Клавдий / @Klavdiy        → POST http://claudio-agent-claudio-1:8092/zulip/webhook
    └── (default / unknown)        → POST http://balda-agent-valera-1:8091/zulip/webhook
         ↕ ownership: stream+topic → bot (TTL 24h, persisted to /data/ownership.json)

Ключевое: credentials — Eagle/Орла (не новый бот). Роутер регистрирует свою event queue (отдельную от очереди Eagle).

Правила маршрутизации

  1. @Валера или @Valera в тексте → Валера (+ ownership обновляется)
  2. @Клавдий или @Klavdiy в тексте → Клавдий (+ ownership обновляется)
  3. Топик уже у кого-то → туда же (TTL refreshed)
  4. Новый топик без @mention → Валера (default)
  5. reset без @mention → только владельцу топика

Что меняется в balda

После деплоя роутера Events API polling уже отключён у обоих ботов (сделано 2026-06-16):

zulip:
  events_polling:
    enabled: false

Сообщения приходят только через webhook от роутера.

Код

Репозиторий: ~/Developer/zulip-router/ — Go, ~260 LOC (план)

Deploy: ~/Docker/zulip-router/docker-compose.yaml

Файл Назначение
main.go Poll loop, routing, dispatch
config.go Config struct + YAML loading + env var expansion
zulip.go Zulip API client (register_queue, get_events, long-poll)
ownership.go Topic ownership store (RW mutex + JSON persistence)
forwarder.go HTTP POST к balda webhook endpoints

Deployment

Compose: ~/Docker/zulip-router/docker-compose.yaml

Credentials: Eagle, не новый бот

Роутер использует credentials Eagle/Орла из ~/.hermes/config.yamlplatforms.zulip.

Не создавать нового бота. Eagle уже имеет права на чтение всех публичных стримов.

Env vars

Создать ~/Docker/zulip-router/.env:

# Credentials Eagle/Орла — из ~/.hermes/config.yaml
ZULIP_BOT_EMAIL=eagle-bot@zulip.qentra.top
ZULIP_API_KEY=<скопировать из конфига Eagle>

# Куда форвардить (Docker DNS, сеть balda_default)
VALERA_WEBHOOK=http://balda-agent-valera-1:8091/zulip/webhook
CLAUDIO_WEBHOOK=http://claudio-agent-claudio-1:8092/zulip/webhook

Запуск

cd ~/Docker/zulip-router
docker-compose up -d
docker logs zulip-router --tail 20   # проверить poll loop

TODO

  • Написать код роутера (~260 LOC)
  • Создать compose ~/Docker/zulip-router/docker-compose.yaml
  • Набить .env с credentials Eagle (из ~/.hermes/config.yaml)
  • docker-compose up -d
  • Проверить логи: docker logs zulip-router --tail 50
  • Протестировать: @Клавдий и @Валера в разных топиках
  • Проверить ownership: сообщение в топик без @mention → последний бот
  • Удалить extractOtherMention() патч из кода (больше не нужен)