120 lines
5.2 KiB
Markdown
120 lines
5.2 KiB
Markdown
# Zulip Router
|
||
|
||
_Последнее обновление: 2026-06-16_
|
||
|
||
## Цель
|
||
|
||
Event-роутер между Zulip и balda-ботами (Валера, Клавдий).
|
||
Решает проблему конкурентного получения событий — сейчас оба бота через Events API видят все сообщения одновременно.
|
||
|
||
## Проблема (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 bot_type=3 через @mention)
|
||
```
|
||
|
||
## Архитектура (с роутером)
|
||
|
||
```
|
||
Zulip Event Queue
|
||
↓ poll (отдельный бот-роутер или reuse одного из существующих)
|
||
[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)
|
||
```
|
||
|
||
**Важно:** таргеты — не Hermes инстансы, а balda-боты (Go бинарники). У каждого уже есть webhook endpoint `/zulip/webhook`.
|
||
|
||
## Правила маршрутизации
|
||
|
||
1. `@Валера` или `@Valera` в тексте → Валера (+ ownership обновляется)
|
||
2. `@Клавдий` или `@Klavdiy` в тексте → Клавдий (+ ownership обновляется)
|
||
3. Топик уже у кого-то → туда же (TTL refreshed)
|
||
4. Новый топик без @mention → Валера (default)
|
||
5. `reset` без @mention → только владельцу топика
|
||
|
||
## Что меняется в balda
|
||
|
||
После деплоя роутера у обоих ботов нужно **отключить Events API polling** в config.yaml:
|
||
|
||
```yaml
|
||
zulip:
|
||
events_polling:
|
||
enabled: false # ← было true
|
||
```
|
||
|
||
После этого сообщения приходят **только через webhook** (от роутера).
|
||
Перезапуск: `docker-compose up -d` (в каждом compose).
|
||
|
||
## Код
|
||
|
||
**Репозиторий:** `~/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`
|
||
|
||
### Перед запуском: создать бота-роутера в Zulip
|
||
|
||
Нужен **отдельный** бот (не valera-bot, не claudio-bot).
|
||
|
||
1. В Zulip: **Settings → Bots → Add a new bot**
|
||
2. Тип: **Outgoing webhook**
|
||
3. Имя: `zulip-router` (или любое)
|
||
4. Bot email: скопировать (понадобится в .env)
|
||
5. API key: скопировать (понадобится в .env)
|
||
6. Endpoint URL: не заполнять (роутер сам поллит, webhook от Zulip ему не нужен)
|
||
7. Сохранить
|
||
|
||
### Env vars
|
||
|
||
Создать `~/Docker/zulip-router/.env`:
|
||
```env
|
||
ZULIP_ROUTER_BOT_EMAIL=zulip-router-bot@zulip.qentra.top
|
||
ZULIP_ROUTER_API_KEY=<api-key из шага 5>
|
||
|
||
# Куда форвардить
|
||
VALERA_WEBHOOK=http://balda-agent-valera-1:8091/zulip/webhook
|
||
CLAUDIO_WEBHOOK=http://claudio-agent-claudio-1:8092/zulip/webhook
|
||
```
|
||
|
||
### Запуск
|
||
```bash
|
||
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`
|
||
- [ ] Создать бота-роутера в Zulip (или реюзнуть valera-bot/claudio-bot), получить API key
|
||
- [ ] `docker-compose up -d`
|
||
- [ ] Проверить логи: `docker logs zulip-router --tail 50`
|
||
- [ ] Отключить `events_polling.enabled` у Валеры → `docker-compose up -d`
|
||
- [ ] Отключить `events_polling.enabled` у Клавдия → `docker-compose up -d`
|
||
- [ ] Протестировать: @Клавдий и @Валера в разных топиках
|
||
- [ ] Проверить ownership: сообщение в топик без @mention → последний бот
|
||
- [ ] Удалить `extractOtherMention()` патч из кода (больше не нужен)
|