fix(voice): отдавать клиенту базовый адрес LiveKit без сегмента /rtc

LiveKit SDK сам дописывает сигнальный путь (`/rtc`, `/rtc/v1`) к базовому
адресу, поэтому `wss://host/rtc` из конфига превращался в `wss://host/rtc/rtc`
и комната навсегда оставалась в состоянии «Подключение…» (AGENT.md 7.14).

- `voice.ResolveLiveKitURL` снимает завершающий сегмент `/rtc`, сохраняя
  префикс прокси (`wss://host/livekit/rtc` → `wss://host/livekit`);
- `POST /channels/{id}/voice/join` отдаёт адрес через `VoiceURLForClient` и
  отвечает `voice.disabled`, если адрес не разрешился;
- тесты: таблица адресов, ожидание `wss://gl.test` в голосовом сценарии.
This commit is contained in:
2026-09-20 19:29:19 +03:00
parent 1552146aa1
commit 2538e07ec3
4 changed files with 49 additions and 8 deletions
+6 -1
View File
@@ -78,6 +78,11 @@ func (s *Server) registerVoiceRoutes(api huma.API) {
if !s.voice.Enabled() {
return nil, humaErrorStatus(http.StatusServiceUnavailable, "voice.disabled", "голос на инстансе не настроен")
}
// Клиенту отдаём базовый адрес SDK: сигнальный путь `/rtc` SDK дописывает сам.
clientURL := s.voice.VoiceURLForClient(s.cfg.LiveKitURL)
if clientURL == "" {
return nil, humaErrorStatus(http.StatusServiceUnavailable, "voice.disabled", "голос на инстансе не настроен")
}
// Сохраняем состояние: пользователь мог перейти из другой комнаты.
state, err := s.store.UpsertVoiceState(ctx, store.VoiceStateParams{
@@ -100,7 +105,7 @@ func (s *Server) registerVoiceRoutes(api huma.API) {
output := &voiceJoinOutput{}
output.Body.Token = token
output.Body.URL = s.cfg.LiveKitURL
output.Body.URL = clientURL
output.Body.Room = voice.RoomName(*channel.GuildID, channelID)
output.Body.ChannelID = formatSnowflake(channelID)
output.Body.GuildID = formatSnowflake(*channel.GuildID)