package config import ( "fmt" "os" "path/filepath" "strconv" "sync" "github.com/joho/godotenv" ) // Config holds all application configuration type Config struct { Database struct { Host string Port int User string Password string DBName string SSLMode string } Images struct { Enabled bool ConcurrentLimit int Path string } Storage struct { Endpoint string Token string } Server struct { Port int } } var ( Cfg Config once sync.Once ) // Load initializes configuration once func Load() *Config { once.Do(func() { // Try loading from .env file first _ = godotenv.Load() pwd, err := os.Getwd() if err != nil { fmt.Println(err) os.Exit(1) } // Database config Cfg.Database.Host = getEnv("PGHOST", "localhost") Cfg.Database.Port = getEnvAsInt("PGPORT", 5432) Cfg.Database.User = getEnv("POSTGRES_USER", "postgres") Cfg.Database.Password = getEnv("POSTGRES_PASSWORD", "") Cfg.Database.DBName = getEnv("POSTGRES_DB", "postgres") Cfg.Database.SSLMode = getEnv("PGSSLMODE", "true") // Image processing config Cfg.Images.Enabled = getEnvAsBool("IMAGEOPTION", true) Cfg.Images.ConcurrentLimit = getEnvAsInt("CONCURRENT_IMAGES", 5) Cfg.Images.Path = filepath.Join(pwd, "images") // Storage config Cfg.Storage.Endpoint = getEnv("STORAGE_URL", "") Cfg.Storage.Token = getEnv("STORAGE_TOKEN", "") // Server config Cfg.Server.Port = getEnvAsInt("PORT", 1323) // Validate required config if Cfg.Database.Password == "" { fmt.Printf("required environment variable POSTGRES_PASSWORD not set\n") } }) return &Cfg } // Helper functions func getEnv(key, fallback string) string { if value, exists := os.LookupEnv(key); exists { return value } return fallback } func getEnvAsInt(key string, fallback int) int { if strValue := getEnv(key, ""); strValue != "" { if value, err := strconv.Atoi(strValue); err == nil { return value } } return fallback } func getEnvAsBool(key string, fallback bool) bool { if strValue := getEnv(key, ""); strValue != "" { if value, err := strconv.ParseBool(strValue); err == nil { return value } } return fallback }