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