diff --git a/main.js b/main.js index 6377ffc6e499c13c6c3f0f593cc4915fe63f9716..9891580edd62642a283289405a7c1c46dfccaf78 100644 --- a/main.js +++ b/main.js @@ -45,6 +45,17 @@ global.SOCKET_CLIENT = null; global.PRINT_RUNNER = new TaskRunner({ concurrency: 1 }); // 打印队列 done 集合 global.PRINT_RUNNER_DONE = {}; +// 分批打印任务的打印任务信息 +global.PRINT_FRAGMENTS_MAPPING = { + // [id: string]: { // 当前打印任务id,当此任务完成或超过指定时间会删除该对象 + // { + // total: number, // html片段总数 + // count: number, // 已经保存完成的片段数量,当count与total相同时,所有片段传输完成 + // fragments: Array, // 按照顺序摆放的html文本片段 + // updateTime: number, // 最后更新此任务信息的时间戳,用于超时时移除此对象 + // } + // } +}; // socket.io 服务端,用于创建本地服务 const ioServer = (global.SOCKET_SERVER = new require("socket.io")(server, { diff --git a/tools/utils.js b/tools/utils.js index 3389d48a1a954b5f5d11a6909fcb3be95cfb1166..528ffd2bc5e72617dd6ac36aeba45d1acc733f9c 100644 --- a/tools/utils.js +++ b/tools/utils.js @@ -119,6 +119,11 @@ const _address = { all: addressAll, }; +/** + * @description: 检查分片任务实例,用于自动删除超时分片信息 + */ +const watchTaskInstance = generateWatchTask(() => global.PRINT_FRAGMENTS_MAPPING)(); + /** * @description: 抛出当前客户端信息,提供更多有价值的信息,逐步替换原有 address * @param {io.Socket} socket @@ -139,6 +144,61 @@ function emitClientInfo(socket) { }); } +/** + * 生成检查分片任务的闭包函数 + * @param {Object} getCheckTarget 获取校验对象,最后会得到global.PRINT_FRAGMENTS_MAPPING + * @returns {Function} + */ +function generateWatchTask(getCheckTarget) { + // 记录当前检查任务是否开启,避免重复开启任务 + let isWatching = false; + /** + * @description: 检查分片任务实例创建函数 + * @param {Object} config 检查参数,根据实际情况调整 + * @param {number} [config.checkInterval=5] 执行内存检查的时间间隔,单位分钟 + * @param {number} [config.expire=5] 分片信息过期时间,单位分钟,不应过小 + */ + return function generateWatchTaskInstance(config = {}) { + // 合并用户和默认配置 + const realConfig = Object.assign({ + // checkInterval: 5, // 默认检查间隔 + // expire: 5, // 默认过期时间 + + checkInterval: 0.5, // 默认检查间隔 + expire: 1, // 默认过期时间 + }, config); + return { + startWatch() { + if (isWatching) return; + this.createWatchTimeout(); + }, + createWatchTimeout() { + // 更新开关状态 + isWatching = true + return setTimeout(this.clearFragmentsWhichIsExpired.bind(this), realConfig.checkInterval * 60 * 1000); + }, + clearFragmentsWhichIsExpired() { + const checkTarget = getCheckTarget(); + const currentTimeStamp = Date.now(); + Object.entries(checkTarget).map(([id, fragmentInfo]) => { + // 获取任务最后更新时间 + const { updateTime } = fragmentInfo + // 任务过期时,清除任务信息释放内存 + if ((currentTimeStamp - updateTime) > realConfig.expire * 60 * 1000) { + delete checkTarget[id] + } + }); + // 获取剩余任务数量 + const printTaskCount = Object.keys(checkTarget).length; + // 还有打印任务,继续创建检查任务 + if (printTaskCount) this.createWatchTimeout(); + // 更新开关状态 + else isWatching = false; + } + } + } +} + /** * @description: 作为本地服务端时绑定的 socket 事件 * @param {*} server @@ -319,6 +379,41 @@ function initServeEvent(server) { } }); + /** + * @description: client 分批打印任务 + */ + socket.on('printByFragments', (data) => { + if (data) { + const { total, index, htmlFragment, id, } = data + const currentInfo = PRINT_FRAGMENTS_MAPPING[id] + || (PRINT_FRAGMENTS_MAPPING[id] = { total, fragments: [], count: 0, updateTime: 0, }) + // 添加片段信息 + currentInfo.fragments[index] = htmlFragment; + // 计数 + currentInfo.count++; + // 记录更新时间 + currentInfo.updateTime = Date.now(); + // 全部片段已传输完毕 + if (currentInfo.count === currentInfo.total) { + // 清除全局缓存 + delete PRINT_FRAGMENTS_MAPPING[id] + // 合并全部打印片段信息 + data.html = currentInfo.fragments.join('') + // 添加打印任务 + PRINT_RUNNER.add((done) => { + data.socketId = socket.id; + data.taskId = new Date().getTime(); + data.clientType = "local"; + PRINT_WINDOW.webContents.send("print-new", data); + MAIN_WINDOW.webContents.send("printTask", true); + PRINT_RUNNER_DONE[data.taskId] = done; + }); + } + // 开始检查任务 + watchTaskInstance.startWatch(); + } + }); + /** * @description: client 断开连接 */