fix: surface doctor lock owner state (#105) (thanks @artemgetmann)
This commit is contained in:
parent
e73dba0ecb
commit
0ce920839e
@ -8,6 +8,7 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- Doctor: report lock owner PID and distinguish paired stores locked by another process. (#105 — thanks @artemgetmann)
|
||||
- Media: recover panics per download job so one bad payload no longer drains the worker pool. (#179 — thanks @shaun0927)
|
||||
- Messages: attribute history messages from LID-addressed groups to the top-level participant sender. (#19 — thanks @entropyy0)
|
||||
- Messages: show display text for replies, reactions, and media in `messages context`. (#183 — thanks @fuleinist)
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
@ -14,6 +15,31 @@ import (
|
||||
"github.com/steipete/wacli/internal/out"
|
||||
)
|
||||
|
||||
func parseLockOwnerPID(lockInfo string) int {
|
||||
for _, line := range strings.Split(lockInfo, "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if !strings.HasPrefix(line, "pid=") {
|
||||
continue
|
||||
}
|
||||
pid, err := strconv.Atoi(strings.TrimSpace(strings.TrimPrefix(line, "pid=")))
|
||||
if err == nil && pid > 0 {
|
||||
return pid
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func doctorConnectionState(authed, connected, lockHeld, connect bool) string {
|
||||
switch {
|
||||
case connected:
|
||||
return "connected"
|
||||
case authed && lockHeld && !connect:
|
||||
return "locked_by_other_process"
|
||||
default:
|
||||
return "disconnected"
|
||||
}
|
||||
}
|
||||
|
||||
func newDoctorCmd(flags *rootFlags) *cobra.Command {
|
||||
var connect bool
|
||||
|
||||
@ -57,23 +83,28 @@ func newDoctorCmd(flags *rootFlags) *cobra.Command {
|
||||
connected = true
|
||||
}
|
||||
}
|
||||
lockOwnerPID := parseLockOwnerPID(lockInfo)
|
||||
|
||||
type report struct {
|
||||
StoreDir string `json:"store_dir"`
|
||||
LockHeld bool `json:"lock_held"`
|
||||
LockInfo string `json:"lock_info,omitempty"`
|
||||
Authed bool `json:"authenticated"`
|
||||
Connected bool `json:"connected"`
|
||||
FTSEnabled bool `json:"fts_enabled"`
|
||||
StoreDir string `json:"store_dir"`
|
||||
LockHeld bool `json:"lock_held"`
|
||||
LockInfo string `json:"lock_info,omitempty"`
|
||||
LockOwnerPID int `json:"lock_owner_pid,omitempty"`
|
||||
Authed bool `json:"authenticated"`
|
||||
Connected bool `json:"connected"`
|
||||
ConnectionState string `json:"connection_state"`
|
||||
FTSEnabled bool `json:"fts_enabled"`
|
||||
}
|
||||
|
||||
rep := report{
|
||||
StoreDir: storeDir,
|
||||
LockHeld: lockHeld,
|
||||
LockInfo: lockInfo,
|
||||
Authed: authed,
|
||||
Connected: connected,
|
||||
FTSEnabled: a.DB().HasFTS(),
|
||||
StoreDir: storeDir,
|
||||
LockHeld: lockHeld,
|
||||
LockInfo: lockInfo,
|
||||
LockOwnerPID: lockOwnerPID,
|
||||
Authed: authed,
|
||||
Connected: connected,
|
||||
ConnectionState: doctorConnectionState(authed, connected, lockHeld, connect),
|
||||
FTSEnabled: a.DB().HasFTS(),
|
||||
}
|
||||
|
||||
if flags.asJSON {
|
||||
@ -86,8 +117,12 @@ func newDoctorCmd(flags *rootFlags) *cobra.Command {
|
||||
if rep.LockHeld && rep.LockInfo != "" {
|
||||
fmt.Fprintf(w, "LOCK_INFO\t%s\n", rep.LockInfo)
|
||||
}
|
||||
if rep.LockOwnerPID > 0 {
|
||||
fmt.Fprintf(w, "LOCK_OWNER_PID\t%d\n", rep.LockOwnerPID)
|
||||
}
|
||||
fmt.Fprintf(w, "AUTHENTICATED\t%v\n", rep.Authed)
|
||||
fmt.Fprintf(w, "CONNECTED\t%v\n", rep.Connected)
|
||||
fmt.Fprintf(w, "CONNECTION_STATE\t%s\n", rep.ConnectionState)
|
||||
fmt.Fprintf(w, "FTS5\t%v\n", rep.FTSEnabled)
|
||||
_ = w.Flush()
|
||||
|
||||
|
||||
48
cmd/wacli/doctor_test.go
Normal file
48
cmd/wacli/doctor_test.go
Normal file
@ -0,0 +1,48 @@
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestParseLockOwnerPID(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
info string
|
||||
want int
|
||||
}{
|
||||
{name: "pid line", info: "pid=50394\nacquired_at=2026-04-05T12:30:11Z", want: 50394},
|
||||
{name: "trimmed pid", info: " pid= 42 ", want: 42},
|
||||
{name: "missing pid", info: "acquired_at=2026-04-05T12:30:11Z"},
|
||||
{name: "invalid pid", info: "pid=abc"},
|
||||
{name: "zero pid", info: "pid=0"},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if got := parseLockOwnerPID(tc.info); got != tc.want {
|
||||
t.Fatalf("parseLockOwnerPID() = %d, want %d", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoctorConnectionState(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
authed bool
|
||||
connected bool
|
||||
lockHeld bool
|
||||
connect bool
|
||||
want string
|
||||
}{
|
||||
{name: "connected wins", authed: true, connected: true, lockHeld: true, want: "connected"},
|
||||
{name: "locked paired session", authed: true, lockHeld: true, want: "locked_by_other_process"},
|
||||
{name: "connect requested stays disconnected", authed: true, lockHeld: true, connect: true, want: "disconnected"},
|
||||
{name: "plain disconnected", authed: true, want: "disconnected"},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got := doctorConnectionState(tc.authed, tc.connected, tc.lockHeld, tc.connect)
|
||||
if got != tc.want {
|
||||
t.Fatalf("doctorConnectionState() = %q, want %q", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user