mirror of
https://github.com/fosrl/olm.git
synced 2026-02-08 05:56:41 +00:00
186
olm/olm.go
186
olm/olm.go
@@ -53,6 +53,11 @@ var (
|
||||
updateRegister func(newData interface{})
|
||||
stopPing chan struct{}
|
||||
peerManager *peers.PeerManager
|
||||
// Power mode management
|
||||
currentPowerMode string
|
||||
originalPeerInterval time.Duration
|
||||
originalHolepunchMinInterval time.Duration
|
||||
originalHolepunchMaxInterval time.Duration
|
||||
)
|
||||
|
||||
// initTunnelInfo creates the shared UDP socket and holepunch manager.
|
||||
@@ -432,6 +437,18 @@ func StartTunnel(config TunnelConfig) {
|
||||
APIServer: apiServer,
|
||||
})
|
||||
|
||||
// Capture original intervals for power mode management
|
||||
if peerManager != nil {
|
||||
peerMonitor := peerManager.GetPeerMonitor()
|
||||
if peerMonitor != nil {
|
||||
originalPeerInterval = 2 * time.Second // Default peer interval
|
||||
originalHolepunchMinInterval, originalHolepunchMaxInterval = peerMonitor.GetHolepunchIntervals()
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize power mode to normal
|
||||
currentPowerMode = "normal"
|
||||
|
||||
for i := range wgData.Sites {
|
||||
site := wgData.Sites[i]
|
||||
var siteEndpoint string
|
||||
@@ -1156,3 +1173,172 @@ func SwitchOrg(orgID string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetPowerMode switches between normal and low power modes
|
||||
// In low power mode: websocket is closed (stopping pings) and monitoring intervals are set to 10 minutes
|
||||
// In normal power mode: websocket is reconnected (restarting pings) and monitoring intervals are restored
|
||||
func SetPowerMode(mode string) error {
|
||||
// Validate mode
|
||||
if mode != "normal" && mode != "low" {
|
||||
return fmt.Errorf("invalid power mode: %s (must be 'normal' or 'low')", mode)
|
||||
}
|
||||
|
||||
// If already in the requested mode, return early
|
||||
if currentPowerMode == mode {
|
||||
logger.Debug("Already in %s power mode", mode)
|
||||
return nil
|
||||
}
|
||||
|
||||
logger.Info("Switching to %s power mode", mode)
|
||||
|
||||
if mode == "low" {
|
||||
// Low Power Mode: Close websocket and reduce monitoring frequency
|
||||
|
||||
// Close websocket connection - this stops:
|
||||
// - WebSocket ping monitor (via pingMonitor() goroutine)
|
||||
// - Application ping messages (via keepSendingPing() goroutine)
|
||||
if olmClient != nil {
|
||||
logger.Info("Closing websocket connection for low power mode")
|
||||
if err := olmClient.Close(); err != nil {
|
||||
logger.Error("Error closing websocket: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop application ping goroutine
|
||||
if stopPing != nil {
|
||||
select {
|
||||
case <-stopPing:
|
||||
// Channel already closed
|
||||
default:
|
||||
close(stopPing)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop peer monitoring
|
||||
if peerManager != nil {
|
||||
peerManager.Stop()
|
||||
}
|
||||
|
||||
// Store original intervals if not already stored
|
||||
if originalPeerInterval == 0 && peerManager != nil {
|
||||
peerMonitor := peerManager.GetPeerMonitor()
|
||||
if peerMonitor != nil {
|
||||
originalPeerInterval = 2 * time.Second // Default peer interval
|
||||
originalHolepunchMinInterval, originalHolepunchMaxInterval = peerMonitor.GetHolepunchIntervals()
|
||||
}
|
||||
}
|
||||
|
||||
// Set monitoring intervals to 10 minutes
|
||||
if peerManager != nil {
|
||||
peerMonitor := peerManager.GetPeerMonitor()
|
||||
if peerMonitor != nil {
|
||||
lowPowerInterval := 10 * time.Minute
|
||||
peerMonitor.SetInterval(lowPowerInterval)
|
||||
peerMonitor.SetHolepunchInterval(lowPowerInterval, lowPowerInterval)
|
||||
logger.Info("Set monitoring intervals to 10 minutes for low power mode")
|
||||
}
|
||||
}
|
||||
|
||||
// Restart peer monitoring with new intervals (but websocket remains closed)
|
||||
if peerManager != nil {
|
||||
peerManager.Start()
|
||||
}
|
||||
|
||||
currentPowerMode = "low"
|
||||
logger.Info("Switched to low power mode")
|
||||
|
||||
} else {
|
||||
// Normal Power Mode: Restore intervals and reconnect websocket
|
||||
|
||||
// Restore monitoring intervals to original values
|
||||
if peerManager != nil {
|
||||
peerMonitor := peerManager.GetPeerMonitor()
|
||||
if peerMonitor != nil {
|
||||
// Restore peer interval
|
||||
if originalPeerInterval == 0 {
|
||||
originalPeerInterval = 2 * time.Second // Default if not captured
|
||||
}
|
||||
peerMonitor.SetInterval(originalPeerInterval)
|
||||
|
||||
// Restore holepunch intervals
|
||||
if originalHolepunchMinInterval == 0 {
|
||||
originalHolepunchMinInterval = 2 * time.Second // Default if not captured
|
||||
}
|
||||
if originalHolepunchMaxInterval == 0 {
|
||||
originalHolepunchMaxInterval = 30 * time.Second // Default if not captured
|
||||
}
|
||||
peerMonitor.SetHolepunchInterval(originalHolepunchMinInterval, originalHolepunchMaxInterval)
|
||||
logger.Info("Restored monitoring intervals to normal (peer: %v, holepunch: %v-%v)",
|
||||
originalPeerInterval, originalHolepunchMinInterval, originalHolepunchMaxInterval)
|
||||
}
|
||||
}
|
||||
|
||||
// Restart peer monitoring with restored intervals
|
||||
if peerManager != nil {
|
||||
peerManager.Start()
|
||||
}
|
||||
|
||||
// Reconnect websocket - this restarts:
|
||||
// - WebSocket ping monitor
|
||||
// - Application ping messages (via OnConnect callback)
|
||||
// Note: Since websocket client's Close() permanently closes the done channel,
|
||||
// we need to create a new client instance and re-register handlers
|
||||
if tunnelConfig.ID != "" && tunnelConfig.Secret != "" && tunnelConfig.Endpoint != "" {
|
||||
logger.Info("Reconnecting websocket for normal power mode")
|
||||
|
||||
// Close old client if it exists
|
||||
if olmClient != nil {
|
||||
olmClient.Close()
|
||||
}
|
||||
|
||||
// Recreate stopPing channel for application pings
|
||||
stopPing = make(chan struct{})
|
||||
|
||||
// Create a new websocket client
|
||||
var (
|
||||
id = tunnelConfig.ID
|
||||
secret = tunnelConfig.Secret
|
||||
userToken = tunnelConfig.UserToken
|
||||
)
|
||||
|
||||
olm, err := websocket.NewClient(
|
||||
id,
|
||||
secret,
|
||||
userToken,
|
||||
tunnelConfig.OrgID,
|
||||
tunnelConfig.Endpoint,
|
||||
tunnelConfig.PingIntervalDuration,
|
||||
tunnelConfig.PingTimeoutDuration,
|
||||
)
|
||||
if err != nil {
|
||||
logger.Error("Failed to create new websocket client: %v", err)
|
||||
return fmt.Errorf("failed to create new websocket client: %w", err)
|
||||
}
|
||||
|
||||
// Store the new client
|
||||
olmClient = olm
|
||||
|
||||
// Re-register essential handlers (simplified - only the most critical ones)
|
||||
// The full handler registration happens in StartTunnel, so this is just for reconnection
|
||||
olm.OnConnect(func() error {
|
||||
logger.Info("Websocket Reconnected")
|
||||
apiServer.SetConnectionStatus(true)
|
||||
go keepSendingPing(olm)
|
||||
return nil
|
||||
})
|
||||
|
||||
// Connect to the WebSocket server
|
||||
if err := olm.Connect(); err != nil {
|
||||
logger.Error("Failed to reconnect websocket: %v", err)
|
||||
return fmt.Errorf("failed to reconnect websocket: %w", err)
|
||||
}
|
||||
} else {
|
||||
logger.Warn("Cannot reconnect websocket: tunnel config not available")
|
||||
}
|
||||
|
||||
currentPowerMode = "normal"
|
||||
logger.Info("Switched to normal power mode")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -84,6 +84,13 @@ func (pm *PeerManager) GetPeer(siteId int) (SiteConfig, bool) {
|
||||
return peer, ok
|
||||
}
|
||||
|
||||
// GetPeerMonitor returns the internal peer monitor instance
|
||||
func (pm *PeerManager) GetPeerMonitor() *monitor.PeerMonitor {
|
||||
pm.mu.RLock()
|
||||
defer pm.mu.RUnlock()
|
||||
return pm.peerMonitor
|
||||
}
|
||||
|
||||
func (pm *PeerManager) GetAllPeers() []SiteConfig {
|
||||
pm.mu.RLock()
|
||||
defer pm.mu.RUnlock()
|
||||
|
||||
@@ -62,11 +62,11 @@ type PeerMonitor struct {
|
||||
holepunchFailures map[int]int // siteID -> consecutive failure count
|
||||
|
||||
// Exponential backoff fields for holepunch monitor
|
||||
holepunchMinInterval time.Duration // Minimum interval (initial)
|
||||
holepunchMaxInterval time.Duration // Maximum interval (cap for backoff)
|
||||
holepunchBackoffMultiplier float64 // Multiplier for each stable check
|
||||
holepunchStableCount map[int]int // siteID -> consecutive stable status count
|
||||
holepunchCurrentInterval time.Duration // Current interval with backoff applied
|
||||
holepunchMinInterval time.Duration // Minimum interval (initial)
|
||||
holepunchMaxInterval time.Duration // Maximum interval (cap for backoff)
|
||||
holepunchBackoffMultiplier float64 // Multiplier for each stable check
|
||||
holepunchStableCount map[int]int // siteID -> consecutive stable status count
|
||||
holepunchCurrentInterval time.Duration // Current interval with backoff applied
|
||||
|
||||
// Rapid initial test fields
|
||||
rapidTestInterval time.Duration // interval between rapid test attempts
|
||||
@@ -167,6 +167,25 @@ func (pm *PeerMonitor) SetMaxAttempts(attempts int) {
|
||||
}
|
||||
}
|
||||
|
||||
// SetHolepunchInterval sets both the minimum and maximum intervals for holepunch monitoring
|
||||
func (pm *PeerMonitor) SetHolepunchInterval(minInterval, maxInterval time.Duration) {
|
||||
pm.mutex.Lock()
|
||||
defer pm.mutex.Unlock()
|
||||
|
||||
pm.holepunchMinInterval = minInterval
|
||||
pm.holepunchMaxInterval = maxInterval
|
||||
// Reset current interval to the new minimum
|
||||
pm.holepunchCurrentInterval = minInterval
|
||||
}
|
||||
|
||||
// GetHolepunchIntervals returns the current minimum and maximum intervals for holepunch monitoring
|
||||
func (pm *PeerMonitor) GetHolepunchIntervals() (minInterval, maxInterval time.Duration) {
|
||||
pm.mutex.Lock()
|
||||
defer pm.mutex.Unlock()
|
||||
|
||||
return pm.holepunchMinInterval, pm.holepunchMaxInterval
|
||||
}
|
||||
|
||||
// AddPeer adds a new peer to monitor
|
||||
func (pm *PeerMonitor) AddPeer(siteID int, endpoint string, holepunchEndpoint string) error {
|
||||
pm.mutex.Lock()
|
||||
|
||||
Reference in New Issue
Block a user