Faster unchanged polls; orphan-core cleanup on listen ports; clearer busy-port errors; cores only from binDir; incremental server list; CSP without Google Fonts; single-instance activates existing window; close-to-tray without kill-others or balloon. Co-authored-by: Cursor <cursoragent@cursor.com>
37 lines
754 B
Go
37 lines
754 B
Go
//go:build !windows
|
|
|
|
package singleinstance
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
// Lock uses an exclusive lock file under the user config dir when available.
|
|
func Lock(appName string) (func(), error) {
|
|
if appName == "" {
|
|
appName = "Navis"
|
|
}
|
|
dir, err := os.UserConfigDir()
|
|
if err != nil {
|
|
return func() {}, nil
|
|
}
|
|
path := filepath.Join(dir, appName, "singleinstance.lock")
|
|
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
|
return func() {}, nil
|
|
}
|
|
f, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0o600)
|
|
if err != nil {
|
|
return func() {}, nil
|
|
}
|
|
if err := flockExclusive(f); err != nil {
|
|
_ = f.Close()
|
|
return nil, fmt.Errorf("%w", ErrAlreadyRunning)
|
|
}
|
|
return func() {
|
|
_ = funlock(f)
|
|
_ = f.Close()
|
|
}, nil
|
|
}
|