package config import ( "fmt" "log" "os" "path/filepath" legacy "weatherstation/internal/config" "gopkg.in/yaml.v3" ) type Config struct { Addr string UIServeDir string BigscreenDir string TemplateDir string StaticDir string DevEnableCORS bool Legacy *legacy.Config SMS SmsConfig AuthSecret string } // SmsConfig holds Aliyun SMS settings loaded from config/env. type SmsConfig struct { AccessKeyID string AccessKeySecret string SignName string TemplateCode string Endpoint string // optional, default dysmsapi.aliyuncs.com } func Load() Config { lg := legacy.GetConfig() port := lg.Server.WebPort if port <= 0 { port = 8080 } cfg := Config{ Addr: fmt.Sprintf(":%d", port), UIServeDir: "core/frontend/dist/ui", BigscreenDir: "core/frontend/dist/bigscreen", TemplateDir: "templates", StaticDir: "static", DevEnableCORS: true, Legacy: lg, SMS: SmsConfig{}, AuthSecret: "change-me-dev", // default dev secret; override with CORE_AUTH_SECRET } // Try load SMS from YAML (same search order as legacy) type smsAliyun struct { AccessKeyID string `yaml:"access_key_id"` AccessKeySecret string `yaml:"access_key_secret"` SignName string `yaml:"sign_name"` TemplateCode string `yaml:"template_code"` Endpoint string `yaml:"endpoint"` } var smsFile struct { SMS struct { Enabled bool `yaml:"enabled"` Provider string `yaml:"provider"` Aliyun smsAliyun `yaml:"aliyun"` } `yaml:"sms"` } // Probe possible locations exePath, _ := os.Executable() exeDir := "" if exePath != "" { exeDir = filepath.Dir(exePath) } candidates := []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"), } for _, p := range candidates { if b, err := os.ReadFile(p); err == nil { if err := yaml.Unmarshal(b, &smsFile); err == nil { cfg.SMS.AccessKeyID = smsFile.SMS.Aliyun.AccessKeyID cfg.SMS.AccessKeySecret = smsFile.SMS.Aliyun.AccessKeySecret if v := smsFile.SMS.Aliyun.SignName; v != "" { cfg.SMS.SignName = v } if v := smsFile.SMS.Aliyun.TemplateCode; v != "" { cfg.SMS.TemplateCode = v } if v := smsFile.SMS.Aliyun.Endpoint; v != "" { cfg.SMS.Endpoint = v } } break } } if v := os.Getenv("CORE_ADDR"); v != "" { cfg.Addr = v } if v := os.Getenv("CORE_UI_DIR"); v != "" { cfg.UIServeDir = v } if v := os.Getenv("CORE_BIGSCREEN_DIR"); v != "" { cfg.BigscreenDir = v } if v := os.Getenv("CORE_TEMPLATE_DIR"); v != "" { cfg.TemplateDir = v } if v := os.Getenv("CORE_STATIC_DIR"); v != "" { cfg.StaticDir = v } if v := os.Getenv("CORE_ENABLE_CORS"); v != "" { if v == "0" || v == "false" { cfg.DevEnableCORS = false } else { cfg.DevEnableCORS = true } } // Auth secret; do not log value if v := os.Getenv("CORE_AUTH_SECRET"); v != "" { cfg.AuthSecret = v } // SMS settings (do not log secrets) if v := os.Getenv("CORE_SMS_AK"); v != "" { cfg.SMS.AccessKeyID = v } if v := os.Getenv("CORE_SMS_SK"); v != "" { cfg.SMS.AccessKeySecret = v } if v := os.Getenv("CORE_SMS_SIGN"); v != "" { cfg.SMS.SignName = v } if v := os.Getenv("CORE_SMS_TPL"); v != "" { cfg.SMS.TemplateCode = v } if v := os.Getenv("CORE_SMS_ENDPOINT"); v != "" { cfg.SMS.Endpoint = v } log.Printf("config: addr=%s ui=%s bigscreen=%s tpl=%s static=%s cors=%v sms.sign=%v sms.tpl=%v auth.secret=%v", cfg.Addr, cfg.UIServeDir, cfg.BigscreenDir, cfg.TemplateDir, cfg.StaticDir, cfg.DevEnableCORS, cfg.SMS.SignName != "", cfg.SMS.TemplateCode != "", cfg.AuthSecret != "") return cfg }