// Package config loads device-control-service settings from environment // variables, matching the names used in the repo-root .env.example. package config import ( "fmt" "os" "strconv" "time" ) type Config struct { GRPCPort int MQTTBrokerURL string MQTTClientID string RedisAddr string RedisPassword string RedisDB int RabbitMQURL string HealthCheckTimeout time.Duration HealthCheckInterval time.Duration } func Load() (Config, error) { cfg := Config{ MQTTBrokerURL: fmt.Sprintf("tcp://%s:%s", getEnv("MQTT_HOST", "localhost"), getEnv("MQTT_PORT", "1883")), MQTTClientID: getEnv("DEVICE_CONTROL_MQTT_CLIENT_ID", "device-control-service"), RedisAddr: fmt.Sprintf("%s:%s", getEnv("REDIS_HOST", "localhost"), getEnv("REDIS_PORT", "6379")), RedisPassword: getEnv("REDIS_PASSWORD", ""), RabbitMQURL: fmt.Sprintf("amqp://%s:%s@%s:%s/", getEnv("RABBITMQ_USER", "guest"), getEnv("RABBITMQ_PASSWORD", "guest"), getEnv("RABBITMQ_HOST", "localhost"), getEnv("RABBITMQ_PORT", "5672"), ), } var err error if cfg.GRPCPort, err = getEnvInt("DEVICE_CONTROL_GRPC_PORT", 50051); err != nil { return Config{}, err } if cfg.RedisDB, err = getEnvInt("REDIS_DB", 0); err != nil { return Config{}, err } if cfg.HealthCheckTimeout, err = getEnvDuration("DEVICE_CONTROL_HEALTHCHECK_TIMEOUT", 60*time.Second); err != nil { return Config{}, err } if cfg.HealthCheckInterval, err = getEnvDuration("DEVICE_CONTROL_HEALTHCHECK_INTERVAL", 15*time.Second); err != nil { return Config{}, err } return cfg, nil } func getEnv(key, fallback string) string { if v := os.Getenv(key); v != "" { return v } return fallback } func getEnvInt(key string, fallback int) (int, error) { v := os.Getenv(key) if v == "" { return fallback, nil } n, err := strconv.Atoi(v) if err != nil { return 0, fmt.Errorf("%s: %w", key, err) } return n, nil } func getEnvDuration(key string, fallback time.Duration) (time.Duration, error) { v := os.Getenv(key) if v == "" { return fallback, nil } d, err := time.ParseDuration(v) if err != nil { return 0, fmt.Errorf("%s: %w", key, err) } return d, nil }