package config import ( "fmt" "os" "path/filepath" "sync" "gopkg.in/yaml.v3" ) type ServerConfig struct { WebPort int `yaml:"web_port"` // Gin Web服务器端口 UDPPort int `yaml:"udp_port"` // UDP服务器端口 } type DatabaseConfig struct { Host string `yaml:"host"` Port int `yaml:"port"` User string `yaml:"user"` Password string `yaml:"password"` DBName string `yaml:"dbname"` SSLMode string `yaml:"sslmode"` } // ForecastConfig 预报相关配置 type ForecastConfig struct { CaiyunToken string `yaml:"caiyun_token"` } type Config struct { Server ServerConfig `yaml:"server"` Database DatabaseConfig `yaml:"database"` Forecast ForecastConfig `yaml:"forecast"` } var ( instance *Config once sync.Once ) // GetConfig 返回配置单例 func GetConfig() *Config { once.Do(func() { instance = &Config{} if err := instance.loadConfig(); err != nil { panic(fmt.Sprintf("加载配置文件失败: %v", err)) } }) return instance } // loadConfig 从配置文件加载配置 func (c *Config) loadConfig() error { // 尝试多个位置查找配置文件 configPaths := []string{ "config.yaml", // 当前目录 "../config.yaml", // 上级目录 "../../config.yaml", // 项目根目录 filepath.Join(os.Getenv("HOME"), ".weatherstation/config.yaml"), // 用户目录 } var data []byte var err error for _, path := range configPaths { if data, err = os.ReadFile(path); err == nil { break } } if err != nil { return fmt.Errorf("未找到配置文件: %v", err) } if err := yaml.Unmarshal(data, c); err != nil { return fmt.Errorf("解析配置文件失败: %v", err) } return c.validate() } // validate 验证配置有效性 func (c *Config) validate() error { if c.Server.WebPort <= 0 { c.Server.WebPort = 10003 // 默认Web端口 } if c.Server.UDPPort <= 0 { c.Server.UDPPort = 10001 // 默认UDP端口 } if c.Database.SSLMode == "" { c.Database.SSLMode = "disable" // 默认禁用SSL } // CaiyunToken 允许为空:表示不启用彩云定时任务 return nil }