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