Files
keeporg/internal/client/lock_windows.go
T
ReactorcoremeltdownandClaude Opus 5.5 ead82dc777 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>
2026-11-02 12:30:28 +01:00

31 lines
741 B
Go

//go:build windows
package client
import (
"errors"
"syscall"
)
// lockPath opens the file with no sharing at all, which Windows enforces
// until the handle closes.
func lockPath(path string) (func(), error) {
p, err := syscall.UTF16PtrFromString(path)
if err != nil {
return nil, err
}
h, err := syscall.CreateFile(p, syscall.GENERIC_READ|syscall.GENERIC_WRITE,
0, nil, syscall.OPEN_ALWAYS, syscall.FILE_ATTRIBUTE_HIDDEN, 0)
if err != nil {
if errors.Is(err, errSharingViolation) {
return nil, ErrMirrorBusy
}
return nil, err
}
return func() { syscall.CloseHandle(h) }, nil
}
// errSharingViolation is ERROR_SHARING_VIOLATION, which package syscall
// does not name.
const errSharingViolation = syscall.Errno(32)