mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-18 08:16:39 +00:00
[client] Fix controller re-connection (#2758)
Rethink the peer reconnection implementation
This commit is contained in:
119
client/internal/peer/guard/sr_watcher.go
Normal file
119
client/internal/peer/guard/sr_watcher.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package guard
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal/peer/ice"
|
||||
"github.com/netbirdio/netbird/client/internal/stdnet"
|
||||
)
|
||||
|
||||
type chNotifier interface {
|
||||
SetOnReconnectedListener(func())
|
||||
Ready() bool
|
||||
}
|
||||
|
||||
type SRWatcher struct {
|
||||
signalClient chNotifier
|
||||
relayManager chNotifier
|
||||
|
||||
listeners map[chan struct{}]struct{}
|
||||
mu sync.Mutex
|
||||
iFaceDiscover stdnet.ExternalIFaceDiscover
|
||||
iceConfig ice.Config
|
||||
|
||||
cancelIceMonitor context.CancelFunc
|
||||
}
|
||||
|
||||
// NewSRWatcher creates a new SRWatcher. This watcher will notify the listeners when the ICE candidates change or the
|
||||
// Relay connection is reconnected or the Signal client reconnected.
|
||||
func NewSRWatcher(signalClient chNotifier, relayManager chNotifier, iFaceDiscover stdnet.ExternalIFaceDiscover, iceConfig ice.Config) *SRWatcher {
|
||||
srw := &SRWatcher{
|
||||
signalClient: signalClient,
|
||||
relayManager: relayManager,
|
||||
iFaceDiscover: iFaceDiscover,
|
||||
iceConfig: iceConfig,
|
||||
listeners: make(map[chan struct{}]struct{}),
|
||||
}
|
||||
return srw
|
||||
}
|
||||
|
||||
func (w *SRWatcher) Start() {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
|
||||
if w.cancelIceMonitor != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
w.cancelIceMonitor = cancel
|
||||
|
||||
iceMonitor := NewICEMonitor(w.iFaceDiscover, w.iceConfig)
|
||||
go iceMonitor.Start(ctx, w.onICEChanged)
|
||||
w.signalClient.SetOnReconnectedListener(w.onReconnected)
|
||||
w.relayManager.SetOnReconnectedListener(w.onReconnected)
|
||||
|
||||
}
|
||||
|
||||
func (w *SRWatcher) Close() {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
|
||||
if w.cancelIceMonitor == nil {
|
||||
return
|
||||
}
|
||||
w.cancelIceMonitor()
|
||||
w.signalClient.SetOnReconnectedListener(nil)
|
||||
w.relayManager.SetOnReconnectedListener(nil)
|
||||
}
|
||||
|
||||
func (w *SRWatcher) NewListener() chan struct{} {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
|
||||
listenerChan := make(chan struct{}, 1)
|
||||
w.listeners[listenerChan] = struct{}{}
|
||||
return listenerChan
|
||||
}
|
||||
|
||||
func (w *SRWatcher) RemoveListener(listenerChan chan struct{}) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
delete(w.listeners, listenerChan)
|
||||
close(listenerChan)
|
||||
}
|
||||
|
||||
func (w *SRWatcher) onICEChanged() {
|
||||
if !w.signalClient.Ready() {
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("network changes detected by ICE agent")
|
||||
w.notify()
|
||||
}
|
||||
|
||||
func (w *SRWatcher) onReconnected() {
|
||||
if !w.signalClient.Ready() {
|
||||
return
|
||||
}
|
||||
if !w.relayManager.Ready() {
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("reconnected to Signal or Relay server")
|
||||
w.notify()
|
||||
}
|
||||
|
||||
func (w *SRWatcher) notify() {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
for listener := range w.listeners {
|
||||
select {
|
||||
case listener <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user