package config import ( "os" "path/filepath" "strconv" "strings" "github.com/joho/godotenv" ) type Config struct { Port string JWTSecret string DatabaseURL string Mode string // debug / release // OpenAPIKey 皮肤源头开放接口标识(Header: X-Api-Key,可公开给对接方) OpenAPIKey string // OpenAPISecret 签名密钥(仅用于 HMAC,不走 Header) OpenAPISecret string // OpenSignSkew 签名时间戳允许偏差(秒) OpenSignSkew int64 // OpenAPIDebug 开放接口详细调试日志 OpenAPIDebug bool // LogFile 日志文件路径;非空时同时写控制台与文件 LogFile string } // Load 加载配置:先尝试读取 .env,再读系统环境变量(已存在的系统环境变量优先级更高) func Load() *Config { loadDotEnv() mode := getEnv("GIN_MODE", "debug") // OPEN_API_DEBUG 优先;未设置时 debug 模式默认开启 debugOpen := getEnvBool("OPEN_API_DEBUG", mode == "debug" || mode == "") return &Config{ Port: getEnv("PORT", "8080"), JWTSecret: getEnv("JWT_SECRET", "affiliate-dash-dev-secret-change-me"), DatabaseURL: getEnv("DATABASE_URL", "postgres://affiliate:affiliate_dev_password@127.0.0.1:5432/affiliate_dash?sslmode=disable"), Mode: mode, OpenAPIKey: getEnv("OPEN_API_KEY", "sk_source_dev_key_change_me"), OpenAPISecret: getEnv("OPEN_API_SECRET", "sk_source_dev_secret_change_me"), OpenSignSkew: int64(getEnvInt("OPEN_SIGN_SKEW", 300)), OpenAPIDebug: debugOpen, LogFile: getEnv("LOG_FILE", "logs/app.log"), } } func getEnvBool(key string, def bool) bool { v := os.Getenv(key) if v == "" { return def } switch strings.ToLower(strings.TrimSpace(v)) { case "1", "true", "yes", "on": return true case "0", "false", "no", "off": return false default: return def } } // loadDotEnv 依次尝试常见路径,不覆盖已有环境变量 func loadDotEnv() { var paths []string if wd, err := os.Getwd(); err == nil { paths = append(paths, filepath.Join(wd, ".env"), filepath.Join(wd, "..", ".env"), // 在 backend/ 下启动时读仓库根 .env filepath.Join(wd, "backend", ".env"), // 在仓库根启动时 ) } paths = append(paths, ".env") seen := map[string]struct{}{} for _, p := range paths { abs, err := filepath.Abs(p) if err != nil { continue } if _, ok := seen[abs]; ok { continue } seen[abs] = struct{}{} _ = godotenv.Load(abs) // 忽略不存在;不覆盖已在环境中的变量 } } func getEnv(key, def string) string { if v := os.Getenv(key); v != "" { return v } return def } func getEnvInt(key string, def int) int { if v := os.Getenv(key); v != "" { if n, err := strconv.Atoi(v); err == nil { return n } } return def }