package config import ( "fmt" "os" "strconv" "time" ) // Config holds runtime configuration loaded from environment variables. type Config struct { AppName string NodeID string ControlPlaneURL string NodeToken string HealthListenAddr string HeartbeatInterval time.Duration ReconnectBackoff time.Duration DataDir string DockerSocket string LogLevel string TLSCertFile string TLSKeyFile string TLSCAFile string TLSSkipVerify bool ShutdownGracePeriod time.Duration } // Load reads configuration from environment variables with sensible defaults for development. func Load() (*Config, error) { cfg := &Config{ AppName: envOrDefault("APP_NAME", "HexaHost GameCloud"), NodeID: os.Getenv("NODE_ID"), ControlPlaneURL: os.Getenv("NODE_AGENT_PUBLIC_URL"), NodeToken: os.Getenv("NODE_TOKEN"), HealthListenAddr: envOrDefault("NODE_AGENT_HEALTH_ADDR", ":9100"), HeartbeatInterval: durationFromEnv("NODE_HEARTBEAT_INTERVAL", 10*time.Second), ReconnectBackoff: durationFromEnv("NODE_RECONNECT_BACKOFF", 5*time.Second), DataDir: envOrDefault("NODE_DATA_DIR", "/var/lib/hexahost-gamecloud"), DockerSocket: envOrDefault("DOCKER_HOST", "unix:///var/run/docker.sock"), LogLevel: envOrDefault("LOG_LEVEL", "info"), TLSCertFile: os.Getenv("NODE_TLS_CERT"), TLSKeyFile: os.Getenv("NODE_TLS_KEY"), TLSCAFile: os.Getenv("NODE_CA_CERT"), TLSSkipVerify: boolFromEnv("NODE_TLS_SKIP_VERIFY", false), ShutdownGracePeriod: durationFromEnv("NODE_SHUTDOWN_GRACE", 30*time.Second), } if cfg.NodeID == "" { return nil, fmt.Errorf("NODE_ID is required") } if cfg.ControlPlaneURL == "" { return nil, fmt.Errorf("NODE_AGENT_PUBLIC_URL is required") } return cfg, nil } func envOrDefault(key, fallback string) string { if v := os.Getenv(key); v != "" { return v } return fallback } func durationFromEnv(key string, fallback time.Duration) time.Duration { raw := os.Getenv(key) if raw == "" { return fallback } d, err := time.ParseDuration(raw) if err != nil { return fallback } return d } func boolFromEnv(key string, fallback bool) bool { raw := os.Getenv(key) if raw == "" { return fallback } v, err := strconv.ParseBool(raw) if err != nil { return fallback } return v }