UNPKG

mm_machine

Version:

这是超级美眉框架机制构建辅助模块,用于快速构建一个机制

487 lines (455 loc) 9.73 kB
const util = require('util'); const conf = require('mm_config'); const Mod = require('mm_hot_reload'); $.mod = new Mod(); $.require = function(file, func) { return $.mod.load(file, func); } $.loadJson = function(file, func) { return $.mod.load(file, func); } /** * 驱动基础类 * @class */ class Item { /** * 构造函数 * @param {String} dir 当前目录 * @param {String} dir_base 模块目录 * @constructor */ constructor(dir, dir_base) { /** * 当前路径 */ this.dir = dir; /** * 默认文件 */ this.default_file = "./sys.json"; // 当前文件 this.filename; /* 通用项 */ /** * 配置参数 */ this.config = { /** * 名称, 由中英文和下“_”组成, 用于卸载接口 例如: demo */ "name": "", /** * 标题, 介绍作用 */ "title": "", /** * 描述, 用于描述该有什么用的 */ "description": "", /** * 文件路径, 当调用函数不存在时,会先从文件中加载 */ "func_file": "./index.js", /** * 回调函数名 用于决定调用脚本的哪个函数 */ "func_name": "", /** * 排序 */ "sort": 10, /** * 状态, 0表示未启用, 1表示启用 */ "state": 1, /** * 显示, 0表示不显示, 1表示显示 */ "show": 0 }; /** * 模块目录 */ this.dir_base = dir_base; /** * 模式 * 1.生产模式,改变文件不会重新加载 * 2.热更新模式,改变配置文件会重新加载配置,不重新加载脚本 * 3.热重载模式,改变配置文件都会加载配置和脚本 * 4.热更新+重载模式,改变配置文件重新加载配置和脚本,执行完后重新加载脚本 * 5.重载模式,执行完后重新加载脚本,避免变量污染 */ this.mode = 1; // 加载完成 this.complete = false; } } /** * 设置配置 * @param {Object} config 配置 */ Item.prototype.set_config = function(config) { if (config.func_file !== this.config.func_file) { this.complete = false; } this.config = conf(Object.assign({}, this.config, config || {}), this.filename); } /** * 设置配置后 */ Item.prototype.set_config_after = function() { }; /** * 新建脚本 * @param {String} file */ Item.prototype.new_script = function(file) { var fl = this.dir_base + "/script.js"; if (fl.hasFile()) { fl.copyFile(file); } }; /** * 移除模块 * @param {Object} m */ Item.prototype.remove_module = function(m) { if (this.mode === 3 || this.mode === 4) { // 移除模块和监听 $.mod.unload(m); } else { // 移除模块 var filename = require.resolve(m); require.cache[filename] = null; delete require.cache[filename]; } }; /** * 卸载脚本 * @param {String} file 文件 */ Item.prototype.unload_script = function(file) { if (!file) { var f = this.config.func_file; if (f) { file = f.fullname(this.dir) } } if (file) { this.remove_module(file); } this.complete = false; } /** * 重载脚本 * @param {String} file 文件 */ Item.prototype.reload_script = function() { this.unload_script(); this.load_script(); } /** * 卸载 */ Item.prototype.unload = async function() { } /** * 卸载之后 * @param {Boolean} remove 是否删除文件 */ Item.prototype.unload_after = async function(remove) { // 删除脚本 this.unload_script(); if (remove) { this.remove_file(); } } /** * 加载脚本 * @param {String} file 文件 * @param {String} name 函数名 * @returns {Object} 返回加载的模块对象 */ Item.prototype.load_script = function(file, name = "") { if (!file) { var f = this.config.func_file; if (f) { file = f.fullname(this.dir); if (!file.hasFile()) { this.new_script(file); } } else { return; } } if (!name) { name = this.config.func_name; } var cs; if (this.mode === 3 || this.mode === 4) { cs = $.require(file, (cs, way) => { if (way == "change" && cs) { if (name) { if (cs[name]) { this.main = cs[name]; } } else { $.push(this, cs, true); } } }); } else { cs = require(file); } if (cs) { if (name) { if (cs[name]) { this.main = cs[name]; } } else { $.push(this, cs, true); } } return cs; } /** * 新建配置 * @param {String} file */ Item.prototype.new_config = function(file) { var fl = this.dir_base + "/config.tpl.json"; fl.copyFile(file); }; /** * 加载配置文件 * @param {String} file 文件路径 * @param {String} name 配置项名称 * @return {Object} 配置对象 */ Item.prototype.load_file = function(file, name) { var config; var f = file.fullname(this.dir); var text = f.loadText(); if (!text) { this.new_config(f); } if (text) { if (this.mode === 2 || this.mode === 3 || this.mode === 4) { config = $.loadJson(f, (conf, way) => { if (way == "change" && conf) { if (Array.isArray(conf)) { var list = conf; for (var i = 0; i < list.length; i++) { var o = list[i]; if (this.config.name === o.name) { this.set_config(o); this.set_config_after(); if (this.mode === 3 || this.mode === 4) { this.reload_script(); } break; } } } else { this.set_config(conf); this.set_config_after(); if (this.mode === 3 || this.mode === 4) { this.reload_script(); } } } }); } else { config = f.loadJson(); } if (name) { if (Array.isArray(config)) { var list = config; for (var i = 0; i < list.length; i++) { var o = list[i]; if (name === o.name) { config = o; break; } } } } } this.dir = f.dirname(); this.filename = f; return config; }; /** * 删除文件 */ Item.prototype.del_dir = function() { var f = this.config.func_file; if (f) { $.dir.del(this.dir); } }; /** * 删除配置和脚本文件 * @param {Object} item 项目 */ Item.prototype.remove_file = function() { var name = this.config.name; var file = this.filename; var msg = null; if (file.hasFile()) { var text = file.loadText(); if (text) { var jarr = text.toJson(); if (jarr.constructor == Array) { for (var i = 0; i < jarr.length; i++) { var o = jarr[i]; if (name === o.name) { this.del_dir(); jarr.splice(i, 1); break; } } if (jarr.length) { file.saveText(JSON.stringify(jarr, null, 4)); } else { file.delFile(); } } else { this.del_dir(); } } else { this.del_dir(); } } else { msg = "配置文件不存在"; } return msg; }; /** * 载入配置 * @param {Object|String} cg 配置对象或配置路径 * @param {String} name 配置名称 */ Item.prototype.load_config = function(cg, name) { var config; if (cg) { if (typeof(cg) === "string") { config = this.load_file(cg, name); } else { config = cg; } } else { config = this.load_file(this.filename, name); } this.set_config(config); this.set_config_after(); }; /** * 加载前 */ Item.prototype.load_before = async function() { var cs = this.load_script(); if (cs) { this.complete = true; } } /** * 加载 */ Item.prototype.load = async function() { // 加载前 } /** * 重载配置和脚本 */ Item.prototype.reload = async function() { await this.run('unload'); await this.run('load'); } /** * 保存配置 */ Item.prototype.save = function() { var f = this.filename.fullname(this.dir); var text = f.loadText(); if (text) { if (text.trim().startsWith('[')) { var jarr = text.toJson(); for (var i = 0; i < jarr.length; i++) { if (jarr[i].name === this.config.name) { jarr[i] = this.config; break; } } var txt = JSON.stringify(jarr, null, 4); f.saveText(txt); return; } } var txt = JSON.stringify(this.config, null, 4); f.saveText(txt); }; /** * 主要执行函数 * @param {Object} params 参数集合 */ Item.prototype.main = async function(...params) { // console.log("未实现", params); return null; }; /** * 运行 * @param {Object} params 参数集合 */ Item.prototype.run = async function(...params) { return await this.exec("main", ...params); } /** * 调用函数 * @param {String} method 函数名 * @param {Object} params 参数集合 * @return {Object} 执行结果 */ Item.prototype.exec = async function(method, ...params) { if (this[method]) { var ret; if (this[method + "_before"]) { try { ret = this[method + "_before"](...params); } catch (err) { $.log.error("执行前失败!", err); } if (util.types.isPromise(ret)) { ret = await ret; } } try { ret = this[method](...params); } catch (err) { $.log.error("执行时失败!", err); } if (util.types.isPromise(ret)) { ret = await ret; } // console.log(this.config.name + "-" + method + "内容", ret); if (this[method + "_after"]) { try { var result = this[method + "_after"](ret, ...params); if (util.types.isPromise(result)) { result = await result; } if (result) { ret = result; } } catch (err) { $.log.error("执行后失败!", err); } } return ret } }; /** * @module 导出Drive类 */ module.exports = Item;