mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-15 01:49:08 +02:00
Merge branch 'main' into log/conn-disconn
This commit is contained in:
@@ -228,6 +228,7 @@ type BundleGenerator struct {
|
|||||||
syncResponse *mgmProto.SyncResponse
|
syncResponse *mgmProto.SyncResponse
|
||||||
logPath string
|
logPath string
|
||||||
cpuProfile []byte
|
cpuProfile []byte
|
||||||
|
refreshStatus func() // Optional callback to refresh status before bundle generation
|
||||||
|
|
||||||
anonymize bool
|
anonymize bool
|
||||||
includeSystemInfo bool
|
includeSystemInfo bool
|
||||||
@@ -248,6 +249,7 @@ type GeneratorDependencies struct {
|
|||||||
SyncResponse *mgmProto.SyncResponse
|
SyncResponse *mgmProto.SyncResponse
|
||||||
LogPath string
|
LogPath string
|
||||||
CPUProfile []byte
|
CPUProfile []byte
|
||||||
|
RefreshStatus func() // Optional callback to refresh status before bundle generation
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBundleGenerator(deps GeneratorDependencies, cfg BundleConfig) *BundleGenerator {
|
func NewBundleGenerator(deps GeneratorDependencies, cfg BundleConfig) *BundleGenerator {
|
||||||
@@ -265,6 +267,7 @@ func NewBundleGenerator(deps GeneratorDependencies, cfg BundleConfig) *BundleGen
|
|||||||
syncResponse: deps.SyncResponse,
|
syncResponse: deps.SyncResponse,
|
||||||
logPath: deps.LogPath,
|
logPath: deps.LogPath,
|
||||||
cpuProfile: deps.CPUProfile,
|
cpuProfile: deps.CPUProfile,
|
||||||
|
refreshStatus: deps.RefreshStatus,
|
||||||
|
|
||||||
anonymize: cfg.Anonymize,
|
anonymize: cfg.Anonymize,
|
||||||
includeSystemInfo: cfg.IncludeSystemInfo,
|
includeSystemInfo: cfg.IncludeSystemInfo,
|
||||||
@@ -408,6 +411,10 @@ func (g *BundleGenerator) addStatus() error {
|
|||||||
profName = activeProf.Name
|
profName = activeProf.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if g.refreshStatus != nil {
|
||||||
|
g.refreshStatus()
|
||||||
|
}
|
||||||
|
|
||||||
fullStatus := g.statusRecorder.GetFullStatus()
|
fullStatus := g.statusRecorder.GetFullStatus()
|
||||||
protoFullStatus := nbstatus.ToProtoFullStatus(fullStatus)
|
protoFullStatus := nbstatus.ToProtoFullStatus(fullStatus)
|
||||||
protoFullStatus.Events = g.statusRecorder.GetEventHistory()
|
protoFullStatus.Events = g.statusRecorder.GetEventHistory()
|
||||||
|
|||||||
@@ -1050,6 +1050,9 @@ func (e *Engine) handleBundle(params *mgmProto.BundleParameters) (*mgmProto.JobR
|
|||||||
StatusRecorder: e.statusRecorder,
|
StatusRecorder: e.statusRecorder,
|
||||||
SyncResponse: syncResponse,
|
SyncResponse: syncResponse,
|
||||||
LogPath: e.config.LogPath,
|
LogPath: e.config.LogPath,
|
||||||
|
RefreshStatus: func() {
|
||||||
|
e.RunHealthProbes(true)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
bundleJobParams := debug.BundleConfig{
|
bundleJobParams := debug.BundleConfig{
|
||||||
@@ -1827,7 +1830,7 @@ func (e *Engine) getRosenpassAddr() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunHealthProbes executes health checks for Signal, Management, Relay and WireGuard services
|
// RunHealthProbes executes health checks for Signal, Management, Relay, and WireGuard services
|
||||||
// and updates the status recorder with the latest states.
|
// and updates the status recorder with the latest states.
|
||||||
func (e *Engine) RunHealthProbes(waitForResult bool) bool {
|
func (e *Engine) RunHealthProbes(waitForResult bool) bool {
|
||||||
e.syncMsgMux.Lock()
|
e.syncMsgMux.Lock()
|
||||||
@@ -1841,23 +1844,8 @@ func (e *Engine) RunHealthProbes(waitForResult bool) bool {
|
|||||||
stuns := slices.Clone(e.STUNs)
|
stuns := slices.Clone(e.STUNs)
|
||||||
turns := slices.Clone(e.TURNs)
|
turns := slices.Clone(e.TURNs)
|
||||||
|
|
||||||
if e.wgInterface != nil {
|
if err := e.statusRecorder.RefreshWireGuardStats(); err != nil {
|
||||||
stats, err := e.wgInterface.GetStats()
|
log.Debugf("failed to refresh WireGuard stats: %v", err)
|
||||||
if err != nil {
|
|
||||||
log.Warnf("failed to get wireguard stats: %v", err)
|
|
||||||
e.syncMsgMux.Unlock()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, key := range e.peerStore.PeersPubKey() {
|
|
||||||
// wgStats could be zero value, in which case we just reset the stats
|
|
||||||
wgStats, ok := stats[key]
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err := e.statusRecorder.UpdateWireGuardPeerState(key, wgStats); err != nil {
|
|
||||||
log.Debugf("failed to update wg stats for peer %s: %s", key, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
e.syncMsgMux.Unlock()
|
e.syncMsgMux.Unlock()
|
||||||
|
|||||||
@@ -1145,6 +1145,38 @@ func (d *Status) PeersStatus() (*configurer.Stats, error) {
|
|||||||
return d.wgIface.FullStats()
|
return d.wgIface.FullStats()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RefreshWireGuardStats fetches fresh WireGuard statistics from the interface
|
||||||
|
// and updates the cached peer states. This ensures accurate handshake times and
|
||||||
|
// transfer statistics in status reports without running full health probes.
|
||||||
|
func (d *Status) RefreshWireGuardStats() error {
|
||||||
|
d.mux.Lock()
|
||||||
|
defer d.mux.Unlock()
|
||||||
|
|
||||||
|
if d.wgIface == nil {
|
||||||
|
return nil // silently skip if interface not set
|
||||||
|
}
|
||||||
|
|
||||||
|
stats, err := d.wgIface.FullStats()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("get wireguard stats: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update each peer's WireGuard statistics
|
||||||
|
for _, peerStats := range stats.Peers {
|
||||||
|
peerState, ok := d.peers[peerStats.PublicKey]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
peerState.LastWireguardHandshake = peerStats.LastHandshake
|
||||||
|
peerState.BytesRx = peerStats.RxBytes
|
||||||
|
peerState.BytesTx = peerStats.TxBytes
|
||||||
|
d.peers[peerStats.PublicKey] = peerState
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type EventQueue struct {
|
type EventQueue struct {
|
||||||
maxSize int
|
maxSize int
|
||||||
events []*proto.SystemEvent
|
events []*proto.SystemEvent
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ import (
|
|||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultLog = slog.LevelInfo
|
||||||
|
defaultLogLevelVar = "NB_ROSENPASS_LOG_LEVEL"
|
||||||
|
)
|
||||||
|
|
||||||
func hashRosenpassKey(key []byte) string {
|
func hashRosenpassKey(key []byte) string {
|
||||||
hasher := sha256.New()
|
hasher := sha256.New()
|
||||||
hasher.Write(key)
|
hasher.Write(key)
|
||||||
@@ -45,7 +50,7 @@ func NewManager(preSharedKey *wgtypes.Key, wgIfaceName string) (*Manager, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
rpKeyHash := hashRosenpassKey(public)
|
rpKeyHash := hashRosenpassKey(public)
|
||||||
log.Debugf("generated new rosenpass key pair with public key %s", rpKeyHash)
|
log.Tracef("generated new rosenpass key pair with public key %s", rpKeyHash)
|
||||||
return &Manager{ifaceName: wgIfaceName, rpKeyHash: rpKeyHash, spk: public, ssk: secret, preSharedKey: (*[32]byte)(preSharedKey), rpPeerIDs: make(map[string]*rp.PeerID), lock: sync.Mutex{}}, nil
|
return &Manager{ifaceName: wgIfaceName, rpKeyHash: rpKeyHash, spk: public, ssk: secret, preSharedKey: (*[32]byte)(preSharedKey), rpPeerIDs: make(map[string]*rp.PeerID), lock: sync.Mutex{}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +106,7 @@ func (m *Manager) removePeer(wireGuardPubKey string) error {
|
|||||||
|
|
||||||
func (m *Manager) generateConfig() (rp.Config, error) {
|
func (m *Manager) generateConfig() (rp.Config, error) {
|
||||||
opts := &slog.HandlerOptions{
|
opts := &slog.HandlerOptions{
|
||||||
Level: slog.LevelDebug,
|
Level: getLogLevel(),
|
||||||
}
|
}
|
||||||
logger := slog.New(slog.NewTextHandler(os.Stdout, opts))
|
logger := slog.New(slog.NewTextHandler(os.Stdout, opts))
|
||||||
cfg := rp.Config{Logger: logger}
|
cfg := rp.Config{Logger: logger}
|
||||||
@@ -133,6 +138,26 @@ func (m *Manager) generateConfig() (rp.Config, error) {
|
|||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getLogLevel() slog.Level {
|
||||||
|
level, ok := os.LookupEnv(defaultLogLevelVar)
|
||||||
|
if !ok {
|
||||||
|
return defaultLog
|
||||||
|
}
|
||||||
|
switch strings.ToLower(level) {
|
||||||
|
case "debug":
|
||||||
|
return slog.LevelDebug
|
||||||
|
case "info":
|
||||||
|
return slog.LevelInfo
|
||||||
|
case "warn":
|
||||||
|
return slog.LevelWarn
|
||||||
|
case "error":
|
||||||
|
return slog.LevelError
|
||||||
|
default:
|
||||||
|
log.Warnf("unknown log level: %s. Using default %s", level, defaultLog.String())
|
||||||
|
return defaultLog
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Manager) OnDisconnected(peerKey string) {
|
func (m *Manager) OnDisconnected(peerKey string) {
|
||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
defer m.lock.Unlock()
|
defer m.lock.Unlock()
|
||||||
|
|||||||
@@ -34,6 +34,18 @@ func (s *Server) DebugBundle(_ context.Context, req *proto.DebugBundleRequest) (
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare refresh callback for health probes
|
||||||
|
var refreshStatus func()
|
||||||
|
if s.connectClient != nil {
|
||||||
|
engine := s.connectClient.Engine()
|
||||||
|
if engine != nil {
|
||||||
|
refreshStatus = func() {
|
||||||
|
log.Debug("refreshing system health status for debug bundle")
|
||||||
|
engine.RunHealthProbes(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bundleGenerator := debug.NewBundleGenerator(
|
bundleGenerator := debug.NewBundleGenerator(
|
||||||
debug.GeneratorDependencies{
|
debug.GeneratorDependencies{
|
||||||
InternalConfig: s.config,
|
InternalConfig: s.config,
|
||||||
@@ -41,6 +53,7 @@ func (s *Server) DebugBundle(_ context.Context, req *proto.DebugBundleRequest) (
|
|||||||
SyncResponse: syncResponse,
|
SyncResponse: syncResponse,
|
||||||
LogPath: s.logFile,
|
LogPath: s.logFile,
|
||||||
CPUProfile: cpuProfileData,
|
CPUProfile: cpuProfileData,
|
||||||
|
RefreshStatus: refreshStatus,
|
||||||
},
|
},
|
||||||
debug.BundleConfig{
|
debug.BundleConfig{
|
||||||
Anonymize: req.GetAnonymize(),
|
Anonymize: req.GetAnonymize(),
|
||||||
|
|||||||
@@ -1327,6 +1327,10 @@ func (s *Server) runProbes(waitForProbeResult bool) {
|
|||||||
if engine.RunHealthProbes(waitForProbeResult) {
|
if engine.RunHealthProbes(waitForProbeResult) {
|
||||||
s.lastProbe = time.Now()
|
s.lastProbe = time.Now()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if err := s.statusRecorder.RefreshWireGuardStats(); err != nil {
|
||||||
|
log.Debugf("failed to refresh WireGuard stats: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1033,7 +1033,7 @@ func (s *serviceClient) onTrayReady() {
|
|||||||
s.mDown.Disable()
|
s.mDown.Disable()
|
||||||
systray.AddSeparator()
|
systray.AddSeparator()
|
||||||
|
|
||||||
s.mSettings = systray.AddMenuItem("Settings", settingsMenuDescr)
|
s.mSettings = systray.AddMenuItem("Settings", disabledMenuDescr)
|
||||||
s.mAllowSSH = s.mSettings.AddSubMenuItemCheckbox("Allow SSH", allowSSHMenuDescr, false)
|
s.mAllowSSH = s.mSettings.AddSubMenuItemCheckbox("Allow SSH", allowSSHMenuDescr, false)
|
||||||
s.mAutoConnect = s.mSettings.AddSubMenuItemCheckbox("Connect on Startup", autoConnectMenuDescr, false)
|
s.mAutoConnect = s.mSettings.AddSubMenuItemCheckbox("Connect on Startup", autoConnectMenuDescr, false)
|
||||||
s.mEnableRosenpass = s.mSettings.AddSubMenuItemCheckbox("Enable Quantum-Resistance", quantumResistanceMenuDescr, false)
|
s.mEnableRosenpass = s.mSettings.AddSubMenuItemCheckbox("Enable Quantum-Resistance", quantumResistanceMenuDescr, false)
|
||||||
@@ -1060,7 +1060,7 @@ func (s *serviceClient) onTrayReady() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.exitNodeMu.Lock()
|
s.exitNodeMu.Lock()
|
||||||
s.mExitNode = systray.AddMenuItem("Exit Node", exitNodeMenuDescr)
|
s.mExitNode = systray.AddMenuItem("Exit Node", disabledMenuDescr)
|
||||||
s.mExitNode.Disable()
|
s.mExitNode.Disable()
|
||||||
s.exitNodeMu.Unlock()
|
s.exitNodeMu.Unlock()
|
||||||
|
|
||||||
@@ -1261,7 +1261,6 @@ func (s *serviceClient) setSettingsEnabled(enabled bool) {
|
|||||||
if s.mSettings != nil {
|
if s.mSettings != nil {
|
||||||
if enabled {
|
if enabled {
|
||||||
s.mSettings.Enable()
|
s.mSettings.Enable()
|
||||||
s.mSettings.SetTooltip(settingsMenuDescr)
|
|
||||||
} else {
|
} else {
|
||||||
s.mSettings.Hide()
|
s.mSettings.Hide()
|
||||||
s.mSettings.SetTooltip("Settings are disabled by daemon")
|
s.mSettings.SetTooltip("Settings are disabled by daemon")
|
||||||
|
|||||||
+1
-3
@@ -1,8 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
const (
|
const (
|
||||||
settingsMenuDescr = "Settings of the application"
|
|
||||||
profilesMenuDescr = "Manage your profiles"
|
|
||||||
allowSSHMenuDescr = "Allow SSH connections"
|
allowSSHMenuDescr = "Allow SSH connections"
|
||||||
autoConnectMenuDescr = "Connect automatically when the service starts"
|
autoConnectMenuDescr = "Connect automatically when the service starts"
|
||||||
quantumResistanceMenuDescr = "Enable post-quantum security via Rosenpass"
|
quantumResistanceMenuDescr = "Enable post-quantum security via Rosenpass"
|
||||||
@@ -11,7 +9,7 @@ const (
|
|||||||
notificationsMenuDescr = "Enable notifications"
|
notificationsMenuDescr = "Enable notifications"
|
||||||
advancedSettingsMenuDescr = "Advanced settings of the application"
|
advancedSettingsMenuDescr = "Advanced settings of the application"
|
||||||
debugBundleMenuDescr = "Create and open debug information bundle"
|
debugBundleMenuDescr = "Create and open debug information bundle"
|
||||||
exitNodeMenuDescr = "Select exit node for routing traffic"
|
disabledMenuDescr = ""
|
||||||
networksMenuDescr = "Open the networks management window"
|
networksMenuDescr = "Open the networks management window"
|
||||||
latestVersionMenuDescr = "Download latest version"
|
latestVersionMenuDescr = "Download latest version"
|
||||||
quitMenuDescr = "Quit the client app"
|
quitMenuDescr = "Quit the client app"
|
||||||
|
|||||||
@@ -99,6 +99,8 @@ func (h *eventHandler) handleConnectClick() {
|
|||||||
func (h *eventHandler) handleDisconnectClick() {
|
func (h *eventHandler) handleDisconnectClick() {
|
||||||
h.client.mDown.Disable()
|
h.client.mDown.Disable()
|
||||||
|
|
||||||
|
h.client.exitNodeStates = []exitNodeState{}
|
||||||
|
|
||||||
if h.client.connectCancel != nil {
|
if h.client.connectCancel != nil {
|
||||||
log.Debugf("cancelling ongoing connect operation")
|
log.Debugf("cancelling ongoing connect operation")
|
||||||
h.client.connectCancel()
|
h.client.connectCancel()
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ func (s *serviceClient) recreateExitNodeMenu(exitNodes []*proto.Network) {
|
|||||||
|
|
||||||
if runtime.GOOS == "linux" || runtime.GOOS == "freebsd" {
|
if runtime.GOOS == "linux" || runtime.GOOS == "freebsd" {
|
||||||
s.mExitNode.Remove()
|
s.mExitNode.Remove()
|
||||||
s.mExitNode = systray.AddMenuItem("Exit Node", exitNodeMenuDescr)
|
s.mExitNode = systray.AddMenuItem("Exit Node", disabledMenuDescr)
|
||||||
}
|
}
|
||||||
|
|
||||||
var showDeselectAll bool
|
var showDeselectAll bool
|
||||||
|
|||||||
@@ -856,3 +856,7 @@ func (c *Controller) GetNetworkMap(ctx context.Context, peerID string) (*types.N
|
|||||||
func (c *Controller) DisconnectPeers(ctx context.Context, accountId string, peerIDs []string) {
|
func (c *Controller) DisconnectPeers(ctx context.Context, accountId string, peerIDs []string) {
|
||||||
c.peersUpdateManager.CloseChannels(ctx, peerIDs)
|
c.peersUpdateManager.CloseChannels(ctx, peerIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Controller) TrackEphemeralPeer(ctx context.Context, peer *nbpeer.Peer) {
|
||||||
|
c.EphemeralPeersManager.OnPeerDisconnected(ctx, peer)
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,4 +36,6 @@ type Controller interface {
|
|||||||
DisconnectPeers(ctx context.Context, accountId string, peerIDs []string)
|
DisconnectPeers(ctx context.Context, accountId string, peerIDs []string)
|
||||||
OnPeerConnected(ctx context.Context, accountID string, peerID string) (chan *UpdateMessage, error)
|
OnPeerConnected(ctx context.Context, accountID string, peerID string) (chan *UpdateMessage, error)
|
||||||
OnPeerDisconnected(ctx context.Context, accountID string, peerID string)
|
OnPeerDisconnected(ctx context.Context, accountID string, peerID string)
|
||||||
|
|
||||||
|
TrackEphemeralPeer(ctx context.Context, peer *nbpeer.Peer)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
// Code generated by MockGen. DO NOT EDIT.
|
// Code generated by MockGen. DO NOT EDIT.
|
||||||
// Source: ./interface.go
|
// Source: management/internals/controllers/network_map/interface.go
|
||||||
//
|
//
|
||||||
// Generated by this command:
|
// Generated by this command:
|
||||||
//
|
//
|
||||||
// mockgen -package network_map -destination=interface_mock.go -source=./interface.go -build_flags=-mod=mod
|
// mockgen -package network_map -destination=management/internals/controllers/network_map/interface_mock.go -source=management/internals/controllers/network_map/interface.go -build_flags=-mod=mod
|
||||||
//
|
//
|
||||||
|
|
||||||
// Package network_map is a generated GoMock package.
|
// Package network_map is a generated GoMock package.
|
||||||
@@ -211,6 +211,18 @@ func (mr *MockControllerMockRecorder) StartWarmup(arg0 any) *gomock.Call {
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartWarmup", reflect.TypeOf((*MockController)(nil).StartWarmup), arg0)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartWarmup", reflect.TypeOf((*MockController)(nil).StartWarmup), arg0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TrackEphemeralPeer mocks base method.
|
||||||
|
func (m *MockController) TrackEphemeralPeer(ctx context.Context, arg1 *peer.Peer) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
m.ctrl.Call(m, "TrackEphemeralPeer", ctx, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrackEphemeralPeer indicates an expected call of TrackEphemeralPeer.
|
||||||
|
func (mr *MockControllerMockRecorder) TrackEphemeralPeer(ctx, arg1 any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TrackEphemeralPeer", reflect.TypeOf((*MockController)(nil).TrackEphemeralPeer), ctx, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateAccountPeer mocks base method.
|
// UpdateAccountPeer mocks base method.
|
||||||
func (m *MockController) UpdateAccountPeer(ctx context.Context, accountId, peerId string) error {
|
func (m *MockController) UpdateAccountPeer(ctx context.Context, accountId, peerId string) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|||||||
@@ -746,6 +746,11 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, accountID, setupKe
|
|||||||
return fmt.Errorf("failed adding peer to All group: %w", err)
|
return fmt.Errorf("failed adding peer to All group: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if temporary {
|
||||||
|
// we should track ephemeral peers to be able to clean them if the peer don't sync and be marked as connected
|
||||||
|
am.networkMapController.TrackEphemeralPeer(ctx, newPeer)
|
||||||
|
}
|
||||||
|
|
||||||
if addedByUser {
|
if addedByUser {
|
||||||
err := transaction.SaveUserLastLogin(ctx, accountID, userID, newPeer.GetLastLogin())
|
err := transaction.SaveUserLastLogin(ctx, accountID, userID, newPeer.GetLastLogin())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user