Browse Source
- 添加了 ReconnectManager 类,用于处理重连逻辑和状态 - 引入了用于重连配置和状态更新的 IPC 事件 - 增强了设备连接处理,支持断开连接时自动重连 - 集成了带有可配置限制和启用选项的告警功能 - 更新了 UI 组件,以反映连接状态并根据设备连接性启用 / 禁用输入 - 实现了心跳检查,用于监控设备连接状态并在必要时触发重连 - 重构了现有代码,以适应新的重连功能并提高可维护性master
9 changed files with 849 additions and 61 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