🎉 live server seems to be working now

This commit is contained in:
2026-05-14 14:29:57 +02:00
commit d72e439fd9
181 changed files with 47406 additions and 0 deletions

58
internal/live/roster.go Normal file
View File

@@ -0,0 +1,58 @@
package live
import (
"sort"
"sync"
"time"
)
// RosterEntry is one observed Sendspin client. Populated from
// client/hello messages — independent of whether the connection was
// then accepted or rejected. This is what gives the UI the ability to
// show the *actual* `client_id` of every speaker on the network, even
// when ClientFilter rejected its current attempt.
type RosterEntry struct {
ClientID string `json:"client_id"`
Name string `json:"name"`
LastSeen time.Time `json:"last_seen"`
}
// Roster caches every (client_id, name) pair the sendspin server has
// observed via client/hello. Records are kept indefinitely — speakers
// usually keep the same client_id across reboots, so a stale entry
// remains useful when the user is configuring presets offline.
type Roster struct {
mu sync.RWMutex
entries map[string]RosterEntry
}
func NewRoster() *Roster {
return &Roster{entries: make(map[string]RosterEntry)}
}
// Record is intended to be plugged into ServerConfig.OnClientHello.
// Updates the entry's LastSeen on every call so the UI can show
// "active now" vs. "last seen 5 minutes ago".
func (r *Roster) Record(clientID, name string) {
if clientID == "" {
return
}
r.mu.Lock()
defer r.mu.Unlock()
r.entries[clientID] = RosterEntry{
ClientID: clientID,
Name: name,
LastSeen: time.Now(),
}
}
func (r *Roster) List() []RosterEntry {
r.mu.RLock()
defer r.mu.RUnlock()
out := make([]RosterEntry, 0, len(r.entries))
for _, e := range r.entries {
out = append(out, e)
}
sort.Slice(out, func(i, j int) bool { return out[i].ClientID < out[j].ClientID })
return out
}