package config import ( "cs-bridge/internal/consts" "encoding/json" "fmt" "log" "os" "path/filepath" "sync" "github.com/go-yaml/yaml" "github.com/spf13/viper" ) var ( globalViper *viper.Viper globalViperOnce sync.Once configMu sync.RWMutex cachedConfig *Config ) // NewConfig 初始化配置 func NewConfig() *Config { globalViperOnce.Do(func() { globalViper = viper.New() }) configPath := loadConfigFile() if configPath == "" { log.Println("⚠️ 未找到配置文件,使用默认配置并导出为 config.yaml") cachedConfig = DefaultConfig() exportConfig(cachedConfig, "yaml") return cachedConfig } conf, err := parseConfig() if err != nil { log.Printf("⚠️ 解析配置失败,使用默认配置并导出为 config.yaml: %v", err) conf = DefaultConfig() exportConfig(conf, "yaml") } cachedConfig = conf return conf } // loadConfigFile 加载配置文件 func loadConfigFile() string { files := []string{ fmt.Sprintf("%s.yaml", consts.ConfigName), fmt.Sprintf("%s.yml", consts.ConfigName), } for _, file := range files { if _, err := os.Stat(file); err == nil { ext := filepath.Ext(file)[1:] globalViper.SetConfigFile(file) globalViper.SetConfigType(ext) globalViper.AddConfigPath(".") if err := globalViper.ReadInConfig(); err != nil { log.Printf("⚠️ 读取配置文件 %s 失败: %v", file, err) continue } log.Printf("✅ 成功加载配置文件: %s", file) return file } } return "" } // parseConfig 将配置解析为结构体 func parseConfig() (*Config, error) { configMu.Lock() defer configMu.Unlock() var conf Config if err := globalViper.Unmarshal(&conf); err != nil { return nil, err } return &conf, nil } // exportConfig 导出配置文件(默认保存为 config.yaml) func exportConfig(conf *Config, format string) { var ( data []byte err error ) switch format { case "json": data, err = json.MarshalIndent(conf, "", " ") case "yaml", "yml", "": format = "yaml" data, err = yaml.Marshal(conf) default: log.Printf("⚠️ 不支持的导出格式: %s", format) return } if err != nil { log.Printf("⚠️ 导出 %s 格式配置失败: %v", format, err) return } filename := fmt.Sprintf("%s.%s", consts.ConfigName, format) if err := os.WriteFile(filename, data, 0644); err != nil { log.Printf("⚠️ 写入配置文件 %s 失败: %v", filename, err) } else { log.Printf("✅ 已导出配置文件: %s", filename) } log.Printf("📋 当前 %s 配置:\n%s", format, data) } // GetConfig 获取当前配置(线程安全) func GetConfig() *Config { configMu.RLock() defer configMu.RUnlock() if cachedConfig == nil { return DefaultConfig() } conf := *cachedConfig return &conf }