orama/pkg/sfu/config.go
anonpenguin23 8ee606bfb1 feat: implement SFU and TURN server functionality
- Add signaling package with message types and structures for SFU communication.
- Implement client and server message serialization/deserialization tests.
- Enhance systemd manager to handle SFU and TURN services, including start/stop logic.
- Create TURN server configuration and main server logic with HMAC-SHA1 authentication.
- Add tests for TURN server credential generation and validation.
- Define systemd service files for SFU and TURN services.
2026-02-21 11:17:13 +02:00

81 lines
2.5 KiB
Go

package sfu
import "fmt"
// Config holds configuration for the SFU server
type Config struct {
// ListenAddr is the address to bind the signaling WebSocket server.
// Must be a WireGuard IP (10.0.0.x) — never 0.0.0.0.
ListenAddr string `yaml:"listen_addr"`
// Namespace this SFU instance belongs to
Namespace string `yaml:"namespace"`
// MediaPortRange defines the UDP port range for RTP media
MediaPortStart int `yaml:"media_port_start"`
MediaPortEnd int `yaml:"media_port_end"`
// TURN servers this SFU should advertise to peers
TURNServers []TURNServerConfig `yaml:"turn_servers"`
// TURNSecret is the shared HMAC-SHA1 secret for generating TURN credentials
TURNSecret string `yaml:"turn_secret"`
// TURNCredentialTTL is the lifetime of TURN credentials in seconds
TURNCredentialTTL int `yaml:"turn_credential_ttl"`
// RQLiteDSN is the namespace-local RQLite DSN for room state
RQLiteDSN string `yaml:"rqlite_dsn"`
}
// TURNServerConfig represents a single TURN server endpoint
type TURNServerConfig struct {
Host string `yaml:"host"` // IP or hostname
Port int `yaml:"port"` // UDP port (3478 or 443)
}
// Validate checks the SFU configuration for errors
func (c *Config) Validate() []error {
var errs []error
if c.ListenAddr == "" {
errs = append(errs, fmt.Errorf("sfu.listen_addr: must not be empty"))
}
if c.Namespace == "" {
errs = append(errs, fmt.Errorf("sfu.namespace: must not be empty"))
}
if c.MediaPortStart <= 0 || c.MediaPortEnd <= 0 {
errs = append(errs, fmt.Errorf("sfu.media_port_range: start and end must be positive"))
} else if c.MediaPortEnd <= c.MediaPortStart {
errs = append(errs, fmt.Errorf("sfu.media_port_range: end (%d) must be greater than start (%d)", c.MediaPortEnd, c.MediaPortStart))
}
if len(c.TURNServers) == 0 {
errs = append(errs, fmt.Errorf("sfu.turn_servers: at least one TURN server must be configured"))
}
for i, ts := range c.TURNServers {
if ts.Host == "" {
errs = append(errs, fmt.Errorf("sfu.turn_servers[%d].host: must not be empty", i))
}
if ts.Port <= 0 || ts.Port > 65535 {
errs = append(errs, fmt.Errorf("sfu.turn_servers[%d].port: must be between 1 and 65535", i))
}
}
if c.TURNSecret == "" {
errs = append(errs, fmt.Errorf("sfu.turn_secret: must not be empty"))
}
if c.TURNCredentialTTL <= 0 {
errs = append(errs, fmt.Errorf("sfu.turn_credential_ttl: must be positive"))
}
if c.RQLiteDSN == "" {
errs = append(errs, fmt.Errorf("sfu.rqlite_dsn: must not be empty"))
}
return errs
}