diff --git a/client/ui/client_ui.go b/client/ui/client_ui.go index 44643616d32..6462e9fc5f5 100644 --- a/client/ui/client_ui.go +++ b/client/ui/client_ui.go @@ -318,7 +318,8 @@ type serviceClient struct { logFile string wLoginURL fyne.Window - connectCancel context.CancelFunc + connectCancel context.CancelFunc + updateStatusChan chan struct{} } type menuHandler struct { @@ -354,6 +355,7 @@ func newServiceClient(args *newServiceClientArgs) *serviceClient { showAdvancedSettings: args.showSettings, showNetworks: args.showNetworks, update: version.NewUpdate("nb/client-ui"), + updateStatusChan: make(chan struct{}, 1), } s.eventHandler = newEventHandler(s) @@ -892,20 +894,7 @@ func (s *serviceClient) updateStatus() error { switch { case status.Status == string(internal.StatusConnected): - s.connected = true - s.sendNotification = true - if s.isUpdateIconActive { - systray.SetTemplateIcon(iconUpdateConnectedMacOS, s.icUpdateConnected) - } else { - systray.SetTemplateIcon(iconConnectedMacOS, s.icConnected) - } - systray.SetTooltip("NetBird (Connected)") - s.mStatus.SetTitle("Connected") - s.mStatus.SetIcon(s.icConnectedDot) - s.mUp.Disable() - s.mDown.Enable() - s.mNetworks.Enable() - go s.updateExitNodes() + s.setConnectedStatus() systrayIconState = true case status.Status == string(internal.StatusConnecting): s.setConnectingStatus() @@ -969,6 +958,23 @@ func (s *serviceClient) setDisconnectedStatus() { go s.updateExitNodes() } +func (s *serviceClient) setConnectedStatus() { + s.connected = true + s.sendNotification = true + if s.isUpdateIconActive { + systray.SetTemplateIcon(iconUpdateConnectedMacOS, s.icUpdateConnected) + } else { + systray.SetTemplateIcon(iconConnectedMacOS, s.icConnected) + } + systray.SetTooltip("NetBird (Connected)") + s.mStatus.SetTitle("Connected") + s.mStatus.SetIcon(s.icConnectedDot) + s.mUp.Disable() + s.mDown.Enable() + s.mNetworks.Enable() + go s.updateExitNodes() +} + func (s *serviceClient) setConnectingStatus() { s.connected = false systray.SetTemplateIcon(iconConnectingMacOS, s.icConnecting) @@ -980,6 +986,36 @@ func (s *serviceClient) setConnectingStatus() { s.mExitNode.Disable() } +func (s *serviceClient) statusUpdateLoop() { + s.getSrvConfig() + time.Sleep(100 * time.Millisecond) + ticker := time.NewTicker(2 * time.Second) + defer ticker.Stop() + + for { + select { + case <-s.ctx.Done(): + return + case <-s.updateStatusChan: + case <-ticker.C: + } + + err := s.updateStatus() + if err != nil { + log.Errorf("error while updating status: %v", err) + } + + s.checkAndUpdateFeatures() + } +} + +func (s *serviceClient) triggerStatusUpdate() { + select { + case s.updateStatusChan <- struct{}{}: + default: + } +} + func (s *serviceClient) onTrayReady() { systray.SetTemplateIcon(iconDisconnectedMacOS, s.icDisconnected) systray.SetTooltip("NetBird") @@ -1072,21 +1108,7 @@ func (s *serviceClient) onTrayReady() { go s.updateExitNodes() s.update.SetOnUpdateListener(s.onUpdateAvailable) - go func() { - s.getSrvConfig() - time.Sleep(100 * time.Millisecond) // To prevent race condition caused by systray not being fully initialized and ignoring setIcon - for { - err := s.updateStatus() - if err != nil { - log.Errorf("error while updating status: %v", err) - } - - // Check features periodically to handle daemon restarts - s.checkAndUpdateFeatures() - - time.Sleep(2 * time.Second) - } - }() + go s.statusUpdateLoop() s.eventManager = event.NewManager(s.app, s.addr) s.eventManager.SetNotificationsEnabled(s.mNotifications.Checked()) diff --git a/client/ui/event_handler.go b/client/ui/event_handler.go index e0b61941173..01312a68bb2 100644 --- a/client/ui/event_handler.go +++ b/client/ui/event_handler.go @@ -90,9 +90,7 @@ func (h *eventHandler) handleConnectClick() { } } - if err := h.client.updateStatus(); err != nil { - log.Debugf("failed to update status after connect: %v", err) - } + h.client.triggerStatusUpdate() }() } @@ -116,9 +114,7 @@ func (h *eventHandler) handleDisconnectClick() { } } - if err := h.client.updateStatus(); err != nil { - log.Debugf("failed to update status after disconnect: %v", err) - } + h.client.triggerStatusUpdate() }() }