UNPKG

node-web-mvc

Version:
117 lines (116 loc) 4.48 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const child_process_1 = __importDefault(require("child_process")); const destroyHandlers = []; const releaseForHandlers = []; class HotUpdaterReleaseManager { static normalizeId(file) { return (file || '').toLowerCase(); } static resolveDependency(stack) { const files = (stack || '').split('\n').slice(2, 10).map((m) => { return m.split('(').pop().replace(/(:\d+)+/, '').replace(/\)$/, ''); }); return files[0]; } /** * 通用拦截函数,用于拦截指定函数的返回值,与调用依赖,记录下依赖与返回值 * @param name 要拦截的函数名 * @param target 要拦截的目标对象 * @param dependencies 依赖记录集合 * @returns 代理对象 */ static proxyMethod(target, name, releaseHandler) { const scope = this; const dependencies = new Map(); releaseForHandlers.push((file) => { file = this.normalizeId(file); const values = dependencies.get(file) || []; values.forEach((value) => { // console.log('release method', name); releaseHandler(value); }); }); const value = target[name]; const meta = Proxy.revocable(value, { apply(handler, thisArg, args) { const file = scope.resolveDependency(new Error().stack); const id = scope.normalizeId(file); const returnValue = handler.apply(thisArg, args); if (!dependencies.has(id)) { dependencies.set(id, []); } dependencies.get(id).push(returnValue); // console.log('call method', name); return returnValue; }, }); target[name] = meta.proxy; return meta.proxy; } /** * 通用拦截类构造函数,并且记录调用依赖 * @param clazz 类 * @param releaseHandler 自定义释放函数 * @returns */ static proxyClass(clazz, releaseHandler) { const scope = this; const dependencies = new Map(); releaseForHandlers.push((file) => { file = this.normalizeId(file); const values = dependencies.get(file) || []; values.forEach((value) => { // console.log('release instance', clazz.name); releaseHandler(value); }); }); const meta = Proxy.revocable(clazz, { construct(target, argArray) { const file = scope.resolveDependency(new Error().stack); const id = scope.normalizeId(file); const returnValue = new target(...argArray); if (!dependencies.has(id)) { dependencies.set(id, []); } dependencies.get(id).push(returnValue); // console.log('create instance', target.name); return returnValue; }, }); return meta.proxy; } static install() { if (this.installed) return; this.installed = true; // 拦截setInterval this.proxyMethod(global, 'setInterval', (id) => clearInterval(id)); // 拦截setTimeout this.proxyMethod(global, 'setTimeout', (id) => clearTimeout(id)); // 拦截子进程 this.proxyMethod(child_process_1.default, 'spawn', (child) => child.kill()); this.proxyMethod(child_process_1.default, 'exec', (child) => child.kill()); this.proxyMethod(child_process_1.default, 'execFile', (child) => child.kill()); this.proxyMethod(child_process_1.default, 'fork', (child) => child.kill()); } static push(handler) { destroyHandlers.push(handler); } static releaseFor(file) { releaseForHandlers.forEach((handler) => handler(file)); } static destroy() { destroyHandlers.forEach(handler => handler()); destroyHandlers.length = 0; Object.keys(require.cache).forEach((file) => { this.releaseFor(file); }); destroyHandlers.length = 0; } } HotUpdaterReleaseManager.installed = false; exports.default = HotUpdaterReleaseManager;