Compare commits
2 Commits
9e158b88e5
...
80479e8c7d
Author | SHA1 | Date |
---|---|---|
|
80479e8c7d | 1 month ago |
|
9c8bd39a5b | 1 month ago |
11 changed files with 915 additions and 82 deletions
@ -0,0 +1,221 @@ |
|||||
|
import { EventEmitter } from 'events' |
||||
|
const log = require('electron-log') |
||||
|
|
||||
|
class ReconnectManager extends EventEmitter { |
||||
|
constructor() { |
||||
|
super() |
||||
|
this.reconnectTimers = new Map() // IP -> timer对象
|
||||
|
this.reconnectAttempts = new Map() // IP -> 当前重连次数
|
||||
|
this.reconnectConfig = { |
||||
|
enabled: false, |
||||
|
interval: 5, // 秒
|
||||
|
maxAttempts: 10 |
||||
|
} |
||||
|
this.isReconnecting = new Map() // IP -> boolean,防止重复重连
|
||||
|
} |
||||
|
|
||||
|
// 更新重连配置
|
||||
|
updateConfig(config) { |
||||
|
this.reconnectConfig = { |
||||
|
...this.reconnectConfig, |
||||
|
...config, |
||||
|
interval: Math.max(4, config.interval || this.reconnectConfig.interval) // 最小4秒
|
||||
|
} |
||||
|
log.info('Reconnect config updated:', this.reconnectConfig) |
||||
|
} |
||||
|
|
||||
|
// 启动重连
|
||||
|
startReconnect(ip, reason = 'Connection lost') { |
||||
|
if (!this.reconnectConfig.enabled) { |
||||
|
log.info(`Reconnect disabled for ${ip}`) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
// 防止重复启动重连
|
||||
|
if (this.isReconnecting.get(ip)) { |
||||
|
log.warn(`Reconnect already in progress for ${ip}`) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
this.isReconnecting.set(ip, true) |
||||
|
|
||||
|
// 如果没有当前重连次数,初始化为0
|
||||
|
if (!this.reconnectAttempts.has(ip)) { |
||||
|
this.reconnectAttempts.set(ip, 0) |
||||
|
} |
||||
|
|
||||
|
log.info(`${reason}, starting reconnect for ${ip}...`) |
||||
|
|
||||
|
// 发送重连状态更新
|
||||
|
this.emit('reconnect-status', { |
||||
|
ip, |
||||
|
isReconnecting: true |
||||
|
}) |
||||
|
|
||||
|
// 设置重连定时器
|
||||
|
this.scheduleNextAttempt(ip) |
||||
|
} |
||||
|
|
||||
|
// 安排下次重连尝试
|
||||
|
scheduleNextAttempt(ip) { |
||||
|
// 递增重连次数
|
||||
|
const currentAttempts = this.reconnectAttempts.get(ip) || 0 |
||||
|
const newAttempts = currentAttempts + 1 |
||||
|
this.reconnectAttempts.set(ip, newAttempts) |
||||
|
|
||||
|
if (newAttempts > this.reconnectConfig.maxAttempts) { |
||||
|
log.error( |
||||
|
`Max reconnect attempts reached for ${ip} (${newAttempts}/${this.reconnectConfig.maxAttempts})` |
||||
|
) |
||||
|
this.stopReconnect(ip, 'Max attempts reached') |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
log.info( |
||||
|
`Scheduling reconnect attempt ${newAttempts}/${this.reconnectConfig.maxAttempts} for ${ip}` |
||||
|
) |
||||
|
|
||||
|
const intervalMs = this.reconnectConfig.interval * 1000 |
||||
|
log.info(`Reconnect timer set for ${ip} in ${this.reconnectConfig.interval}s (${intervalMs}ms)`) |
||||
|
|
||||
|
const timer = setTimeout(() => { |
||||
|
log.info(`Reconnect timer fired for ${ip}, executing attempt ${newAttempts}`) |
||||
|
this.executeReconnectAttempt(ip) |
||||
|
}, intervalMs) |
||||
|
|
||||
|
// 清除之前的定时器
|
||||
|
this.clearTimer(ip) |
||||
|
this.reconnectTimers.set(ip, timer) |
||||
|
} |
||||
|
|
||||
|
// 执行重连尝试
|
||||
|
executeReconnectAttempt(ip) { |
||||
|
const attempts = this.reconnectAttempts.get(ip) || 0 |
||||
|
log.info( |
||||
|
`Executing reconnect attempt ${attempts}/${this.reconnectConfig.maxAttempts} for ${ip}` |
||||
|
) |
||||
|
|
||||
|
// 发出重连请求事件
|
||||
|
this.emit('attempt-reconnect', ip, (success, error) => { |
||||
|
if (success) { |
||||
|
log.info(`Reconnect attempt ${attempts} successful for ${ip}`) |
||||
|
this.onReconnectSuccess(ip) |
||||
|
} else { |
||||
|
log.warn(`Reconnect attempt ${attempts} failed for ${ip}: ${error?.message || error}`) |
||||
|
this.onReconnectFailure(ip, error) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 重连成功处理
|
||||
|
onReconnectSuccess(ip) { |
||||
|
const attempts = this.reconnectAttempts.get(ip) || 0 |
||||
|
log.info(`Reconnect attempt ${attempts} successful for ${ip}, clearing reconnect state`) |
||||
|
|
||||
|
// 停止重连
|
||||
|
this.stopReconnect(ip, 'Reconnect successful') |
||||
|
} |
||||
|
|
||||
|
// 重连失败处理
|
||||
|
onReconnectFailure(ip, error) { |
||||
|
const attempts = this.reconnectAttempts.get(ip) || 0 |
||||
|
|
||||
|
log.warn( |
||||
|
`Reconnect attempt ${attempts} failed for ${ip}, scheduling next attempt in ${this.reconnectConfig.interval}s`, |
||||
|
error |
||||
|
) |
||||
|
|
||||
|
// 发送重连状态更新
|
||||
|
this.emit('reconnect-status', { |
||||
|
ip, |
||||
|
isReconnecting: true |
||||
|
}) |
||||
|
|
||||
|
// 安排下次重连
|
||||
|
this.scheduleNextAttempt(ip) |
||||
|
} |
||||
|
|
||||
|
// 停止重连
|
||||
|
stopReconnect(ip, reason = 'Manual stop') { |
||||
|
log.info(`Stopping reconnect for ${ip}: ${reason}`) |
||||
|
|
||||
|
this.clearTimer(ip) |
||||
|
this.reconnectAttempts.delete(ip) |
||||
|
this.isReconnecting.set(ip, false) |
||||
|
|
||||
|
// 发送重连状态更新
|
||||
|
this.emit('reconnect-status', { |
||||
|
ip, |
||||
|
isReconnecting: false |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 清除重连定时器
|
||||
|
clearTimer(ip) { |
||||
|
const timer = this.reconnectTimers.get(ip) |
||||
|
if (timer) { |
||||
|
clearTimeout(timer) |
||||
|
this.reconnectTimers.delete(ip) |
||||
|
log.debug(`Cleared reconnect timer for ${ip}`) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 重置重连计数
|
||||
|
resetAttempts(ip) { |
||||
|
this.reconnectAttempts.set(ip, 0) |
||||
|
log.debug(`Reset reconnect attempts for ${ip}`) |
||||
|
} |
||||
|
|
||||
|
// 检查是否正在重连
|
||||
|
isReconnectInProgress(ip) { |
||||
|
return this.isReconnecting.get(ip) || false |
||||
|
} |
||||
|
|
||||
|
// 获取重连状态
|
||||
|
getReconnectStatus(ip) { |
||||
|
return { |
||||
|
isReconnecting: this.isReconnecting.get(ip) || false, |
||||
|
attempts: this.reconnectAttempts.get(ip) || 0, |
||||
|
maxAttempts: this.reconnectConfig.maxAttempts, |
||||
|
config: this.reconnectConfig |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 获取所有重连状态
|
||||
|
getAllReconnectStatus() { |
||||
|
const status = {} |
||||
|
for (const [ip] of this.isReconnecting) { |
||||
|
status[ip] = this.getReconnectStatus(ip) |
||||
|
} |
||||
|
return status |
||||
|
} |
||||
|
|
||||
|
// 清理指定IP的所有重连状态
|
||||
|
cleanup(ip) { |
||||
|
log.info(`Cleaning up reconnect state for ${ip}`) |
||||
|
this.clearTimer(ip) |
||||
|
this.reconnectAttempts.delete(ip) |
||||
|
this.isReconnecting.delete(ip) |
||||
|
} |
||||
|
|
||||
|
// 清理所有重连状态
|
||||
|
cleanupAll() { |
||||
|
log.info('Cleaning up all reconnect states') |
||||
|
|
||||
|
// 清除所有定时器
|
||||
|
for (const [ip] of this.reconnectTimers) { |
||||
|
this.clearTimer(ip) |
||||
|
} |
||||
|
|
||||
|
// 清除所有状态
|
||||
|
this.reconnectAttempts.clear() |
||||
|
this.isReconnecting.clear() |
||||
|
} |
||||
|
|
||||
|
// 获取配置
|
||||
|
getConfig() { |
||||
|
return { ...this.reconnectConfig } |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default ReconnectManager |
Loading…
Reference in new issue