feat: GuiPresence (chat-service presence backend, gateway route, mod module); restore TODO history

This commit is contained in:
loki5512344 2026-10-02 13:41:49 +02:00
parent 8d9a2ad0d6
commit e82efb74e7
Signed by: boba
GPG key ID: 253067914055423B
44 changed files with 2202 additions and 19 deletions

View file

@ -0,0 +1,47 @@
# 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), метрики, горизонтальное масштабирование (состояние в памяти одного процесса).