package config import ( "errors" "fmt" "net" "net/url" "os" "strings" "git.ipao.vip/rogee/go-sip/internal/tenant" ) // DispatcherEnvironment contains only deployment-owned startup values. The // SaaS read secret is never a task/AI setting and must not be logged. type DispatcherEnvironment struct { DispatcherID string SecretKey string SaaSBaseURL string RabbitMQURL string SQLitePath string } // LoadDispatcherEnvironment is pure inspection: it opens no database, queue or // network connection. The current executable accepts only isolated Mock mode. func LoadDispatcherEnvironment(mode string) (DispatcherEnvironment, error) { if mode != "mock" { return DispatcherEnvironment{}, errors.New("Dispatcher accepts only isolated Mock mode") } get := func(name string) (string, error) { value := os.Getenv(name) if strings.TrimSpace(value) == "" { return "", fmt.Errorf("%s is required", name) } return value, nil } var settings DispatcherEnvironment var err error if settings.DispatcherID, err = get("DISPATCHER_ID"); err != nil { return DispatcherEnvironment{}, err } if tenant.ValidateDispatcherID(settings.DispatcherID) != nil { return DispatcherEnvironment{}, errors.New("DISPATCHER_ID must be a canonical UUID v4") } if settings.SecretKey, err = get("DISPATCHER_SECRET_KEY"); err != nil { return DispatcherEnvironment{}, err } if settings.SaaSBaseURL, err = get("SAAS_BASE_URL"); err != nil { return DispatcherEnvironment{}, err } if !localEndpoint(settings.SaaSBaseURL, "http", "https") { return DispatcherEnvironment{}, errors.New("SAAS_BASE_URL must name a local Mock HTTP endpoint") } if settings.RabbitMQURL, err = get("RABBITMQ_URL"); err != nil { return DispatcherEnvironment{}, err } if !localEndpoint(settings.RabbitMQURL, "amqp", "amqps") { return DispatcherEnvironment{}, errors.New("RABBITMQ_URL must name a local Mock AMQP endpoint") } if settings.SQLitePath, err = get("DISPATCHER_SQLITE_PATH"); err != nil { return DispatcherEnvironment{}, err } return settings, nil } func localEndpoint(raw string, schemes ...string) bool { parsed, err := url.Parse(raw) if err != nil || parsed.Hostname() == "" || parsed.Opaque != "" || parsed.Fragment != "" || parsed.RawQuery != "" { return false } validScheme := false for _, scheme := range schemes { validScheme = validScheme || parsed.Scheme == scheme } if !validScheme { return false } host := parsed.Hostname() if strings.EqualFold(host, "localhost") { return true } ip := net.ParseIP(host) return ip != nil && ip.IsLoopback() }