const dayjs = require('dayjs'); const Sequelize = require('sequelize'); const db = require('../dbProxy'); const config = require('./config'); const utils = require('./utils'); /** * 设备管理器(简化版) * 合并了 Monitor 和 Strategy 的核心功能 */ class DeviceManager { constructor() { // 设备状态 { sn_code: { isOnline, lastHeartbeat, lastSearch, lastApply, lastChat, dailyCounts } } this.devices = new Map(); // 系统统计 this.stats = { totalDevices: 0, onlineDevices: 0, totalTasks: 0, completedTasks: 0, failedTasks: 0, startTime: new Date() }; } /** * 初始化 */ async init() { console.log('[设备管理器] 初始化中...'); await this.loadStats(); console.log('[设备管理器] 初始化完成'); } /** * 加载统计数据 */ async loadStats() { try { const devices = await db.getModel('pla_account').findAll(); this.stats.totalDevices = devices.length; const completedCount = await db.getModel('task_status').count({ where: { status: 'completed' } }); const failedCount = await db.getModel('task_status').count({ where: { status: 'failed' } }); this.stats.completedTasks = completedCount; this.stats.failedTasks = failedCount; this.stats.totalTasks = completedCount + failedCount; } catch (error) { console.error('[设备管理器] 加载统计失败:', error); } } /** * 记录心跳 */ async recordHeartbeat(sn_code, heartbeatData = {}) { const now = Date.now(); if (!this.devices.has(sn_code)) { this.devices.set(sn_code, { isOnline: true, isLoggedIn: heartbeatData.isLoggedIn || false, lastHeartbeat: now, dailyCounts: { date: utils.getTodayString(), searchCount: 0, applyCount: 0, chatCount: 0 } }); console.log(`[设备管理器] 新设备 ${sn_code} 初始化 - isLoggedIn: ${heartbeatData.isLoggedIn}`); } const device = this.devices.get(sn_code); device.isOnline = true; device.lastHeartbeat = now; // 更新登录状态 if (heartbeatData.isLoggedIn !== undefined) { device.isLoggedIn = heartbeatData.isLoggedIn; console.log(`[设备管理器] 设备 ${sn_code} 登录状态更新 - isLoggedIn: ${device.isLoggedIn}`); } } /** * 检查设备是否在线 */ isDeviceOnline(sn_code) { const device = this.devices.get(sn_code); if (!device) return false; const elapsed = Date.now() - device.lastHeartbeat; if (elapsed > config.monitoring.heartbeatTimeout) { device.isOnline = false; return false; } return device.isOnline; } /** * 检查是否可以执行操作 */ canExecuteOperation(sn_code, operation_type) { // 检查频率限制 const device = this.devices.get(sn_code); if (device) { const lastTime = device[`last${operation_type.charAt(0).toUpperCase() + operation_type.slice(1)}`] || 0; const interval = config.getRateLimit(operation_type); if (Date.now() - lastTime < interval) { return { allowed: false, reason: '操作过于频繁' }; } } // 检查日限制 if (device && device.dailyCounts) { const today = utils.getTodayString(); if (device.dailyCounts.date !== today) { device.dailyCounts = { date: today, searchCount: 0, applyCount: 0, chatCount: 0 }; } const countKey = `${operation_type}Count`; const current = device.dailyCounts[countKey] || 0; const max = config.getDailyLimit(operation_type); if (current >= max) { return { allowed: false, reason: `今日${operation_type}操作已达上限` }; } } return { allowed: true }; } /** * 记录操作 */ recordOperation(sn_code, operation_type) { const device = this.devices.get(sn_code) || {}; device[`last${operation_type.charAt(0).toUpperCase() + operation_type.slice(1)}`] = Date.now(); if (device.dailyCounts) { const countKey = `${operation_type}Count`; device.dailyCounts[countKey] = (device.dailyCounts[countKey] || 0) + 1; } this.devices.set(sn_code, device); } /** * 记录任务开始 */ recordTaskStart(sn_code, task) { // 简化实现,只记录日志 console.log(`[设备管理器] 设备 ${sn_code} 开始执行任务: ${task.taskName}`); } /** * 记录任务完成 */ recordTaskComplete(sn_code, task, success, duration) { if (success) { this.stats.completedTasks++; } else { this.stats.failedTasks++; } this.stats.totalTasks++; console.log(`[设备管理器] 设备 ${sn_code} 任务${success ? '成功' : '失败'}: ${task.taskName} (${duration}ms)`); } /** * 获取系统统计 */ getSystemStats() { const onlineCount = Array.from(this.devices.values()).filter(d => d.isOnline).length; return { ...this.stats, onlineDevices: onlineCount, uptime: utils.formatDuration(Date.now() - this.stats.startTime.getTime()) }; } /** * 获取所有设备状态 */ getAllDevicesStatus() { const result = {}; for (const [sn_code, device] of this.devices.entries()) { result[sn_code] = { isOnline: device.isOnline, isLoggedIn: device.isLoggedIn || false, lastHeartbeat: device.lastHeartbeat, dailyCounts: device.dailyCounts || {} }; } return result; } /** * 检查心跳状态(仅更新内存状态,device_status 表已移除) */ async checkHeartbeatStatus() { try { const now = Date.now(); const offlineDevices = []; // 检查内存中的设备状态 for (const [sn_code, device] of this.devices.entries()) { if (now - device.lastHeartbeat > config.monitoring.heartbeatTimeout) { // 如果之前是在线状态,现在检测到离线 if (device.isOnline) { device.isOnline = false; offlineDevices.push(sn_code); } } } // 记录离线设备(仅日志,不再更新数据库) if (offlineDevices.length > 0) { console.log(`[设备管理器] 检测到 ${offlineDevices.length} 个设备心跳超时: ${offlineDevices.join(', ')}`); // 注意:device_status 表已移除,设备状态仅在内存中维护 } } catch (error) { console.error('[设备管理器] 检查心跳状态失败:', error); } } /** * 重置所有日计数器 */ resetAllDailyCounters() { const today = utils.getTodayString(); for (const device of this.devices.values()) { if (device.dailyCounts && device.dailyCounts.date !== today) { device.dailyCounts = { date: today, searchCount: 0, applyCount: 0, chatCount: 0 }; } } } /** * 清理离线设备 */ cleanupOfflineDevices(threshold = 3600000) { const now = Date.now(); for (const [sn_code, device] of this.devices.entries()) { if (now - device.lastHeartbeat > threshold) { this.devices.delete(sn_code); } } } } // 导出单例 const deviceManager = new DeviceManager(); module.exports = deviceManager;