Files
autoAiWorkSys/api/middleware/schedule/deviceManager.js
张成 c6c78d0c43 1
2025-12-25 13:10:54 +08:00

243 lines
7.7 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 && 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;