The tray says why the engine is not running, and setup will not run under a live app
Seen on the demo PC: Start did nothing and Stop stayed grey. The supervisor's engine had failed because a second engine already held port 8010, and the tray reported that as nothing at all. The supervisor now keeps the engine's last lines and turns the known ones into a sentence - 'port 8010 is already in use - another Behavision or its engine is still running', 'run behavision-setup again' - which the tray and the window show. Tray clicks no longer run on the menu loop, so a stop that waits for the process cannot make the menu look dead. Two ways that second process came to exist are closed: setup refuses to run while Behavision.exe or the agent is up, and the app watches agent.json so a claim made underneath it - which rotates the API token - is picked up instead of leaving camera sync refused until a restart. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KGcjxF1cNLcuwc3DAPcnfj
This commit is contained in:
@@ -101,9 +101,11 @@ func (t *tray) onReady(ctx context.Context) {
|
||||
case <-t.mOpen.ClickedCh:
|
||||
runtime.Show(ctx)
|
||||
case <-t.mStart.ClickedCh:
|
||||
t.app.StartEngine()
|
||||
// Never on the menu loop itself: a stop waits for the process to
|
||||
// exit, and a menu that is deaf for the duration looks broken.
|
||||
go func() { t.app.StartEngine(); t.refresh() }()
|
||||
case <-t.mStop.ClickedCh:
|
||||
t.app.StopEngine()
|
||||
go func() { t.app.StopEngine(); t.refresh() }()
|
||||
case <-t.mLogs.ClickedCh:
|
||||
runtime.BrowserOpenURL(ctx, "file://"+logsDir())
|
||||
case <-t.mQuit.ClickedCh:
|
||||
@@ -129,23 +131,29 @@ func (t *tray) poll(ctx context.Context) {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-tick.C:
|
||||
s := t.app.EngineStatus()
|
||||
state, label := describe(s)
|
||||
systray.SetIcon(iconFor(state))
|
||||
systray.SetTooltip("Behavision — " + label)
|
||||
if t.mStatus != nil {
|
||||
t.mStatus.SetTitle(label)
|
||||
}
|
||||
running := s.State == "running"
|
||||
if t.mStart != nil && t.mStop != nil {
|
||||
if running {
|
||||
t.mStart.Disable()
|
||||
t.mStop.Enable()
|
||||
} else {
|
||||
t.mStart.Enable()
|
||||
t.mStop.Disable()
|
||||
}
|
||||
}
|
||||
t.refresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// refresh redraws the icon and the menu from EngineStatus - the same source
|
||||
// the window reads, so the two cannot disagree.
|
||||
func (t *tray) refresh() {
|
||||
s := t.app.EngineStatus()
|
||||
state, label := describe(s)
|
||||
systray.SetIcon(iconFor(state))
|
||||
systray.SetTooltip("Behavision — " + label)
|
||||
if t.mStatus != nil {
|
||||
t.mStatus.SetTitle(label)
|
||||
}
|
||||
running := s.State == "running" || s.State == "starting" || s.State == "backoff"
|
||||
if t.mStart != nil && t.mStop != nil {
|
||||
if running {
|
||||
t.mStart.Disable()
|
||||
t.mStop.Enable()
|
||||
} else {
|
||||
t.mStart.Enable()
|
||||
t.mStop.Disable()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,7 +168,9 @@ func describe(s EngineStatus) (state, label string) {
|
||||
case s.State == "stopped":
|
||||
return "stopped", "Stopped"
|
||||
case s.State == "failed":
|
||||
return "error", "Failed — " + firstLine(s.Error)
|
||||
// The supervisor's error is already a sentence (port in use, missing
|
||||
// library); show it whole, because it is the thing to act on.
|
||||
return "error", "Not running — " + firstLine(s.Error)
|
||||
case s.State == "backoff":
|
||||
return "error", fmt.Sprintf("Restarting (%d attempts)", s.Restarts)
|
||||
case !s.Reachable:
|
||||
|
||||
Reference in New Issue
Block a user