mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-14 04:39:54 +00:00
The daemon's Up RPC previously always blocked in waitForUp (up to 50s) until the engine connected. The UI does not need this — status updates already flow through the SubscribeStatus stream. Add bool async = 4 to UpRequest. When true the daemon starts connectWithRetryRuns and returns immediately; the CLI path (async=false, the default) is unchanged. ProfileSwitcher.SwitchActive now sets Async:true so all three RPCs (Status, Switch, Down, Up) return quickly. The background goroutine and its associated race condition are removed entirely.
83 lines
3.4 KiB
Go
83 lines
3.4 KiB
Go
//go:build !android && !ios && !freebsd && !js
|
|
|
|
package services
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// ProfileSwitcher encapsulates the full profile-switching reconnect policy so
|
|
// both the tray and the React frontend use identical logic.
|
|
//
|
|
// Reconnect policy:
|
|
//
|
|
// ┌─────────────────┬──────────────────────┬────────────────────────────────────┐
|
|
// │ Previous status │ Action │ Rationale │
|
|
// ├─────────────────┼──────────────────────┼────────────────────────────────────┤
|
|
// │ Connected │ Switch + Down + Up │ Reconnect with the new profile. │
|
|
// │ Connecting │ Switch + Down + Up │ Stop old retry loop, restart. │
|
|
// │ NeedsLogin │ Switch + Down │ Clear stale error; user logs in. │
|
|
// │ LoginFailed │ Switch + Down │ Clear stale error; user logs in. │
|
|
// │ SessionExpired │ Switch + Down │ Clear stale error; user logs in. │
|
|
// │ Idle │ Switch only │ User chose offline; don't connect. │
|
|
// └─────────────────┴──────────────────────┴────────────────────────────────────┘
|
|
type ProfileSwitcher struct {
|
|
profiles *Profiles
|
|
connection *Connection
|
|
peers *Peers
|
|
}
|
|
|
|
// NewProfileSwitcher creates a ProfileSwitcher backed by the given services.
|
|
func NewProfileSwitcher(profiles *Profiles, connection *Connection, peers *Peers) *ProfileSwitcher {
|
|
return &ProfileSwitcher{profiles: profiles, connection: connection, peers: peers}
|
|
}
|
|
|
|
// SwitchActive switches to the named profile applying the reconnect policy.
|
|
// All RPCs complete quickly: Up uses async mode so the daemon starts the
|
|
// connection attempt and returns immediately; status updates flow via the
|
|
// SubscribeStatus stream.
|
|
func (s *ProfileSwitcher) SwitchActive(ctx context.Context, p ProfileRef) error {
|
|
prevStatus := ""
|
|
if st, err := s.peers.Get(ctx); err == nil {
|
|
prevStatus = st.Status
|
|
} else {
|
|
log.Warnf("profileswitcher: get status: %v", err)
|
|
}
|
|
|
|
wasActive := strings.EqualFold(prevStatus, StatusConnected) ||
|
|
strings.EqualFold(prevStatus, StatusConnecting)
|
|
needsDown := wasActive ||
|
|
strings.EqualFold(prevStatus, StatusNeedsLogin) ||
|
|
strings.EqualFold(prevStatus, StatusLoginFailed) ||
|
|
strings.EqualFold(prevStatus, StatusSessionExpired)
|
|
|
|
log.Infof("profileswitcher: switch profile=%q prevStatus=%q wasActive=%v needsDown=%v",
|
|
p.ProfileName, prevStatus, wasActive, needsDown)
|
|
|
|
if err := s.profiles.Switch(ctx, p); err != nil {
|
|
return fmt.Errorf("switch profile %q: %w", p.ProfileName, err)
|
|
}
|
|
|
|
if needsDown {
|
|
if err := s.connection.Down(ctx); err != nil {
|
|
log.Errorf("profileswitcher: Down: %v", err)
|
|
}
|
|
}
|
|
|
|
if wasActive {
|
|
if err := s.connection.Up(ctx, UpParams{
|
|
ProfileName: p.ProfileName,
|
|
Username: p.Username,
|
|
Async: true,
|
|
}); err != nil {
|
|
return fmt.Errorf("reconnect %q: %w", p.ProfileName, err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|