Files
vsix-hpl-toolbox/standalone/single_instance.go
2026-05-22 14:36:34 +08:00

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(userDataDir(), ".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())
}