From 24f551a39eae849d891da26cc91f90d354e3a2db Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Sun, 12 Jul 2026 02:44:05 +0800
Subject: [PATCH] chore(mas): refresh codebase memory after split
---
C1.source/privatevoice.src/internal/singleinstance/singleinstance_unix.go | 75 ++++++++++++++++++++++++++++++++++++-
1 files changed, 73 insertions(+), 2 deletions(-)
diff --git a/C1.source/privatevoice.src/internal/singleinstance/singleinstance_unix.go b/C1.source/privatevoice.src/internal/singleinstance/singleinstance_unix.go
index 4a2e38d..6738053 100755
--- a/C1.source/privatevoice.src/internal/singleinstance/singleinstance_unix.go
+++ b/C1.source/privatevoice.src/internal/singleinstance/singleinstance_unix.go
@@ -3,10 +3,13 @@
package singleinstance
import (
+ "errors"
"fmt"
"os"
"path/filepath"
"syscall"
+
+ "voicesnap/internal/paths"
)
type unixLock struct {
@@ -16,15 +19,83 @@
// Acquire tries to acquire a file lock. Returns error if another instance holds it.
func Acquire() (Lock, error) {
lockPath := filepath.Join(os.TempDir(), "privatevoice-input.lock")
+ if ensureErr := paths.Ensure(); ensureErr != nil {
+ return nil, fmt.Errorf("ensure app lock dir: %w", ensureErr)
+ }
+ appLockPath := paths.File("privatevoice-input.lock")
+ return acquireWithFallback(lockPath, appLockPath)
+}
+
+func acquireWithFallback(primaryPath, fallbackPath string) (Lock, error) {
+ lock, err := acquirePath(primaryPath)
+ if err == nil {
+ return lock, nil
+ }
+
+ var unavailable lockUnavailableError
+ if errors.As(err, &unavailable) {
+ return nil, err
+ }
+
+ lock, fallbackErr := acquirePath(fallbackPath)
+ if fallbackErr != nil {
+ return nil, fmt.Errorf("acquire temp lock: %w; acquire app lock: %v", err, fallbackErr)
+ }
+ return lock, nil
+}
+
+type lockOpenError struct {
+ path string
+ err error
+}
+
+func (e lockOpenError) Error() string {
+ return fmt.Sprintf("open lock %s: %v", e.path, e.err)
+}
+
+func (e lockOpenError) Unwrap() error {
+ return e.err
+}
+
+type lockAccessError struct {
+ path string
+ err error
+}
+
+func (e lockAccessError) Error() string {
+ return fmt.Sprintf("lock %s: %v", e.path, e.err)
+}
+
+func (e lockAccessError) Unwrap() error {
+ return e.err
+}
+
+type lockUnavailableError struct {
+ path string
+ err error
+}
+
+func (e lockUnavailableError) Error() string {
+ return fmt.Sprintf("another instance is already running: %s", e.path)
+}
+
+func (e lockUnavailableError) Unwrap() error {
+ return e.err
+}
+
+func acquirePath(lockPath string) (Lock, error) {
f, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0600)
if err != nil {
- return nil, err
+ return nil, lockOpenError{path: lockPath, err: err}
}
err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
if err != nil {
f.Close()
- return nil, fmt.Errorf("another instance is already running")
+ if errors.Is(err, syscall.EWOULDBLOCK) || errors.Is(err, syscall.EAGAIN) {
+ return nil, lockUnavailableError{path: lockPath, err: err}
+ }
+ return nil, lockAccessError{path: lockPath, err: err}
}
return &unixLock{file: f}, nil
--
Gitblit v1.9.3