mm_machine
Version:
这是超级美眉框架机制构建辅助模块,用于快速构建一个机制
487 lines (455 loc) • 9.73 kB
JavaScript
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;