Turn the desktop client into a system tray application
Started without a command, keeporg now shows a padlock in the system tray with a menu like midi-webhook's: a status line, the mirror folder, each database with its state, Sync Now, browser sign-in and sign-out, the web interface, the configuration, the log, Start at Login, About and Quit. The commands are unchanged. config.json now carries every client setting (device_label, request_timeout_seconds, ca_file, log_file, notifications), is written in full on first start and is reloaded by the tray when saved. A lock in the mirror directory admits one agent at a time, since the tray, `keeporg run` and a service unit could otherwise race each other. The tray uses fyne.io/systray: pure Go on Linux, BSD and Windows, cgo on macOS only. The server keeps no third-party dependencies. Desktop versions go to 0.5.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d314188247
commit
ead82dc777
@@ -0,0 +1,32 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// lockFile marks a mirror directory as being synchronized by one agent. Two
|
||||
// agents on one directory would each think the other's writes were local
|
||||
// saves and push them back, so the tray, `keeporg run` and a service unit
|
||||
// started side by side must not all sync.
|
||||
const lockFile = ".keeporg.lock"
|
||||
|
||||
// ErrMirrorBusy means another agent already holds the mirror directory.
|
||||
var ErrMirrorBusy = errors.New("another keeporg agent is already synchronizing this directory")
|
||||
|
||||
// LockDir takes the mirror directory's lock for this process. The operating
|
||||
// system releases it when the process exits, however it exits, so a crash
|
||||
// never leaves a directory locked.
|
||||
func LockDir(dir string) (unlock func(), err error) {
|
||||
if err := os.MkdirAll(dir, 0o700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path := filepath.Join(dir, lockFile)
|
||||
unlock, err = lockPath(path)
|
||||
if errors.Is(err, ErrMirrorBusy) {
|
||||
return nil, fmt.Errorf("%s: %w", dir, err)
|
||||
}
|
||||
return unlock, err
|
||||
}
|
||||
Reference in New Issue
Block a user