chore(server): delete production-dead code; move test helpers to export_test

Applied from a deadcode (RTA from mains, all build tags) sweep with
per-symbol adversarial verification:

Deleted (nothing but their own self-tests used them):
- admin.Handler (deprecated since Phase 6; production mounts NewHandler)
  plus its two self-tests
- ws.Hub.broadcastVoiceStateUpdate + wrapper + two self-tests (pre-V2
  leftover; the live voice_state path is the hub voice routines)
- ws.VoiceLeaveEvent + methods ('retained as scaffolding', never
  constructed in production; MsgTypeVoiceLeaveBC stays — live via the
  leave routine)
- ws.parseIdentity (production calls parseParticipantIdentity directly;
  ParseIdentityForTest now exercises the real parser)
- telemetry.Float64 (String/Int64 are used; the float case is covered by
  the otel-tagged internal test, re-addable when a caller appears)

Moved into export_test.go so they leave the production binary (all
callers are same-package tests): the eight ws test-client constructors
and voice/E2EE setters from ws/client.go, admin.SetBackupBaseDir
(new admin/export_test.go), api.SecurityHeaders (test-only wrapper;
production uses SecurityHeadersWithTLS — docs/api.md updated to the
real name). Client.getVoiceJoinToken/setVoiceChID inlined into their
existing ForTest wrappers; TestSetVoiceChID_* self-tests deleted.

Kept after verification: updater.SetBaseURL (11 cross-package test call
sites) and telemetry.resetAppMetricsForInit (live under -tags otel —
untagged deadcode false positive).

Full gate green: gofmt/vet, 4 build-tag variants, full suite, deadlock,
race.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
J3vb
2026-07-23 15:28:41 +02:00
co-authored by Claude Fable 5
parent 07b59ca485
commit f2966c2527
16 changed files with 108 additions and 302 deletions
-8
View File
@@ -56,11 +56,3 @@ func NewHandler(database *db.DB, version string, hub HubBroadcaster, u *updater.
return r return r
} }
// Handler returns the admin panel http.Handler using a nil database.
//
// Deprecated: use NewHandler instead. Kept for backwards-compat with any
// caller that already imported this symbol before Phase 6.
func Handler() http.Handler {
return http.FileServer(http.FS(staticFiles))
}
-27
View File
@@ -115,33 +115,6 @@ func TestNewHandler_WithUpdater(t *testing.T) {
} }
} }
// ─── Handler (deprecated) ────────────────────────────────────────────────────
// TestHandler_ReturnsNonNil verifies the deprecated Handler() function returns
// a non-nil http.Handler (it serves the embedded static files).
func TestHandler_ReturnsNonNil(t *testing.T) {
h := admin.Handler()
if h == nil {
t.Fatal("Handler() returned nil")
}
}
// TestHandler_ServesEmbeddedFiles verifies that the deprecated Handler() serves
// a response (the embedded static FS) without panicking.
func TestHandler_ServesEmbeddedFiles(t *testing.T) {
h := admin.Handler()
req := httptest.NewRequest(http.MethodGet, "/index.html", nil)
w := httptest.NewRecorder()
h.ServeHTTP(w, req)
// http.FileServer returns 200 for a found file or 301/404 for others;
// the important thing is it doesn't panic and returns a valid HTTP status.
if w.Code == 0 {
t.Error("Handler() response has zero status code")
}
}
// ─── ownerOnlyMiddleware (tested via API endpoints that use it) ─────────────── // ─── ownerOnlyMiddleware (tested via API endpoints that use it) ───────────────
// TestOwnerOnlyMiddleware_OwnerAllowed verifies that a user with Owner role // TestOwnerOnlyMiddleware_OwnerAllowed verifies that a user with Owner role
+5
View File
@@ -0,0 +1,5 @@
package admin
// SetBackupBaseDir overrides backupBaseDir so tests can point backup handlers
// at a temp dir. Lives here so it stays out of the production binary.
func SetBackupBaseDir(dir string) { backupBaseDir = dir }
-3
View File
@@ -28,9 +28,6 @@ func init() {
} }
} }
// SetBackupBaseDir overrides backupBaseDir. Intended for tests only.
func SetBackupBaseDir(dir string) { backupBaseDir = dir }
// ─── Backup Handlers ───────────────────────────────────────────────────────── // ─── Backup Handlers ─────────────────────────────────────────────────────────
func handleBackup(database *db.DB) http.Handler { func handleBackup(database *db.DB) http.Handler {
+6
View File
@@ -44,3 +44,9 @@ func SetGIFUpstreamForTest(baseURL string, client *http.Client) func() {
gifAPIBase, gifClient = baseURL, client gifAPIBase, gifClient = baseURL, client
return func() { gifAPIBase, gifClient = prevBase, prevClient } return func() { gifAPIBase, gifClient = prevBase, prevClient }
} }
// SecurityHeaders is SecurityHeadersWithTLS with TLS disabled (no HSTS).
// Test-only convenience — production always goes through SecurityHeadersWithTLS.
func SecurityHeaders(next http.Handler) http.Handler {
return SecurityHeadersWithTLS("")(next)
}
-6
View File
@@ -375,12 +375,6 @@ func SecurityHeadersWithTLS(tlsMode string) func(http.Handler) http.Handler {
} }
} }
// SecurityHeaders is a convenience wrapper for SecurityHeadersWithTLS with TLS
// disabled (no HSTS header). Kept for backwards compatibility with tests.
func SecurityHeaders(next http.Handler) http.Handler {
return SecurityHeadersWithTLS("")(next)
}
// MaxBodySize wraps r.Body with http.MaxBytesReader so that reads beyond // MaxBodySize wraps r.Body with http.MaxBytesReader so that reads beyond
// maxBytes return an error. This prevents clients from exhausting server memory // maxBytes return an error. This prevents clients from exhausting server memory
// by sending arbitrarily large request bodies. // by sending arbitrarily large request bodies.
-3
View File
@@ -58,9 +58,6 @@ func String(k, v string) Attr { return Attr{Key: k, Value: v} }
// Int64 constructs an int64 attribute. // Int64 constructs an int64 attribute.
func Int64(k string, v int64) Attr { return Attr{Key: k, Value: v} } func Int64(k string, v int64) Attr { return Attr{Key: k, Value: v} }
// Float64 constructs a float64 attribute.
func Float64(k string, v float64) Attr { return Attr{Key: k, Value: v} }
// Span is a single tracing span. // Span is a single tracing span.
type Span interface { type Span interface {
End() End()
-102
View File
@@ -83,92 +83,6 @@ func (c *Client) GetTokenHash() string {
return c.tokenHash return c.tokenHash
} }
// NewTestClient creates a client with a caller-supplied send channel.
// Intended for unit tests only — conn is nil.
func NewTestClient(hub *Hub, userID int64, send chan []byte) *Client {
return &Client{
hub: hub,
ctx: context.Background(),
userID: userID,
send: send,
sendHigh: send, // unified for test observability
sendLow: send,
}
}
// NewTestClientWithChannel creates a test client subscribed to a specific channel.
func NewTestClientWithChannel(hub *Hub, userID, channelID int64, send chan []byte) *Client {
return &Client{
hub: hub,
ctx: context.Background(),
userID: userID,
channelID: channelID,
send: send,
sendHigh: send, // unified for test observability
sendLow: send,
}
}
// NewTestClientWithUser creates a test client with an authenticated user record set.
// Use this when tests need the client to pass permission checks.
func NewTestClientWithUser(hub *Hub, user *db.User, channelID int64, send chan []byte) *Client {
return &Client{
hub: hub,
ctx: context.Background(),
userID: user.ID,
user: user,
channelID: channelID,
send: send,
sendHigh: send, // unified for test observability
sendLow: send,
}
}
// SetClientVoiceChID sets the voiceChID field on a client. For test use only.
func SetClientVoiceChID(c *Client, channelID int64) {
c.voiceMu.Lock()
defer c.voiceMu.Unlock()
c.voiceChID = channelID
if channelID == 0 {
c.voiceJoinToken = ""
}
}
// SetClientVoiceStateForTest sets both the voice channel and join token.
// For test use only.
func SetClientVoiceStateForTest(c *Client, channelID int64, joinToken string) {
c.voiceMu.Lock()
defer c.voiceMu.Unlock()
c.voiceChID = channelID
c.voiceJoinToken = joinToken
}
// SetClientE2EEPubKeyForTest sets the E2EE public key on a client. For test use only.
func SetClientE2EEPubKeyForTest(c *Client, key string) {
c.setE2EEPubKey(key)
}
// GetClientE2EEPubKeyForTest returns the E2EE public key from a client. For test use only.
func GetClientE2EEPubKeyForTest(c *Client) string {
return c.getE2EEPubKey()
}
// NewTestClientWithTokenHash creates a test client that carries a session token
// hash. Use this when tests need to exercise the periodic session-expiry check.
func NewTestClientWithTokenHash(hub *Hub, user *db.User, tokenHash string, channelID int64, send chan []byte) *Client {
return &Client{
hub: hub,
ctx: context.Background(),
userID: user.ID,
user: user,
tokenHash: tokenHash,
channelID: channelID,
send: send,
sendHigh: send, // unified for test observability
sendLow: send,
}
}
// touch updates the last activity timestamp and increments the received counter. // touch updates the last activity timestamp and increments the received counter.
func (c *Client) touch() { func (c *Client) touch() {
c.mu.Lock() c.mu.Lock()
@@ -198,28 +112,12 @@ func (c *Client) getVoiceChID() int64 {
return c.voiceChID return c.voiceChID
} }
func (c *Client) getVoiceJoinToken() string {
c.voiceMu.Lock()
defer c.voiceMu.Unlock()
return c.voiceJoinToken
}
func (c *Client) getVoiceState() (int64, string) { func (c *Client) getVoiceState() (int64, string) {
c.voiceMu.Lock() c.voiceMu.Lock()
defer c.voiceMu.Unlock() defer c.voiceMu.Unlock()
return c.voiceChID, c.voiceJoinToken return c.voiceChID, c.voiceJoinToken
} }
// setVoiceChID sets the voice channel ID atomically.
func (c *Client) setVoiceChID(chID int64) {
c.voiceMu.Lock()
defer c.voiceMu.Unlock()
c.voiceChID = chID
if chID == 0 {
c.voiceJoinToken = ""
}
}
func (c *Client) setVoiceState(chID int64, joinToken string) { func (c *Client) setVoiceState(chID int64, joinToken string) {
c.voiceMu.Lock() c.voiceMu.Lock()
defer c.voiceMu.Unlock() defer c.voiceMu.Unlock()
-69
View File
@@ -162,75 +162,6 @@ func TestBuildDMChannelOpen_NilAvatar(t *testing.T) {
} }
} }
// ─── broadcastVoiceStateUpdate ──────────────────────────────────────────────
func TestBroadcastVoiceStateUpdate_NotInVoice(t *testing.T) {
hub, database := newCoverageHub(t)
user := seedCoverageOwner(t, database, "bvsu-noop")
send := make(chan []byte, 16)
c := ws.NewTestClientWithUser(hub, user, 0, send)
hub.Register(c)
time.Sleep(20 * time.Millisecond)
// User not in voice — should be a no-op.
hub.BroadcastVoiceStateUpdateForTest(c)
time.Sleep(20 * time.Millisecond)
// No voice_state message should have been sent since user is not in voice.
for len(send) > 0 {
msg := <-send
var m struct {
Type string `json:"type"`
}
_ = json.Unmarshal(msg, &m)
if m.Type == "voice_state" {
t.Error("expected no voice_state broadcast when user is not in voice")
}
}
}
func TestBroadcastVoiceStateUpdate_InVoice(t *testing.T) {
hub, database := newCoverageHub(t)
user := seedCoverageOwner(t, database, "bvsu-voice")
// Create a voice channel.
chanID, err := database.CreateChannel("bvsu-ch", "voice", "", "", 0)
if err != nil {
t.Fatalf("CreateChannel: %v", err)
}
// Join the voice channel in DB.
if err := database.JoinVoiceChannel(user.ID, chanID); err != nil {
t.Fatalf("JoinVoiceChannel: %v", err)
}
send := make(chan []byte, 16)
c := ws.NewTestClientWithUser(hub, user, 0, send)
ws.SetClientVoiceChID(c, chanID)
hub.Register(c)
time.Sleep(20 * time.Millisecond)
// Should broadcast a voice_state message.
hub.BroadcastVoiceStateUpdateForTest(c)
// Drain the channel and check for voice_state message.
time.Sleep(20 * time.Millisecond)
found := false
for len(send) > 0 {
msg := <-send
var m struct {
Type string `json:"type"`
}
_ = json.Unmarshal(msg, &m)
if m.Type == "voice_state" {
found = true
}
}
if !found {
t.Error("expected voice_state broadcast")
}
}
// ─── handleVoiceMute via HandleMessageForTest ─────────────────────────────── // ─── handleVoiceMute via HandleMessageForTest ───────────────────────────────
func TestHandleVoiceMute_NotInVoice2(t *testing.T) { func TestHandleVoiceMute_NotInVoice2(t *testing.T) {
-37
View File
@@ -2300,43 +2300,6 @@ func TestGetLastActivity_MultipleTouch(t *testing.T) {
} }
} }
// ─── setVoiceChID (client.go:186) ───────────────────────────────────────────
func TestSetVoiceChID_SetsAndGetsValue(t *testing.T) {
hub, _ := newCoverageHub(t)
send := make(chan []byte, 4)
c := ws.NewTestClient(hub, 1, send)
ws.SetVoiceChIDForTest(c, 77)
if got := ws.GetClientVoiceChIDForTest(c); got != 77 {
t.Fatalf("voiceChID = %d, want 77", got)
}
}
func TestSetVoiceChID_OverwritesPreviousValue(t *testing.T) {
hub, _ := newCoverageHub(t)
send := make(chan []byte, 4)
c := ws.NewTestClient(hub, 1, send)
ws.SetVoiceChIDForTest(c, 10)
ws.SetVoiceChIDForTest(c, 20)
if got := ws.GetClientVoiceChIDForTest(c); got != 20 {
t.Fatalf("voiceChID = %d, want 20", got)
}
}
func TestSetVoiceChID_ZeroMeansNotInVoice(t *testing.T) {
hub, _ := newCoverageHub(t)
send := make(chan []byte, 4)
c := ws.NewTestClient(hub, 1, send)
ws.SetVoiceChIDForTest(c, 50)
ws.SetVoiceChIDForTest(c, 0)
if got := ws.GetClientVoiceChIDForTest(c); got != 0 {
t.Fatalf("voiceChID = %d, want 0", got)
}
}
// ─── clearVoiceChID (client.go:203) ───────────────────────────────────────── // ─── clearVoiceChID (client.go:203) ─────────────────────────────────────────
func TestClearVoiceChID_ReturnsOldValueAndClearsToZero(t *testing.T) { func TestClearVoiceChID_ReturnsOldValueAndClearsToZero(t *testing.T) {
-11
View File
@@ -259,17 +259,6 @@ type VoiceStateEvent struct {
func (e VoiceStateEvent) EventType() string { return MsgTypeVoiceState } func (e VoiceStateEvent) EventType() string { return MsgTypeVoiceState }
func (e VoiceStateEvent) Payload() []byte { return e.payload } func (e VoiceStateEvent) Payload() []byte { return e.payload }
// VoiceLeaveEvent is a voice_leave broadcast to all connected clients.
// NOTE: Currently unused — the voice_leave V2 handler triggers the hub's
// handleVoiceLeave routine (via Result.LeaveVoice), which broadcasts the leave
// directly. Retained as forward-compatible scaffolding.
type VoiceLeaveEvent struct {
payload []byte
}
func (e VoiceLeaveEvent) EventType() string { return MsgTypeVoiceLeaveBC }
func (e VoiceLeaveEvent) Payload() []byte { return e.payload }
// PluginBroadcastEvent is a plugin slash-command result broadcast to a channel // PluginBroadcastEvent is a plugin slash-command result broadcast to a channel
// (sequenced, replayable). Emitted by the chat_command handler after the // (sequenced, replayable). Emitted by the chat_command handler after the
// invoking user's post permission is verified. // invoking user's post permission is verified.
-2
View File
@@ -83,7 +83,6 @@ func TestEventTypes(t *testing.T) {
{"ReactionChannelEvent", ReactionChannelEvent{}, MsgTypeReactionUpdate}, {"ReactionChannelEvent", ReactionChannelEvent{}, MsgTypeReactionUpdate},
{"ReactionDMEvent", ReactionDMEvent{}, MsgTypeReactionUpdate}, {"ReactionDMEvent", ReactionDMEvent{}, MsgTypeReactionUpdate},
{"VoiceStateEvent", VoiceStateEvent{}, MsgTypeVoiceState}, {"VoiceStateEvent", VoiceStateEvent{}, MsgTypeVoiceState},
{"VoiceLeaveEvent", VoiceLeaveEvent{}, MsgTypeVoiceLeaveBC},
{"VoiceE2EEAnnounceEvent", VoiceE2EEAnnounceEvent{}, MsgTypeVoiceE2EEAnnounceBC}, {"VoiceE2EEAnnounceEvent", VoiceE2EEAnnounceEvent{}, MsgTypeVoiceE2EEAnnounceBC},
{"VoiceE2EEOfferGuardedEvent", VoiceE2EEOfferGuardedEvent{}, MsgTypeVoiceE2EEOfferRelay}, {"VoiceE2EEOfferGuardedEvent", VoiceE2EEOfferGuardedEvent{}, MsgTypeVoiceE2EEOfferRelay},
{"DMChannelOpenEvent", DMChannelOpenEvent{}, MsgTypeDMChannelOpen}, {"DMChannelOpenEvent", DMChannelOpenEvent{}, MsgTypeDMChannelOpen},
@@ -207,7 +206,6 @@ func TestBroadcastAllEventInterface(t *testing.T) {
}{ }{
{"PresenceEvent", PresenceEvent{payload: []byte("p")}}, {"PresenceEvent", PresenceEvent{payload: []byte("p")}},
{"VoiceStateEvent", VoiceStateEvent{payload: []byte("vs")}}, {"VoiceStateEvent", VoiceStateEvent{payload: []byte("vs")}},
{"VoiceLeaveEvent", VoiceLeaveEvent{payload: []byte("vl")}},
} }
for _, tt := range events { for _, tt := range events {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
+96 -11
View File
@@ -49,9 +49,95 @@ func ClearVoiceChIDForTest(c *Client) int64 {
return c.clearVoiceChID() return c.clearVoiceChID()
} }
// SetVoiceChIDForTest exposes Client.setVoiceChID for external tests. // SetVoiceChIDForTest sets the voice channel ID atomically, clearing the join
// token when leaving (chID 0) — the same contract production keeps via
// setVoiceState. Test-only: production has no set-channel-without-token path.
func SetVoiceChIDForTest(c *Client, chID int64) { func SetVoiceChIDForTest(c *Client, chID int64) {
c.setVoiceChID(chID) c.voiceMu.Lock()
defer c.voiceMu.Unlock()
c.voiceChID = chID
if chID == 0 {
c.voiceJoinToken = ""
}
}
// SetClientVoiceChID is an alias kept for existing tests.
func SetClientVoiceChID(c *Client, channelID int64) {
SetVoiceChIDForTest(c, channelID)
}
// SetClientVoiceStateForTest sets both the voice channel and join token.
func SetClientVoiceStateForTest(c *Client, channelID int64, joinToken string) {
c.voiceMu.Lock()
defer c.voiceMu.Unlock()
c.voiceChID = channelID
c.voiceJoinToken = joinToken
}
// SetClientE2EEPubKeyForTest sets the E2EE public key on a client.
func SetClientE2EEPubKeyForTest(c *Client, key string) {
c.setE2EEPubKey(key)
}
// GetClientE2EEPubKeyForTest returns the E2EE public key from a client.
func GetClientE2EEPubKeyForTest(c *Client) string {
return c.getE2EEPubKey()
}
// NewTestClient creates a client with a caller-supplied send channel; conn is nil.
func NewTestClient(hub *Hub, userID int64, send chan []byte) *Client {
return &Client{
hub: hub,
ctx: context.Background(),
userID: userID,
send: send,
sendHigh: send, // unified for test observability
sendLow: send,
}
}
// NewTestClientWithChannel creates a test client subscribed to a specific channel.
func NewTestClientWithChannel(hub *Hub, userID, channelID int64, send chan []byte) *Client {
return &Client{
hub: hub,
ctx: context.Background(),
userID: userID,
channelID: channelID,
send: send,
sendHigh: send, // unified for test observability
sendLow: send,
}
}
// NewTestClientWithUser creates a test client with an authenticated user record
// set. Use this when tests need the client to pass permission checks.
func NewTestClientWithUser(hub *Hub, user *db.User, channelID int64, send chan []byte) *Client {
return &Client{
hub: hub,
ctx: context.Background(),
userID: user.ID,
user: user,
channelID: channelID,
send: send,
sendHigh: send, // unified for test observability
sendLow: send,
}
}
// NewTestClientWithTokenHash creates a test client that carries a session token
// hash. Use this when tests need to exercise the periodic session-expiry check.
func NewTestClientWithTokenHash(hub *Hub, user *db.User, tokenHash string, channelID int64, send chan []byte) *Client {
return &Client{
hub: hub,
ctx: context.Background(),
userID: user.ID,
user: user,
tokenHash: tokenHash,
channelID: channelID,
send: send,
sendHigh: send, // unified for test observability
sendLow: send,
}
} }
// TouchForTest exposes Client.touch for external tests. // TouchForTest exposes Client.touch for external tests.
@@ -138,9 +224,11 @@ func GetClientVoiceChIDForTest(c *Client) int64 {
return c.getVoiceChID() return c.getVoiceChID()
} }
// GetClientVoiceJoinTokenForTest exposes Client.getVoiceJoinToken. // GetClientVoiceJoinTokenForTest reads the join token under voiceMu.
func GetClientVoiceJoinTokenForTest(c *Client) string { func GetClientVoiceJoinTokenForTest(c *Client) string {
return c.getVoiceJoinToken() c.voiceMu.Lock()
defer c.voiceMu.Unlock()
return c.voiceJoinToken
} }
// ExpireSettingsCacheForTest forces the settings cache to appear stale so that // ExpireSettingsCacheForTest forces the settings cache to appear stale so that
@@ -161,9 +249,11 @@ func BuildJSONForTest(v any) []byte {
return buildJSON(v) return buildJSON(v)
} }
// ParseIdentityForTest exposes parseIdentity for external tests. // ParseIdentityForTest parses a LiveKit participant identity and discards the
// join token, exercising the production parseParticipantIdentity.
func ParseIdentityForTest(identity string) (int64, error) { func ParseIdentityForTest(identity string) (int64, error) {
return parseIdentity(identity) userID, _, err := parseParticipantIdentity(identity)
return userID, err
} }
// ParseParticipantIdentityForTest exposes parseParticipantIdentity for tests. // ParseParticipantIdentityForTest exposes parseParticipantIdentity for tests.
@@ -202,11 +292,6 @@ func BuildDMChannelOpenForTest(channelID int64, recipient *db.User) []byte {
return buildDMChannelOpen(channelID, recipient) return buildDMChannelOpen(channelID, recipient)
} }
// BroadcastVoiceStateUpdateForTest exposes broadcastVoiceStateUpdate for external tests.
func (h *Hub) BroadcastVoiceStateUpdateForTest(c *Client) {
h.broadcastVoiceStateUpdate(c)
}
// HandleWebhookParticipantLeftForTest exposes handleWebhookParticipantLeft for // HandleWebhookParticipantLeftForTest exposes handleWebhookParticipantLeft for
// external tests so they can simulate LiveKit webhook events without HTTP. // external tests so they can simulate LiveKit webhook events without HTTP.
func (h *Hub) HandleWebhookParticipantLeftForTest(userID int64, channelID int64, joinToken string) { func (h *Hub) HandleWebhookParticipantLeftForTest(userID int64, channelID int64, joinToken string) {
-6
View File
@@ -89,12 +89,6 @@ func parseParticipantIdentity(identity string) (int64, string, error) {
return userID, joinToken, nil return userID, joinToken, nil
} }
// parseIdentity extracts a user ID from a LiveKit participant identity.
func parseIdentity(identity string) (int64, error) {
userID, _, err := parseParticipantIdentity(identity)
return userID, err
}
// parseRoomChannelID extracts a channel ID from a LiveKit room name // parseRoomChannelID extracts a channel ID from a LiveKit room name
// formatted as "channel-{id}". // formatted as "channel-{id}".
func parseRoomChannelID(roomName string) (int64, error) { func parseRoomChannelID(roomName string) (int64, error) {
-16
View File
@@ -1,7 +1,6 @@
package ws package ws
import ( import (
"log/slog"
"time" "time"
) )
@@ -33,18 +32,3 @@ func qualityBitrate(quality string) int {
} }
return voiceQualities["medium"] return voiceQualities["medium"]
} }
// broadcastVoiceStateUpdate fetches the current voice state for the client
// and broadcasts it to all members of the voice channel they are in.
func (h *Hub) broadcastVoiceStateUpdate(c *Client) {
state, err := h.db.GetVoiceState(c.userID)
if err != nil {
slog.Error("ws broadcastVoiceStateUpdate GetVoiceState", "err", err, "user_id", c.userID)
c.sendMsg(buildErrorMsg(ErrCodeInternal, "failed to broadcast voice state update"))
return
}
if state == nil {
return // user not in a voice channel — nothing to broadcast
}
h.BroadcastToAll(buildVoiceState(*state))
}
+1 -1
View File
@@ -19,7 +19,7 @@ All authenticated endpoints require a session token delivered via the `Authoriza
1. **RequestID** -- assigns a unique `X-Request-Id` response header. 1. **RequestID** -- assigns a unique `X-Request-Id` response header.
2. **Recoverer** -- catches panics and returns 500. 2. **Recoverer** -- catches panics and returns 500.
3. **Request Logger** -- structured logging of method, path, status, duration. 3. **Request Logger** -- structured logging of method, path, status, duration.
4. **SecurityHeaders** -- sets `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`, `X-XSS-Protection: 0`, `Referrer-Policy: strict-origin-when-cross-origin`, `Content-Security-Policy: default-src 'self'`, `Permissions-Policy: camera=(), microphone=(), geolocation=()`, `Cache-Control: no-store`. 4. **SecurityHeadersWithTLS** -- (adds `Strict-Transport-Security` when TLS is on) sets `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`, `X-XSS-Protection: 0`, `Referrer-Policy: strict-origin-when-cross-origin`, `Content-Security-Policy: default-src 'self'`, `Permissions-Policy: camera=(), microphone=(), geolocation=()`, `Cache-Control: no-store`.
5. **MaxBodySize** -- 1 MiB default for all routes except `/api/v1/uploads` (which has its own 100 MiB limit). 5. **MaxBodySize** -- 1 MiB default for all routes except `/api/v1/uploads` (which has its own 100 MiB limit).
--- ---