- OAuth认证系统(Gitea + Lua扩展) - Git自动化操作(本地/SSH远程) - 实时进度WebSocket推送 - 现代化Tab界面UI - Cobra CLI命令行(init/version/serve) - 完整构建系统(Makefile + Taskfile) - UPX压缩支持(体积减少70%)
130 lines
2.7 KiB
Go
130 lines
2.7 KiB
Go
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
|
||
}
|