11 // tokenLockFileName is the lock file of the token file in the data directory.
12 const tokenLockFileName = "auth.lock"
14 // errTokensInUse tells that another onechat process uses the token file.
15 var errTokensInUse = errors.New("another onechat process uses the token file, such as the daemon")
17 // errLocked tells that another process owns the chat.
18 var errLocked = errors.New("another process owns the chat")
20 // lockTokens takes the lock of the token file in dir. Each process that reads
21 // or refreshes the tokens holds it, because a refresh in one process rotates
22 // the refresh token of the other and logs it out.
23 func lockTokens(dir string) (*os.File, error) {
24 lock, err := lockFile(filepath.Join(dir, tokenLockFileName))
25 if errors.Is(err, errLocked) {
26 return nil, errTokensInUse
32 // lockFile opens the file at path and takes an exclusive lock on it. The lock
33 // stays until the file closes or the process ends.
34 func lockFile(path string) (*os.File, error) {
35 file, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0o600)
37 return nil, fmt.Errorf("open lock file: %w", err)
40 err = syscall.Flock(int(file.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
41 if errors.Is(err, syscall.EWOULDBLOCK) {
46 return nil, errors.Join(fmt.Errorf("lock chat: %w", err), file.Close())