You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
5.7 KiB
221 lines
5.7 KiB
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
|
|
|