package config import ( "fmt" "os" "path/filepath" "gopkg.in/yaml.v3" ) // Config 项目根目录 config/config.{env}.yaml(敏感项已 gitignore)。 type Config struct { Feishu FeishuConfig `yaml:"feishu"` HisenseGeo HisenseGeoConfig `yaml:"hisense_geo"` } // FeishuConfig 飞书应用凭证。 type FeishuConfig struct { AppID string `yaml:"app_id"` AppSecret string `yaml:"app_secret"` } // HisenseGeoConfig 海信 GEO 生产环境接口配置。 type HisenseGeoConfig struct { BaseURL string `yaml:"base_url"` // 默认 https://geo-api.hisense.com Token string `yaml:"token"` // x-token,勿提交仓库 } // Load 按 APP_ENV 加载 config 目录下配置,默认 dev。 // 查找顺序: // 1. CONFIG_PATH / FEISHU_CONFIG_PATH // 2. 当前工作目录 ./config/config.{env}.yaml // 3. 向上查找含 config/ 目录的项目根下的 config/config.{env}.yaml func Load() (*Config, error) { env := os.Getenv("APP_ENV") if env == "" { env = "dev" } name := "config." + env + ".yaml" rel := filepath.Join("config", name) candidates := []string{} if p := os.Getenv("CONFIG_PATH"); p != "" { candidates = append(candidates, p) } if p := os.Getenv("FEISHU_CONFIG_PATH"); p != "" { candidates = append(candidates, p) } candidates = append(candidates, rel) if root := FindProjectRoot(); root != "" { candidates = append(candidates, filepath.Join(root, rel)) } var lastErr error for _, path := range candidates { data, err := os.ReadFile(path) if err != nil { lastErr = err continue } var cfg Config if err := yaml.Unmarshal(data, &cfg); err != nil { return nil, fmt.Errorf("解析配置失败 (%s): %w", path, err) } if cfg.HisenseGeo.BaseURL == "" { cfg.HisenseGeo.BaseURL = "https://geo-api.hisense.com" } return &cfg, nil } return nil, fmt.Errorf("未找到配置文件 %s(放在 config/ 目录,或设置 CONFIG_PATH): %w", rel, lastErr) } // FindProjectRoot 向上查找包含 config/ 目录的项目根。 func FindProjectRoot() string { wd, err := os.Getwd() if err != nil { return "" } dir := wd for { cfgDir := filepath.Join(dir, "config") if st, err := os.Stat(cfgDir); err == nil && st.IsDir() { return dir } parent := filepath.Dir(dir) if parent == dir { return "" } dir = parent } }