package config import ( "fmt" "os" "strconv" "strings" "time" "github.com/joho/godotenv" ) // ConfigProvider defines the interface for configuration operations type ConfigProvider interface { GetString(key string) string GetInt(key string) int GetBool(key string) bool GetDuration(key string) time.Duration IsSet(key string) bool Validate() error GetDatabaseDSN() string GetDatabaseDSNForLogging() string GetServerAddress() string IsProduction() bool } // Config implements the ConfigProvider interface type Config struct { defaults map[string]string } // NewConfig creates a new configuration instance func NewConfig() ConfigProvider { // Load .env file if it exists _ = godotenv.Load() return &Config{ defaults: map[string]string{ "SERVER_HOST": "0.0.0.0", "SERVER_PORT": "8090", "SERVER_READ_TIMEOUT": "30s", "SERVER_WRITE_TIMEOUT": "30s", "SERVER_IDLE_TIMEOUT": "60s", "DB_HOST": "localhost", "DB_PORT": "5432", "DB_NAME": "users", "DB_USER": "postgres", "DB_PASSWORD": "postgres", "DB_SSLMODE": "disable", "DB_MAX_OPEN_CONNS": "25", "DB_MAX_IDLE_CONNS": "5", "DB_CONN_MAX_LIFETIME": "5m", "APP_ENV": "development", "APP_VERSION": "1.0.0", "LOG_LEVEL": "debug", "RATE_LIMIT_ENABLED": "true", "RATE_LIMIT_RPS": "100", "RATE_LIMIT_BURST": "200", "AUTH_PROVIDER": "header", "AUTH_HEADER_USER_EMAIL": "X-User-Email", }, } } func (c *Config) GetString(key string) string { if value := os.Getenv(key); value != "" { return value } return c.defaults[key] } func (c *Config) GetInt(key string) int { value := c.GetString(key) if value == "" { return 0 } intVal, err := strconv.Atoi(value) if err != nil { return 0 } return intVal } func (c *Config) GetBool(key string) bool { value := strings.ToLower(c.GetString(key)) return value == "true" || value == "1" } func (c *Config) GetDuration(key string) time.Duration { value := c.GetString(key) if value == "" { return 0 } duration, err := time.ParseDuration(value) if err != nil { return 0 } return duration } func (c *Config) IsSet(key string) bool { return os.Getenv(key) != "" || c.defaults[key] != "" } func (c *Config) Validate() error { required := []string{ "SERVER_HOST", "SERVER_PORT", "DB_HOST", "DB_PORT", "DB_NAME", "DB_USER", "DB_PASSWORD", } var missing []string for _, key := range required { if c.GetString(key) == "" { missing = append(missing, key) } } if len(missing) > 0 { return fmt.Errorf("missing required configuration keys: %s", strings.Join(missing, ", ")) } return nil } func (c *Config) GetDatabaseDSN() string { host := c.GetString("DB_HOST") port := c.GetString("DB_PORT") user := c.GetString("DB_USER") password := c.GetString("DB_PASSWORD") dbname := c.GetString("DB_NAME") sslmode := c.GetString("DB_SSLMODE") // Debug logging to see what values we're getting // fmt.Printf("DEBUG DSN VALUES: host=%s port=%s user=%s password=%s dbname=%s sslmode=%s\n", // host, port, user, password, dbname, sslmode) dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s", host, port, user, password, dbname, sslmode) return dsn } func (c *Config) GetDatabaseDSNForLogging() string { return fmt.Sprintf("host=%s port=%s user=%s dbname=%s sslmode=%s", c.GetString("DB_HOST"), c.GetString("DB_PORT"), c.GetString("DB_USER"), c.GetString("DB_NAME"), c.GetString("DB_SSLMODE"), ) } func (c *Config) GetServerAddress() string { return fmt.Sprintf("%s:%s", c.GetString("SERVER_HOST"), c.GetString("SERVER_PORT")) } func (c *Config) IsProduction() bool { return strings.ToLower(c.GetString("APP_ENV")) == "production" }