package config import ( "bufio" "os" "strconv" "strings" "time" ) func init() { loadDotEnv() } func loadDotEnv() { file, err := os.Open(".env") if err != nil { return } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if line == "" || strings.HasPrefix(line, "#") { continue } parts := strings.SplitN(line, "=", 2) if len(parts) != 2 { continue } key := strings.TrimSpace(parts[0]) val := strings.TrimSpace(parts[1]) if (strings.HasPrefix(val, "\"") && strings.HasSuffix(val, "\"")) || (strings.HasPrefix(val, "'") && strings.HasSuffix(val, "'")) { val = val[1 : len(val)-1] } if os.Getenv(key) == "" { os.Setenv(key, val) } } } type Config struct { Host string Port string Database DatabaseConfig Valkey ValkeyConfig MinIO MinIOConfig LiveKit LiveKitConfig WebPush WebPushConfig Session SessionConfig Giphy GiphyConfig } type DatabaseConfig struct { Host string Port string User string Password string Database string SSLMode string } type ValkeyConfig struct { URL string } type MinIOConfig struct { Endpoint string AccessKey string SecretKey string Bucket string UseSSL bool } type LiveKitConfig struct { URL string APIKey string Secret string } type WebPushConfig struct { PublicKey string PrivateKey string Subject string } type GiphyConfig struct { APIKey string } type SessionConfig struct { CookieName string Duration time.Duration } func Load() *Config { return &Config{ Host: getEnv("DUMPSTER_HOST", "localhost"), Port: getEnv("DUMPSTER_PORT", "8080"), Database: DatabaseConfig{ Host: getEnv("POSTGRES_HOST", "localhost"), Port: getEnv("POSTGRES_PORT", "5432"), User: getEnv("POSTGRES_USER", "dumpster"), Password: getEnv("POSTGRES_PASSWORD", "dumpster"), Database: getEnv("POSTGRES_DB", "dumpster"), SSLMode: getEnv("POSTGRES_SSLMODE", "require"), }, Valkey: ValkeyConfig{ URL: getEnv("VALKEY_URL", "redis://localhost:***@example.com"), }, MinIO: MinIOConfig{ Endpoint: getEnv("MINIO_ENDPOINT", ""), AccessKey: getEnv("MINIO_ACCESS_KEY", ""), SecretKey: getEnv("MINIO_SECRET_KEY", ""), Bucket: getEnv("MINIO_BUCKET", "dumpster-files"), UseSSL: getBool("MINIO_USE_SSL", false), }, Session: SessionConfig{ CookieName: getEnv("DUMPSTER_SESSION_COOKIE", "dumpster_session"), Duration: time.Duration(getInt("DUMPSTER_SESSION_DAYS", 30)) * 24 * time.Hour, }, LiveKit: LiveKitConfig{ URL: getEnv("LIVEKIT_URL", ""), APIKey: getEnv("LIVEKIT_API_KEY", ""), Secret: getEnv("LIVEKIT_API_SECRET", ""), }, WebPush: WebPushConfig{ PublicKey: getEnv("VAPID_PUBLIC_KEY", ""), PrivateKey: getEnv("VAPID_PRIVATE_KEY", ""), Subject: getEnv("VAPID_SUBJECT", ""), }, Giphy: GiphyConfig{ APIKey: getEnv("GIPHY_API_KEY", ""), }, } } func (c *Config) DatabaseDSN() string { return "postgres://" + c.Database.User + ":" + c.Database.Password + "@" + c.Database.Host + ":" + c.Database.Port + "/" + c.Database.Database + "?sslmode=" + c.Database.SSLMode } func getEnv(key, fallback string) string { if v := os.Getenv(key); v != "" { return strings.TrimSpace(v) } return fallback } func getBool(key string, fallback bool) bool { s := strings.ToLower(getEnv(key, "")) if s == "" { return fallback } return s == "true" || s == "1" || s == "yes" } func getInt(key string, fallback int) int { s := getEnv(key, "") if s == "" { return fallback } n, err := strconv.Atoi(s) if err != nil { return fallback } return n }