package config import ( "backend/typesdefs" "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 { Strategy typesdefs.StorageStrategy Path string TempLimit int Minio struct { URL string RootUser string Password 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.Path = filepath.Join(pwd, "storage") Cfg.Storage.TempLimit = getEnvAsInt("TEMP_STORAGE_LIMIT", 5) strategy := getEnv("STORAGE_STRATEGY", "fs") if strategy == "s3" || strategy == "minio" { Cfg.Storage.Minio.URL = getEnv("MINIO_URL", "") Cfg.Storage.Minio.RootUser = getEnv("MINIO_ROOT_USER", "") Cfg.Storage.Minio.Password = getEnv("MINIO_ROOT_PASSWORD", "") if Cfg.Storage.Minio.URL == "" || Cfg.Storage.Minio.RootUser == "" || Cfg.Storage.Minio.Password == "" { fmt.Println("Error: MINIO_ROOT_USER, MINIO_ROOT_PASSWORD and MINIO_URL must be set") Cfg.Storage.Strategy = typesdefs.FS } else { Cfg.Storage.Strategy = typesdefs.S3 } } else { Cfg.Storage.Strategy = typesdefs.FS } // Server config Cfg.Server.Port = getEnvAsInt("PORT", 1323) if os.Getenv("ASPNETCORE_PORT") != "" { Cfg.Server.Port = getEnvAsInt("ASPNETCORE_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 }