package main import ( "fmt" "os" "strconv" "strings" "github.com/joho/godotenv" ) type Config struct { Port string ListenNetwork string ListenAddress string UnixSocketPerm os.FileMode DatabaseURL string StorageDir string DevMode bool } func LoadConfig() (Config, error) { _ = godotenv.Load() cfg := Config{ Port: envOrDefault("PORT", "8080"), ListenNetwork: strings.ToLower(envOrDefault("LISTEN_NETWORK", "tcp")), ListenAddress: strings.TrimSpace(os.Getenv("LISTEN_ADDRESS")), DatabaseURL: os.Getenv("DATABASE_URL"), StorageDir: envOrDefault("STORAGE_DIR", "uploads"), DevMode: strings.EqualFold(envOrDefault("DEV_MODE", "false"), "true"), } if cfg.ListenAddress == "" { cfg.ListenAddress = ":" + cfg.Port } socketPerm, err := parseFileMode(envOrDefault("UNIX_SOCKET_PERM", "0660")) if err != nil { return Config{}, fmt.Errorf("invalid UNIX_SOCKET_PERM: %w", err) } cfg.UnixSocketPerm = socketPerm if cfg.DatabaseURL == "" { return Config{}, fmt.Errorf("DATABASE_URL is required") } switch cfg.ListenNetwork { case "tcp", "unix": default: return Config{}, fmt.Errorf("LISTEN_NETWORK must be tcp or unix") } if cfg.ListenNetwork == "unix" && cfg.ListenAddress == "" { return Config{}, fmt.Errorf("LISTEN_ADDRESS is required when LISTEN_NETWORK=unix") } return cfg, nil } func envOrDefault(key, fallback string) string { value := os.Getenv(key) if value == "" { return fallback } return value } func parseFileMode(value string) (os.FileMode, error) { trimmed := strings.TrimSpace(value) perm, err := strconv.ParseUint(trimmed, 8, 32) if err != nil { return 0, err } return os.FileMode(perm), nil }