package main import ( "context" "flag" "log" "sync" "time" "weatherstation/internal/database" "weatherstation/internal/forecast" "weatherstation/internal/selftest" "weatherstation/internal/server" "weatherstation/internal/tools" ) func main() { // 命令行参数 var webOnly = flag.Bool("web", false, "只启动Web服务器(Gin)") var udpOnly = flag.Bool("udp", false, "只启动UDP服务器") // 调试:回填10分钟表 var doBackfill = flag.Bool("backfill", false, "将16s原始数据聚合写入10分钟表(调试用途)") var bfStation = flag.String("station", "", "指定站点ID(为空则全站回填)") var bfFrom = flag.String("from", "", "回填起始时间,格式:YYYY-MM-DD HH:MM:SS") var bfTo = flag.String("to", "", "回填结束时间,格式:YYYY-MM-DD HH:MM:SS") var bfWrap = flag.Float64("wrap", 0, "回绕一圈对应毫米值(mm),<=0 则降级为仅计当前值") // 自检控制 var noSelftest = flag.Bool("no-selftest", false, "跳过启动自检") var selftestOnly = flag.Bool("selftest_only", false, "仅执行自检后退出") // 预报抓取 var forecastOnly = flag.Bool("forecast_only", false, "仅执行一次open-meteo拉取并退出") flag.Parse() // 设置日志 server.SetupLogger() // 初始化数据库连接 _ = database.GetDB() // 确保数据库连接已初始化 defer database.Close() // 启动前自检 if !*noSelftest { if err := selftest.Run(context.Background()); err != nil { log.Fatalf("启动自检失败: %v", err) } if *selftestOnly { log.Println("自检完成,按 --selftest_only 要求退出") return } } // 单次 open-meteo 拉取 if *forecastOnly { if err := forecast.RunOpenMeteoFetch(context.Background()); err != nil { log.Fatalf("open-meteo 拉取失败: %v", err) } log.Println("open-meteo 拉取完成") return } // Backfill 调试路径 if *doBackfill { if *bfFrom == "" || *bfTo == "" { log.Fatalln("backfill 需要提供 --from 与 --to 时间") } fromT, err := time.Parse("2006-01-02 15:04:05", *bfFrom) if err != nil { log.Fatalf("解析from失败: %v", err) } toT, err := time.Parse("2006-01-02 15:04:05", *bfTo) if err != nil { log.Fatalf("解析to失败: %v", err) } ctx := context.Background() if err := tools.RunBackfill10Min(ctx, tools.BackfillOptions{ StationID: *bfStation, FromTime: fromT, ToTime: toT, WrapCycleMM: *bfWrap, BucketMinutes: 10, }); err != nil { log.Fatalf("回填失败: %v", err) } log.Println("回填完成") return } // 根据命令行参数启动服务 if *webOnly { // 只启动Web服务器 log.Println("启动Web服务器模式...") if err := server.StartGinServer(); err != nil { log.Fatalf("启动Web服务器失败: %v", err) } } else if *udpOnly { // 只启动UDP服务器 log.Println("启动UDP服务器模式...") if err := server.StartUDPServer(); err != nil { log.Fatalf("启动UDP服务器失败: %v", err) } } else { // 同时启动UDP和Web服务器 log.Println("启动完整模式:UDP + Web服务器...") var wg sync.WaitGroup wg.Add(2) // 启动UDP服务器 go func() { defer wg.Done() log.Println("正在启动UDP服务器...") if err := server.StartUDPServer(); err != nil { log.Printf("UDP服务器异常退出: %v", err) } }() // 启动Web服务器 go func() { defer wg.Done() log.Println("正在启动Web服务器...") if err := server.StartGinServer(); err != nil { log.Printf("Web服务器异常退出: %v", err) } }() wg.Wait() } }