package config import ( "os" "path/filepath" "strconv" ) // Config holds all runtime configuration resolved from environment variables. type Config struct { Port int AdminToken string WorksDir string ConfigDir string Debug bool } // Load reads environment variables and returns a fully-populated Config. // // Directory resolution priority: // 1. SPROUTWORKCOLLECT_WORKS_DIR / SPROUTWORKCOLLECT_CONFIG_DIR (per-dir override) // 2. SPROUTWORKCOLLECT_DATA_DIR / DATA_DIR (data root, works/ and config/ appended) // 3. ./data/works and ./data/config (relative to current working directory) func Load() *Config { loadDotEnv() cfg := &Config{ Port: 5000, // Do not commit real admin tokens; override via ADMIN_TOKEN / SPROUTWORKCOLLECT_ADMIN_TOKEN. AdminToken: "change-me", } if v := os.Getenv("PORT"); v != "" { if p, err := strconv.Atoi(v); err == nil { cfg.Port = p } } if v := firstEnv("SPROUTWORKCOLLECT_ADMIN_TOKEN", "ADMIN_TOKEN"); v != "" { cfg.AdminToken = v } dbg := os.Getenv("GIN_DEBUG") cfg.Debug = dbg == "1" || dbg == "true" dataDir := firstEnv("SPROUTWORKCOLLECT_DATA_DIR", "DATA_DIR") worksDir := firstEnv("SPROUTWORKCOLLECT_WORKS_DIR", "WORKS_DIR") if worksDir == "" { if dataDir != "" { worksDir = filepath.Join(dataDir, "works") } else { wd, _ := os.Getwd() worksDir = filepath.Join(wd, "data", "works") } } configDir := firstEnv("SPROUTWORKCOLLECT_CONFIG_DIR", "CONFIG_DIR") if configDir == "" { if dataDir != "" { configDir = filepath.Join(dataDir, "config") } else { wd, _ := os.Getwd() configDir = filepath.Join(wd, "data", "config") } } cfg.WorksDir = filepath.Clean(worksDir) cfg.ConfigDir = filepath.Clean(configDir) return cfg } func firstEnv(keys ...string) string { for _, k := range keys { if v := os.Getenv(k); v != "" { return v } } return "" }