Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion client/ui/client_ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -1354,7 +1354,13 @@ func (s *serviceClient) updateConfig() error {
}

// showLoginURL creates a borderless window styled like a pop-up in the top-right corner using s.wLoginURL.
func (s *serviceClient) showLoginURL() {
// It also starts a background goroutine that periodically checks if the client is already connected
// and closes the window if so. The goroutine can be cancelled by the returned CancelFunc, and it is
// also cancelled when the window is closed.
func (s *serviceClient) showLoginURL() context.CancelFunc {

// create a cancellable context for the background check goroutine
ctx, cancel := context.WithCancel(s.ctx)

resIcon := fyne.NewStaticResource("netbird.png", iconAbout)

Expand All @@ -1363,6 +1369,8 @@ func (s *serviceClient) showLoginURL() {
s.wLoginURL.Resize(fyne.NewSize(400, 200))
s.wLoginURL.SetIcon(resIcon)
}
// ensure goroutine is cancelled when the window is closed
s.wLoginURL.SetOnClosed(func() { cancel() })
// add a description label
label := widget.NewLabel("Your NetBird session has expired.\nPlease re-authenticate to continue using NetBird.")

Expand Down Expand Up @@ -1443,7 +1451,39 @@ func (s *serviceClient) showLoginURL() {
)
s.wLoginURL.SetContent(container.NewCenter(content))

// start a goroutine to check connection status and close the window if connected
go func() {
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()

conn, err := s.getSrvClient(failFastTimeout)
if err != nil {
return
Comment on lines +1459 to +1461
Copy link

Copilot AI Sep 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If acquiring the service client fails once, the goroutine exits and the auto-close behavior never runs. This makes the feature inert under transient startup/network conditions. Consider retrying acquisition inside the loop (or continuing until ctx.Done()) so it recovers from transient failures.

Suggested change
conn, err := s.getSrvClient(failFastTimeout)
if err != nil {
return
var conn proto.ClientServiceClient
for {
select {
case <-ctx.Done():
return
default:
}
var err error
conn, err = s.getSrvClient(failFastTimeout)
if err != nil {
// Retry after a short delay if acquiring the client fails
time.Sleep(2 * time.Second)
continue
}
break

Copilot uses AI. Check for mistakes.

}

for {
select {
case <-ctx.Done():
return
case <-ticker.C:
status, err := conn.Status(s.ctx, &proto.StatusRequest{})
Copy link

Copilot AI Sep 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Status RPC uses s.ctx instead of the cancellable ctx created for this goroutine, meaning in-flight calls won’t be canceled when cancel() is invoked or when the window closes. Use ctx so the RPC respects cancellation.

Suggested change
status, err := conn.Status(s.ctx, &proto.StatusRequest{})
status, err := conn.Status(ctx, &proto.StatusRequest{})

Copilot uses AI. Check for mistakes.

if err != nil {
continue
}
if status.Status == string(internal.StatusConnected) {
if s.wLoginURL != nil {
s.wLoginURL.Close()
}
return
}
}
}
}()

s.wLoginURL.Show()

// return cancel func so callers can stop the background goroutine if desired
return cancel
}

func openURL(url string) error {
Expand Down
Loading