feat(voice): вход в голосовые комнаты, voice states и модерация (Фаза 3)
AGENT.md 7.14, начало Фазы 3:
- `internal/voice`: собственный подписыватель токенов LiveKit (HS256, grants
roomJoin/canPublish/canSubscribe/canPublishData) и адрес комнаты
`guild_{g}_channel_{c}` — без внешних зависимостей;
- таблица `voice_states` (миграция 00009) и store-методы: вход, флаги
(микрофон, звук, камера, экран), серверный мьют и глушение, перемещение,
выход, подсчёт участников комнаты;
- ручки: POST /channels/{id}/voice/join (проверяет CONNECT_VOICE, тип комнаты,
лимит участников и выдаёт токен), POST /channels/{id}/voice/leave,
PATCH /guilds/{id}/voice-states/@me, GET /guilds/{id}/voice-states,
PATCH /guilds/{id}/voice-states/{user_id} (MUTE_MEMBERS/DEAFEN_MEMBERS,
аудит), POST /guilds/{id}/voice-states/{user_id}/move (MOVE_MEMBERS);
- события VOICE_STATE_UPDATE всем участникам сервера, системные записи о входе
в голосовую комнату, READY отдаёт голосовые состояния серверов;
- конфиг: LIVEKIT_API_KEY/SECRET/URL приложению, публичный адрес
`LIVEKIT_PUBLIC_URL` (по умолчанию ws(s)://<домен>/rtc) в установщике и
compose; `/api/v1/meta` сообщает voice_enabled и voice_url;
- тесты: claims токена LiveKit и подпись, выключенный голос, имя комнаты, вход
и флаги, запрет мьюта без прав, перемещение и выход.
This commit is contained in:
@@ -24,6 +24,10 @@ x-app-env: &app-env
|
||||
GOMAXPROCS: "${GOMAXPROCS}"
|
||||
MAX_UPLOAD_SIZE: "${MAX_UPLOAD_SIZE}"
|
||||
SHUTDOWN_TIMEOUT_SECONDS: "20"
|
||||
# LiveKit: приложение выдаёт клиентам токены доступа к комнатам.
|
||||
LIVEKIT_API_KEY: "${LIVEKIT_API_KEY}"
|
||||
LIVEKIT_API_SECRET: "${LIVEKIT_API_SECRET}"
|
||||
LIVEKIT_URL: "${LIVEKIT_PUBLIC_URL}"
|
||||
|
||||
services:
|
||||
app:
|
||||
|
||||
@@ -355,6 +355,14 @@ resolve_derived_values() {
|
||||
GLCHAT_DATA_DIR="${GLCHAT_DATA_DIR}"
|
||||
GLCHAT_CADDY_PROFILE="${CADDY_PROFILE}"
|
||||
GLCHAT_TURN_CERT_DIR="${TURN_CERT_DIR}"
|
||||
# Публичный адрес LiveKit: клиенты ходят через тот же домен по /rtc.
|
||||
if [ -z "${LIVEKIT_PUBLIC_URL:-}" ]; then
|
||||
if [ "${TLS_ENABLED}" = "true" ]; then
|
||||
LIVEKIT_PUBLIC_URL="wss://${DOMAIN}/rtc"
|
||||
else
|
||||
LIVEKIT_PUBLIC_URL="ws://${DOMAIN}/rtc"
|
||||
fi
|
||||
fi
|
||||
# TLS считается включённым и когда сертификаты обслуживает внешний прокси
|
||||
# (--external-proxy --tls-terminated-by-proxy): ссылки в API должны быть https/wss.
|
||||
if [ "$SKIP_TLS" = "1" ] && [ "$TLS_BY_PROXY" != "true" ]; then
|
||||
@@ -728,6 +736,8 @@ TURN_EXTERNAL_TLS=@TURN_EXTERNAL_TLS@
|
||||
TURN_RELAY_START=@TURN_RELAY_START@
|
||||
TURN_RELAY_END=@TURN_RELAY_END@
|
||||
TURN_RELAY_HOST=@TURN_RELAY_HOST@
|
||||
# Публичный адрес LiveKit для клиентов (через прокси: /rtc).
|
||||
LIVEKIT_PUBLIC_URL=@LIVEKIT_PUBLIC_URL@
|
||||
TURN_RELAY_PORT=@TURN_RELAY_PORT@
|
||||
TURN_RELAY_TLS_PORT=@TURN_RELAY_TLS_PORT@
|
||||
|
||||
@@ -828,6 +838,7 @@ TOTP_ENCRYPTION_KEY=${TOTP_ENCRYPTION_KEY}
|
||||
WEBHOOK_SECRET=${WEBHOOK_SECRET}
|
||||
LIVEKIT_API_KEY=${LIVEKIT_API_KEY}
|
||||
LIVEKIT_API_SECRET=${LIVEKIT_API_SECRET}
|
||||
LIVEKIT_PUBLIC_URL=${LIVEKIT_PUBLIC_URL}
|
||||
|
||||
AGE_RECIPIENT=${AGE_RECIPIENT:-}
|
||||
SQLITE_READ_POOL=${PROFILE_SQLITE_READ_POOL}
|
||||
|
||||
Reference in New Issue
Block a user