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"` } // RadarConfig 雷达相关配置 type RadarConfig struct { // RealtimeIntervalMinutes 彩云实况拉取周期(分钟)。允许值:10、30、60。默认 10。 RealtimeIntervalMinutes int `yaml:"realtime_interval_minutes"` // RealtimeEnabled 是否启用彩云实况定时任务。默认 false(不下载)。 RealtimeEnabled bool `yaml:"realtime_enabled"` // Aliases 配置化的雷达别名列表(可用于前端选择与实况拉取)。 Aliases []RadarAlias `yaml:"aliases"` } // RadarAlias 配置中的雷达别名条目 type RadarAlias struct { Alias string `yaml:"alias"` Lat float64 `yaml:"lat"` Lon float64 `yaml:"lon"` Z int `yaml:"z"` Y int `yaml:"y"` X int `yaml:"x"` } // MySQLConfig MySQL 连接配置(用于 rtk_data) type MySQLConfig struct { Host string `yaml:"host"` Port int `yaml:"port"` User string `yaml:"user"` Password string `yaml:"password"` DBName string `yaml:"dbname"` Params string `yaml:"params"` // 例如: parseTime=true&loc=Asia%2FShanghai } type Config struct { Server ServerConfig `yaml:"server"` Database DatabaseConfig `yaml:"database"` Forecast ForecastConfig `yaml:"forecast"` Radar RadarConfig `yaml:"radar"` MySQL MySQLConfig `yaml:"mysql"` } 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 { // 尝试多个位置查找配置文件(兼容从仓库根目录、bin目录、系统安装路径运行) exePath, _ := os.Executable() exeDir := "" if exePath != "" { exeDir = filepath.Dir(exePath) } // 优先顺序:可执行文件所在目录,其次其父目录;然后回退到工作目录及上级,再到系统级/用户级 configPaths := []string{ // 可执行文件所在目录优先 filepath.Join(exeDir, "config.yaml"), filepath.Join(exeDir, "..", "config.yaml"), // 工作目录及其上级 "config.yaml", "../config.yaml", "../../config.yaml", // 系统级与用户级 "/etc/weatherstation/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 } if c.MySQL.Port <= 0 { c.MySQL.Port = 3306 } // Radar 默认拉取周期 if c.Radar.RealtimeIntervalMinutes != 10 && c.Radar.RealtimeIntervalMinutes != 30 && c.Radar.RealtimeIntervalMinutes != 60 { c.Radar.RealtimeIntervalMinutes = 10 } // 默认关闭实时抓取(可按需开启) // 若用户已有旧配置未设置该字段,默认为 false // CaiyunToken 允许为空:表示不启用彩云定时任务 return nil }