package config import ( "os" "strings" ) // Config 承载直播 SFU 分流 Demo 的运行参数。 // 优先级:环境变量 > 默认值。Cloudflare Realtime 为主 SFU,SRS 为本地对照后端。 type Config struct { HTTPPort string GRPCPort string ProviderOrder string // 逗号分隔的后端顺序,如 "cloudflare,srs" SRSBaseURL string SRSApp string SRSSecret string SRSCandidate string CFAppID string CFAppSecret string CFBaseURL string CFStunURL string TokenSecret string TokenRequired bool } func Load() *Config { c := &Config{ HTTPPort: getenv("HTTP_PORT", "8088"), GRPCPort: getenv("GRPC_PORT", "9090"), ProviderOrder: getenv("SFU_PROVIDER", "cloudflare,srs"), SRSBaseURL: getenv("SRS_API_BASE", "http://localhost:1985"), SRSApp: getenv("SRS_APP", "live"), SRSSecret: getenv("SRS_SECRET", ""), SRSCandidate: getenv("SRS_CANDIDATE", "127.0.0.1"), CFAppID: getenv("CF_APP_ID", ""), CFAppSecret: getenv("CF_APP_SECRET", ""), CFBaseURL: getenv("CF_BASE_URL", "https://rtc.live.cloudflare.com/v1"), CFStunURL: getenv("CF_STUN_URL", "stun:stun.cloudflare.com:3478"), TokenSecret: getenv("DEMO_TOKEN_SECRET", ""), TokenRequired: getenv("SFU_TOKEN_REQUIRED", "0") == "1", } if c.TokenSecret == "" { c.TokenSecret = "insecure-demo-secret-change-me" } return c } func getenv(k, def string) string { if v := os.Getenv(k); v != "" { return v } return def } // ProviderList 返回去重、保序的后端名列表。 func (c *Config) ProviderList() []string { parts := strings.Split(c.ProviderOrder, ",") out := make([]string, 0, len(parts)) seen := make(map[string]struct{}, len(parts)) for _, p := range parts { p = strings.TrimSpace(strings.ToLower(p)) if p == "" || p == "both" || p == "all" { if p == "both" || p == "all" { for _, b := range []string{"cloudflare", "srs"} { if _, ok := seen[b]; !ok { seen[b] = struct{}{} out = append(out, b) } } } continue } if _, ok := seen[p]; !ok { seen[p] = struct{}{} out = append(out, p) } } return out }