package tray import ( "log" "os" "os/exec" "path/filepath" "runtime" "sync" ) var ( panelMu sync.Mutex panelProc *os.Process ) // launchPanel starts the syncwarden-panel subprocess if not already running. func launchPanel(baseURL string) { panelMu.Lock() defer panelMu.Unlock() // Check if already running if panelProc != nil { // Check if process is still alive if err := panelProc.Signal(os.Signal(nil)); err == nil { log.Println("panel already running") return } panelProc = nil } panelBin := panelBinaryPath() if panelBin == "" { log.Println("syncwarden-panel binary not found") return } cmd := exec.Command(panelBin, "-addr", baseURL) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Start(); err != nil { log.Printf("failed to start panel: %v", err) return } panelProc = cmd.Process log.Printf("panel started (pid %d)", cmd.Process.Pid) // Wait for process to exit in background go func() { _ = cmd.Wait() panelMu.Lock() panelProc = nil panelMu.Unlock() log.Println("panel exited") }() } // panelBinaryPath finds the syncwarden-panel binary next to the main binary. func panelBinaryPath() string { exe, err := os.Executable() if err != nil { return "" } dir := filepath.Dir(exe) name := "syncwarden-panel" if runtime.GOOS == "windows" { name = "syncwarden-panel.exe" } p := filepath.Join(dir, name) if _, err := os.Stat(p); err == nil { return p } return "" }