const deviceManager = require('../core/deviceManager'); const accountValidator = require('../services/accountValidator'); const db = require('../../dbProxy'); /** * 任务处理器基类 * 提供通用的授权检查、计时、错误处理、设备记录等功能 */ class BaseHandler { constructor(mqttClient) { this.mqttClient = mqttClient; } /** * 执行任务(带授权检查和错误处理) * @param {object} task - 任务对象 * @param {Function} businessLogic - 业务逻辑函数 * @param {object} options - 选项 * @returns {Promise} 执行结果 */ async execute(task, businessLogic, options = {}) { const { checkAuth = true, // 是否检查授权 checkOnline = true, // 是否检查在线状态 recordDeviceMetrics = true // 是否记录设备指标 } = options; const { sn_code, taskName } = task; const startTime = Date.now(); try { // 1. 验证账户(启用 + 授权 + 在线) if (checkAuth || checkOnline) { const validation = await accountValidator.validate(sn_code, { checkEnabled: true, checkAuth, checkOnline, offlineThreshold: 3 * 60 * 1000 // 3分钟 }); if (!validation.valid) { throw new Error(`设备 ${sn_code} 验证失败: ${validation.reason}`); } } // 2. 记录任务开始 if (recordDeviceMetrics) { deviceManager.recordTaskStart(sn_code, task); } // 3. 执行业务逻辑 const result = await businessLogic(); // 4. 记录任务成功 const duration = Date.now() - startTime; if (recordDeviceMetrics) { deviceManager.recordTaskComplete(sn_code, task, true, duration); } return { success: true, duration, ...result }; } catch (error) { // 5. 记录任务失败 const duration = Date.now() - startTime; if (recordDeviceMetrics) { deviceManager.recordTaskComplete(sn_code, task, false, duration); } console.error(`[${taskName}] 执行失败 (设备: ${sn_code}):`, error.message); return { success: false, error: error.message, duration }; } } /** * 检查每日操作限制 * @param {string} sn_code - 设备序列号 * @param {string} operation - 操作类型 (search, deliver, chat) * @param {string} platform - 平台类型 * @returns {Promise<{allowed: boolean, count?: number, limit?: number, reason?: string}>} */ async checkDailyLimit(sn_code, operation, platform = 'boss') { try { const today = new Date().toISOString().split('T')[0]; const task_status = db.getModel('task_status'); // 查询今日该操作的完成次数 const count = await task_status.count({ where: { sn_code, taskType: `auto_${operation}`, status: 'completed', endTime: { [db.models.op.gte]: new Date(today) } } }); // 获取每日限制(从 deviceManager 或配置) const limit = deviceManager.canExecuteOperation(sn_code, operation); if (!limit.allowed) { return { allowed: false, count, reason: limit.reason }; } return { allowed: true, count, limit: limit.max || 999 }; } catch (error) { console.error(`[每日限制检查] 失败 (${sn_code}, ${operation}):`, error); return { allowed: true }; // 检查失败时默认允许 } } /** * 检查执行间隔时间 * @param {string} sn_code - 设备序列号 * @param {string} taskType - 任务类型 * @param {number} intervalMinutes - 间隔时间(分钟) * @returns {Promise<{allowed: boolean, elapsed?: number, remaining?: number, reason?: string}>} */ async checkInterval(sn_code, taskType, intervalMinutes) { try { const task_status = db.getModel('task_status'); // 查询最近一次成功完成的任务 const lastTask = await task_status.findOne({ where: { sn_code, taskType, status: 'completed' }, order: [['endTime', 'DESC']], attributes: ['endTime'] }); if (!lastTask || !lastTask.endTime) { return { allowed: true, elapsed: null }; } const now = Date.now(); const lastTime = new Date(lastTask.endTime).getTime(); const elapsed = now - lastTime; const intervalMs = intervalMinutes * 60 * 1000; if (elapsed < intervalMs) { const remainingMinutes = Math.ceil((intervalMs - elapsed) / (60 * 1000)); const elapsedMinutes = Math.floor(elapsed / (60 * 1000)); return { allowed: false, elapsed: elapsedMinutes, remaining: remainingMinutes, reason: `距离上次执行仅 ${elapsedMinutes} 分钟,还需等待 ${remainingMinutes} 分钟` }; } return { allowed: true, elapsed: Math.floor(elapsed / (60 * 1000)) }; } catch (error) { console.error(`[间隔检查] 失败 (${sn_code}, ${taskType}):`, error); return { allowed: true }; // 检查失败时默认允许 } } /** * 获取账户配置 * @param {string} sn_code - 设备序列号 * @param {string[]} fields - 需要的字段 * @returns {Promise} */ async getAccountConfig(sn_code, fields = ['*']) { try { const pla_account = db.getModel('pla_account'); const account = await pla_account.findOne({ where: { sn_code, is_delete: 0 }, attributes: fields }); return account ? account.toJSON() : null; } catch (error) { console.error(`[获取账户配置] 失败 (${sn_code}):`, error); return null; } } /** * 推送设备工作状态(可选的通知) * @param {string} sn_code - 设备序列号 * @param {object} status - 状态信息 */ async notifyDeviceStatus(sn_code, status) { try { const deviceWorkStatusNotifier = require('../notifiers/deviceWorkStatusNotifier'); await deviceWorkStatusNotifier.sendDeviceWorkStatus(sn_code, status); } catch (error) { console.warn(`[状态推送] 失败 (${sn_code}):`, error.message); } } /** * 标准化错误响应 * @param {Error} error - 错误对象 * @param {string} sn_code - 设备序列号 * @returns {object} 标准化的错误响应 */ formatError(error, sn_code) { return { success: false, error: error.message || '未知错误', sn_code, timestamp: new Date().toISOString() }; } /** * 标准化成功响应 * @param {object} data - 响应数据 * @param {string} sn_code - 设备序列号 * @returns {object} 标准化的成功响应 */ formatSuccess(data, sn_code) { return { success: true, sn_code, timestamp: new Date().toISOString(), ...data }; } } module.exports = BaseHandler;