Ports all five tools to a single 7.5 MB Windows exe with an embedded WebView2 window, file-based config, single-instance focus, and clean shutdown. Adds build.ps1 to build both targets from one command. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
69 lines
1.7 KiB
Go
69 lines
1.7 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
func lockFilePath() string {
|
|
return filepath.Join(appDir(), ".hpltoolbox.lock")
|
|
}
|
|
|
|
// focusExistingInstance returns true if another instance was found and
|
|
// successfully asked to focus its window. In that case the caller should exit.
|
|
// Returns false if no live instance exists (and clears any stale lock).
|
|
func focusExistingInstance() bool {
|
|
data, err := os.ReadFile(lockFilePath())
|
|
if err != nil {
|
|
return false
|
|
}
|
|
parts := strings.Split(strings.TrimSpace(string(data)), "\n")
|
|
if len(parts) != 2 {
|
|
_ = os.Remove(lockFilePath())
|
|
return false
|
|
}
|
|
pid, errPid := strconv.Atoi(strings.TrimSpace(parts[0]))
|
|
port, errPort := strconv.Atoi(strings.TrimSpace(parts[1]))
|
|
if errPid != nil || errPort != nil {
|
|
_ = os.Remove(lockFilePath())
|
|
return false
|
|
}
|
|
|
|
// Quick liveness check: PID must exist.
|
|
if proc, err := os.FindProcess(pid); err != nil || proc == nil {
|
|
_ = os.Remove(lockFilePath())
|
|
return false
|
|
}
|
|
|
|
// Ask the running instance to focus its window.
|
|
client := &http.Client{Timeout: 1500 * time.Millisecond}
|
|
url := fmt.Sprintf("http://127.0.0.1:%d/api/focus", port)
|
|
resp, err := client.Post(url, "application/json", bytes.NewReader(nil))
|
|
if err != nil {
|
|
// Lock file is stale (process died but didn't clean up).
|
|
_ = os.Remove(lockFilePath())
|
|
return false
|
|
}
|
|
_ = resp.Body.Close()
|
|
if resp.StatusCode != http.StatusOK {
|
|
_ = os.Remove(lockFilePath())
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func writeLockFile(port int) error {
|
|
content := fmt.Sprintf("%d\n%d\n", os.Getpid(), port)
|
|
return os.WriteFile(lockFilePath(), []byte(content), 0644)
|
|
}
|
|
|
|
func removeLockFile() {
|
|
_ = os.Remove(lockFilePath())
|
|
}
|