package main import ( "context" "fmt" "os" "time" "sentinel/pkg/config" "sentinel/pkg/device" "sentinel/pkg/docker" "sentinel/pkg/log" ) func main() { deviceID := device.GetDeviceID() // APP Logo InitPrint(deviceID) // Config InitConfigFile() // MQTT InitMQTT(deviceID) } func InitConfigFile() { // 第一次写入默认配置 cfg := config.AppConfig{ VersionCode: config.APP_VERSION, PID: os.Getpid(), NeedUpdate: false, ControlState: "DEGRADED", LastAliveAt: time.Now().Unix(), } // 写入文件 if err := config.WriteLocalConfig(&cfg); err != nil { log.Println("[config] 写入初始配置失败:", err) } } func InitPrint(deviceID string) { banner := ` ============================================================================== ██████ █████ ██████ ██████ ██ ██████ ██████ ██ ██ ██████ ██ ██ ██ ██ ██ ████ ██ ██ ███ ██ ██ █████ ██ ██ ██ ██ █████ ██ ██ ██ ██ █████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██████ ██ ██ ██ ██ ████ ██ ██████ █████ █████ ██████ ██ ██ █████ ██████ ██ ██ ██ ============================================================================== ` log.Println(banner) log.Println("Device id: "+deviceID, "\t版本号: ", config.APP_VERSION) // 第一次启动记录 } func InitMQTT(deviceID string) { var mqttSvc *MQTTService firstFail := true // 标记是否第一次失败 mqttSvc = NewMQTTService(config.MQTT_BROKER, deviceID, deviceID, config.PASSWORD, 60) for { err := mqttSvc.Connect() if err != nil { if firstFail { log.Error("物联网服务器连接失败,如未注册设备,请先注册: " + deviceID) firstFail = false } time.Sleep(3 * time.Second) // 5秒后重试 continue } break } defer mqttSvc.Close() dm, err := docker.NewDockerManager() if err != nil { log.Fatal(err) } biz := NewBusinessService(mqttSvc, deviceID, *dm) for { // MQTT业务 err := biz.Start() if err != nil { log.Error("business service start failed: " + err.Error()) fmt.Println("业务启动失败,5秒后重试...") time.Sleep(5 * time.Second) continue } break } // 第一次运行直接启动 biz.handleRestart() // 4️⃣ T2 超时自毁检查 tickerLost := time.NewTicker(10 * time.Second) defer tickerLost.Stop() go func() { for range tickerLost.C { cfg := config.LoadConfig() now := time.Now().Unix() if cfg.ControlState == "DEGRADED" && now-cfg.LastAliveAt > config.DAEMON_ALIVE_GAP_SECONDS { log.Println("[main] MQTT 长期失联,进入 CONTROL_LOST") cfg.ControlState = "CONTROL_LOST" cfg.LastAliveAt = time.Now().Unix() if err := config.WriteLocalConfig(cfg); err != nil { log.Println("[main] 写状态失败:", err) } // 停止业务容器 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) defer cancel() dm.StopAndRemoveContainer(ctx) // 自杀退出,让 daemon 重启 os.Exit(1) } } }() <-make(chan struct{}) }