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
+21 -3
View File
@@ -3,6 +3,7 @@ package voice_test
import (
"encoding/base64"
"encoding/json"
"errors"
"strings"
"testing"
"time"
@@ -81,13 +82,30 @@ func TestParseRoomName(t *testing.T) {
}
func TestResolveLiveKitURL(t *testing.T) {
url, err := voice.ResolveLiveKitURL("wss://gl.example/rtc/")
if err != nil || url != "wss://gl.example/rtc" {
t.Fatalf("ResolveLiveKitURL = %q, %v", url, err)
cases := map[string]string{
"wss://gl.example/rtc/": "wss://gl.example",
"wss://gl.example/rtc": "wss://gl.example",
"wss://gl.example": "wss://gl.example",
"wss://gl.example/": "wss://gl.example",
"wss://gl.example/livekit/rtc": "wss://gl.example/livekit",
"wss://gl.example:7880/rtc": "wss://gl.example:7880",
"ws://192.168.1.247:7880/rtc/": "ws://192.168.1.247:7880",
"wss://gl.example/notrtc": "wss://gl.example/notrtc",
"wss://gl.example/rtc/extra": "wss://gl.example/rtc/extra",
"wss://gl.example/livekit/rtcx": "wss://gl.example/livekit/rtcx",
}
for raw, want := range cases {
got, err := voice.ResolveLiveKitURL(raw)
if err != nil || got != want {
t.Fatalf("ResolveLiveKitURL(%q) = %q, %v; ожидалось %q", raw, got, err, want)
}
}
if _, err := voice.ResolveLiveKitURL("http://gl.example"); err == nil {
t.Fatal("http-адрес должен отклоняться")
}
if _, err := voice.ResolveLiveKitURL(""); !errors.Is(err, voice.ErrDisabled) {
t.Fatalf("пустой адрес = %v, ожидалось ErrDisabled", err)
}
}
func TestVerifyWebhookSignature(t *testing.T) {