[client] Feed tray status via direct callback instead of the event bus

This commit is contained in:
Zoltán Papp
2026-07-28 16:43:48 +02:00
parent 8a43f4f943
commit b6deed39fb
3 changed files with 30 additions and 14 deletions

View File

@@ -5,6 +5,7 @@ package services
import (
"context"
"fmt"
"slices"
"strings"
"sync"
"time"
@@ -167,6 +168,12 @@ type DaemonFeed struct {
cancel context.CancelFunc
streamWg sync.WaitGroup
// statusSubs are Go-side snapshot consumers (the tray), fed directly so
// they don't ride the window event bus. Callbacks run synchronously on
// the stream goroutine, so pushes arrive in order.
statusSubsMu sync.Mutex
statusSubs []func(Status)
switchMu sync.Mutex
switchInProgress bool
switchInProgressUntil time.Time
@@ -188,6 +195,25 @@ func NewDaemonFeed(conn DaemonConn, emitter Emitter, updaterHolder *updater.Hold
return &DaemonFeed{conn: conn, emitter: emitter, updater: updaterHolder, logCtl: logCtl}
}
// OnStatus registers a Go-side status subscriber. Not for the frontend —
// React consumers subscribe to EventStatusSnapshot on the event bus.
func (s *DaemonFeed) OnStatus(cb func(Status)) {
s.statusSubsMu.Lock()
s.statusSubs = append(s.statusSubs, cb)
s.statusSubsMu.Unlock()
}
// pushStatus delivers a snapshot to the Go-side subscribers and the frontend.
func (s *DaemonFeed) pushStatus(st Status) {
s.statusSubsMu.Lock()
subs := slices.Clone(s.statusSubs)
s.statusSubsMu.Unlock()
for _, cb := range subs {
cb(st)
}
s.emitter.Emit(EventStatusSnapshot, st)
}
// BeginProfileSwitch arms suppression for a switch from Connected/Connecting,
// where the daemon emits stale Connected updates during Down's teardown then an
// Idle before the new Up; statusStreamLoop drops those, and a synthetic
@@ -201,7 +227,7 @@ func (s *DaemonFeed) BeginProfileSwitch() {
s.switchLoginWatch = true
s.switchLoginWatchUntil = now.Add(30 * time.Second)
s.switchMu.Unlock()
s.emitter.Emit(EventStatusSnapshot, Status{Status: StatusConnecting})
s.pushStatus(Status{Status: StatusConnecting})
}
// CancelProfileSwitch aborts a switch midway (tray Disconnect while Connecting):
@@ -343,7 +369,7 @@ func (s *DaemonFeed) statusStreamLoop(ctx context.Context) {
return
}
unavailable = true
s.emitter.Emit(EventStatusSnapshot, Status{Status: StatusDaemonUnavailable})
s.pushStatus(Status{Status: StatusDaemonUnavailable})
}
op := func() error {
@@ -403,7 +429,7 @@ func (s *DaemonFeed) emitStatus(st Status) {
log.Debugf("suppressing status=%q during profile switch", st.Status)
return
}
s.emitter.Emit(EventStatusSnapshot, st)
s.pushStatus(st)
if triggerLogin {
s.emitter.Emit(EventTriggerLogin)
}

View File

@@ -196,7 +196,7 @@ func NewTray(app *application.App, window *application.WebviewWindow, svc TraySe
// menu (e.g. GNOME Shell AppIndicator).
bindTrayClick(t)
app.Event.On(services.EventStatusSnapshot, t.onStatusEvent)
svc.DaemonFeed.OnStatus(t.applyStatus)
app.Event.On(services.EventDaemonNotification, t.onSystemEvent)
// Refresh the Profiles submenu on ProfileSwitcher's change event. A
// switch on an idle daemon drives no status transition, so without this

View File

@@ -5,19 +5,9 @@ package main
import (
"strings"
"github.com/wailsapp/wails/v3/pkg/application"
"github.com/netbirdio/netbird/client/ui/services"
)
func (t *Tray) onStatusEvent(ev *application.CustomEvent) {
st, ok := ev.Data.(services.Status)
if !ok {
return
}
t.applyStatus(st)
}
// applyStatus repaints the tray from a daemon snapshot. Icon refresh is skipped
// when no icon-relevant input changed: the daemon emits rapid SubscribeStatus
// bursts during health probes that would otherwise spam Shell_NotifyIcon.