LoVisual/backend/chat-service/PLAN.md

47 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# chat-service
Подсистема 2 платформы (RPC-чат, друзья, presence, телеметрия виджетов). Сейчас реализован только **GUI presence**;
чат и друзья позже (WebSocket). Сервис без БД: состояние в памяти, живёт секунды.
## GUI presence (идея из evo `GuiPresence`, наш вариант)
Зачем: LoVisual-игроки видят друг у друга над рукой мини-копию открытого меню клиента (какая категория, куда наведён курсор,
поиск), и знают, кто вообще пользуется LoVisual (значок у ника). Без видео и без чужих данных: только положение курсора и флаги.
### Протокол
`POST /presence/gui` (через gateway, нужен device-токен `lvd_...`, gateway кладёт `x-lovisual-account-id`):
```json
{ "server": "play.example.com", "mc": "<uuid игрока>", "gui": "<base64>|null", "want": ["<uuid>", "..."], "publish": true }
```
Ответ: `{ "players": [ { "mc": "<uuid>", "gui": "<base64>|null", "age": 120 } ] }`, `age` в мс с последнего обновления.
- Один запрос и публикует состояние вызывающего, и возвращает состояние тех, кого он видит (`want`, не больше 40).
- `publish = false` (по умолчанию true): только чтение, вызывающий сам не появляется у других.
- `gui = null` значит «меню закрыто, но LoVisual запущен» (значок у ника). Запись живёт 6 с без обновления.
- Игроки разных серверов не видят друг друга (ключ `server`, нормализуется в нижний регистр, ≤64 символов).
- Частота клиента: раз в ~350 мс при открытом меню (пачка до 8 сэмплов курсора по 100 мс), раз в 2 с при закрытом.
Лимит на gateway: 6 запросов в секунду на аккаунт.
### Формат `gui` (36 байт максимум, base64 ≤48 символов; сервис его не разбирает, только проверяет алфавит и длину)
| байт | значение |
|---|---|
| 0 | версия = 1 |
| 1 | биты 0-3 категория (0..15), бит 4 открыта страница настроек, бит 5 поиск, бит 7 меню закрыто |
| 2 | индекс модуля под курсором в списке категории (255 = нет) |
| 3 | число сэмплов n (0..8) |
| 4+4i | сэмпл: x (0..255 по ширине меню), y (0..255 по высоте), бит 0 = зажата ЛКМ, прокрутка списка (0..255) |
### Безопасность
- Идентичность только из заголовка gateway; прямой доступ закрыт общим секретом (как у остальных сервисов).
- Привязка `mc uuid` к аккаунту: чужой аккаунт не может публиковать за занятый uuid (409), привязка снимается через 10 мин
простоя; аккаунт владеет одним uuid, смена альта освобождает прежний. Это защита от подделки, не доказательство владения
аккаунтом Minecraft: серверной верификации uuid нет.
- Размер тела ≤8 КБ, payload только `[A-Za-z0-9+/=]`, `want` ≤40.
### Структура
`src/presence/{payload.rs (валидация), store.rs (состояние + TTL + привязка), handlers.rs (sync)}`; тесты: модульные в `store.rs`,
`payload.rs`, интеграционные `tests/presence.rs`. Порт `CHAT_PORT` (8083), `INTERNAL_KEY` общий. В gateway маршрут `/presence/*`.
### Не сделано
Просмотр видео (`.watch` у evo), чат и друзья (WebSocket), метрики, горизонтальное масштабирование (состояние в памяти одного процесса).