mm_machine 2.2.5 → 2.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +10 -23
- package/package.json +3 -4
- package/item.js +0 -697
package/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
const {
|
|
2
|
-
const {
|
|
1
|
+
const { Mod } = require('./mod');
|
|
2
|
+
const { Drive } = require('./drive.js');
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* 管理器类
|
|
6
6
|
*/
|
|
7
|
-
class Manager extends
|
|
7
|
+
class Manager extends Mod {
|
|
8
8
|
static config = {
|
|
9
9
|
// 管理器名称
|
|
10
10
|
name: 'manager',
|
|
@@ -73,7 +73,7 @@ Manager.prototype.getBaseDir = function () {
|
|
|
73
73
|
/**
|
|
74
74
|
* 默认驱动
|
|
75
75
|
*/
|
|
76
|
-
Manager.prototype.Drive =
|
|
76
|
+
Manager.prototype.Drive = Drive;
|
|
77
77
|
|
|
78
78
|
/**
|
|
79
79
|
* 更新模块信息
|
|
@@ -153,7 +153,7 @@ Manager.prototype.newMod = function (config_file, config, script) {
|
|
|
153
153
|
let mod;
|
|
154
154
|
switch (this.config.type) {
|
|
155
155
|
case 'script':
|
|
156
|
-
mod = new
|
|
156
|
+
mod = new Mod(config, this);
|
|
157
157
|
break;
|
|
158
158
|
default:
|
|
159
159
|
// 创建模块
|
|
@@ -324,13 +324,10 @@ Manager.prototype.update = async function (dir, clear = true) {
|
|
|
324
324
|
// 批量加载脚本
|
|
325
325
|
await this.loadScripts();
|
|
326
326
|
}
|
|
327
|
+
this.is_loaded = true;
|
|
327
328
|
};
|
|
328
329
|
|
|
329
330
|
// ==== 高性能调用接口 ====
|
|
330
|
-
Manager.prototype.run = async function (name, method, ...params) {
|
|
331
|
-
return await this.main(name, method, ...params);
|
|
332
|
-
};
|
|
333
|
-
|
|
334
331
|
/**
|
|
335
332
|
* 调用模块的方法(高性能版本)
|
|
336
333
|
* @param {string} name 模块名
|
|
@@ -434,14 +431,14 @@ Manager.prototype._runSub = async function (mod, method, ...params) {
|
|
|
434
431
|
try {
|
|
435
432
|
// 确保模块已加载
|
|
436
433
|
if (!mod.isLoaded()) {
|
|
437
|
-
await mod.
|
|
434
|
+
await mod.do('loadScript');
|
|
438
435
|
}
|
|
439
436
|
|
|
440
437
|
// 执行方法
|
|
441
438
|
let ret = await mod.exec(method, ...params);
|
|
442
439
|
// 根据模式决定是否重载
|
|
443
440
|
if (this.mode >= 4) {
|
|
444
|
-
mod.
|
|
441
|
+
mod.do('reload');
|
|
445
442
|
}
|
|
446
443
|
|
|
447
444
|
return ret;
|
|
@@ -451,16 +448,6 @@ Manager.prototype._runSub = async function (mod, method, ...params) {
|
|
|
451
448
|
}
|
|
452
449
|
};
|
|
453
450
|
|
|
454
|
-
/**
|
|
455
|
-
* 调用模块的方法
|
|
456
|
-
* @param {string} name 模块名
|
|
457
|
-
* @param {object} params 参数集合
|
|
458
|
-
* @returns {Promise<any>} 执行结果
|
|
459
|
-
*/
|
|
460
|
-
Manager.prototype.call = async function (name, params = {}) {
|
|
461
|
-
return await this.run(name, 'main', params);
|
|
462
|
-
};
|
|
463
|
-
|
|
464
451
|
/**
|
|
465
452
|
* 初始化管理器
|
|
466
453
|
*/
|
|
@@ -494,8 +481,8 @@ Manager.prototype._initCore = function () {
|
|
|
494
481
|
|
|
495
482
|
module.exports = {
|
|
496
483
|
Manager,
|
|
497
|
-
Item,
|
|
498
484
|
Drive,
|
|
499
485
|
// 向后兼容
|
|
500
|
-
Index: Manager
|
|
486
|
+
Index: Manager,
|
|
487
|
+
Item: Drive
|
|
501
488
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mm_machine",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.6",
|
|
4
4
|
"description": "A flexible Node.js plugin mechanism system for dynamic loading, management and execution of modules. Supports hot reload, lifecycle management, and modern JavaScript features.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -33,9 +33,8 @@
|
|
|
33
33
|
"README.md"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"mm_config": "^2.
|
|
37
|
-
"
|
|
38
|
-
"mm_hot_reload": "^1.2.5",
|
|
36
|
+
"mm_config": "^2.3.0",
|
|
37
|
+
"mm_hot_reload": "^1.3.0",
|
|
39
38
|
"mm_tpl": "^2.4.9"
|
|
40
39
|
},
|
|
41
40
|
"devDependencies": {
|
package/item.js
DELETED
|
@@ -1,697 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
Drive
|
|
3
|
-
} = require('./drive');
|
|
4
|
-
require('mm_tpl');
|
|
5
|
-
require('mm_hot_reload');
|
|
6
|
-
let {
|
|
7
|
-
conf
|
|
8
|
-
} = require('mm_config');
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* 增强require函数,专门用于脚本文件(.js)热重载
|
|
12
|
-
* 当脚本文件内容发生变化时,自动重新加载并触发回调
|
|
13
|
-
* @param {string} file 脚本文件路径(.js)
|
|
14
|
-
* @param {Function} func 热更新回调函数,文件变化时触发
|
|
15
|
-
* @returns {object} 加载的模块对象
|
|
16
|
-
* @throws {TypeError} 文件路径不是字符串或回调不是函数时抛出
|
|
17
|
-
*/
|
|
18
|
-
$.require = function (file, func) {
|
|
19
|
-
// 参数校验
|
|
20
|
-
if (typeof file !== 'string') {
|
|
21
|
-
throw new TypeError('文件路径必须是字符串');
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (func && typeof func !== 'function') {
|
|
25
|
-
throw new TypeError('回调函数必须是函数');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// 确保文件是.js文件
|
|
29
|
-
if (!file.endsWith('.js')) {
|
|
30
|
-
throw new TypeError('$.require 只能用于.js脚本文件');
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return $.mod.load(file, func);
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* 增强JSON加载函数,专门用于配置文件(.json)热重载
|
|
38
|
-
* 当配置文件内容发生变化时,自动重新加载并触发回调
|
|
39
|
-
* @param {string} file 配置文件路径(.json)
|
|
40
|
-
* @param {Function} func 热更新回调函数,文件变化时触发
|
|
41
|
-
* @returns {object} 解析的JSON对象
|
|
42
|
-
* @throws {TypeError} 文件路径不是字符串或回调不是函数时抛出
|
|
43
|
-
*/
|
|
44
|
-
$.loadJson = function (file, func) {
|
|
45
|
-
// 参数校验
|
|
46
|
-
if (typeof file !== 'string') {
|
|
47
|
-
throw new TypeError('文件路径必须是字符串');
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (func && typeof func !== 'function') {
|
|
51
|
-
throw new TypeError('回调函数必须是函数');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// 确保文件是.json文件
|
|
55
|
-
if (!file.endsWith('.json')) {
|
|
56
|
-
throw new TypeError('$.loadJson 只能用于.json配置文件');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return $.mod.load(file, func);
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* 驱动基础类
|
|
64
|
-
* @class
|
|
65
|
-
*/
|
|
66
|
-
class Item extends Drive {
|
|
67
|
-
// 模块基础目录,用于放置脚本模板文件和配置模板文件
|
|
68
|
-
static base_dir = '';
|
|
69
|
-
|
|
70
|
-
// 配置项
|
|
71
|
-
static config = {
|
|
72
|
-
// 名称, 由中英文和下"_"组成, 用于卸载接口 例如: demo
|
|
73
|
-
name: '',
|
|
74
|
-
// 标题, 介绍作用
|
|
75
|
-
title: '',
|
|
76
|
-
// 描述, 用于描述该有什么用的
|
|
77
|
-
description: '',
|
|
78
|
-
// 文件路径, 当调用函数不存在时,会先从文件中加载
|
|
79
|
-
main: './index.js',
|
|
80
|
-
// 回调函数名 用于决定调用脚本的哪个函数
|
|
81
|
-
func_name: 'main',
|
|
82
|
-
// 作用域(同时作为检索的后缀名)
|
|
83
|
-
scope: ($.val && $.val.scope) ? $.val.scope : 'server',
|
|
84
|
-
// 排序
|
|
85
|
-
sort: 10,
|
|
86
|
-
// 状态, 0表示未启用, 1表示启用
|
|
87
|
-
state: 1,
|
|
88
|
-
// 显示, 0表示不显示, 1表示显示
|
|
89
|
-
show: 0,
|
|
90
|
-
// 是否结束,可选,默认false
|
|
91
|
-
end: false
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* 构造函数
|
|
96
|
-
* @param {object} config 配置项
|
|
97
|
-
* @param {object} parent 父项
|
|
98
|
-
* @class
|
|
99
|
-
*/
|
|
100
|
-
constructor(config, parent) {
|
|
101
|
-
super({
|
|
102
|
-
...Item.config,
|
|
103
|
-
...config
|
|
104
|
-
}, parent);
|
|
105
|
-
// 当前配置文件路径
|
|
106
|
-
this.config_file = '';
|
|
107
|
-
|
|
108
|
-
// 当前脚本文件路径
|
|
109
|
-
this.script_file = '';
|
|
110
|
-
|
|
111
|
-
// 模式: 1.生产模式 2.热更新模式 3.热重载模式 4.热更新+重载模式 5.重载模式
|
|
112
|
-
this.mode = 1;
|
|
113
|
-
|
|
114
|
-
this.status = '';
|
|
115
|
-
// 脚本的方法
|
|
116
|
-
this.methods = {};
|
|
117
|
-
|
|
118
|
-
// 资源配置列表
|
|
119
|
-
this.getParent = function () {
|
|
120
|
-
return parent;
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* 检查模块是否已加载
|
|
127
|
-
* @returns {boolean} 是否已加载
|
|
128
|
-
*/
|
|
129
|
-
Item.prototype.isLoaded = function () {
|
|
130
|
-
return this.is_loaded;
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* 获取方法函数
|
|
135
|
-
* @param {string} method 方法名
|
|
136
|
-
* @returns {Function|null} 方法函数
|
|
137
|
-
*/
|
|
138
|
-
Item.prototype._getMethod = function (method) {
|
|
139
|
-
let func = this._methods && this._methods[method];
|
|
140
|
-
if (!func) {
|
|
141
|
-
func = this[method];
|
|
142
|
-
}
|
|
143
|
-
return func || null;
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* 设置脚本方法
|
|
148
|
-
* @param {object} methods 脚本方法对象
|
|
149
|
-
*/
|
|
150
|
-
Item.prototype.setMethods = function (methods) {
|
|
151
|
-
if (!methods) return;
|
|
152
|
-
Object.assign(this.methods, methods);
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* 获取配置
|
|
157
|
-
* @param {string} file 配置文件路径
|
|
158
|
-
* @returns {object} 配置项
|
|
159
|
-
*/
|
|
160
|
-
Item.prototype.loadConfig = function (file) {
|
|
161
|
-
if (file) {
|
|
162
|
-
this.config_file = file;
|
|
163
|
-
};
|
|
164
|
-
// 加载配置
|
|
165
|
-
let config = $.loadJson(this.config_file, (cg) => {
|
|
166
|
-
this.setConfig(cg);
|
|
167
|
-
return cg;
|
|
168
|
-
});
|
|
169
|
-
if (!config) {
|
|
170
|
-
this.newConfig(this.config_file);
|
|
171
|
-
config = $.loadJson(this.config_file, (cg) => {
|
|
172
|
-
this.setConfig(cg);
|
|
173
|
-
return cg;
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
this.setConfig(config);
|
|
177
|
-
return config;
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* 设置配置
|
|
182
|
-
* @param {object} config 配置对象
|
|
183
|
-
*/
|
|
184
|
-
Item.prototype.setConfig = function (config) {
|
|
185
|
-
if (config) {
|
|
186
|
-
// 如果main改变,重置加载状态
|
|
187
|
-
if (config.main !== this.config.main) {
|
|
188
|
-
this.is_loaded = false;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (this.config_file) {
|
|
192
|
-
// 合并配置并应用配置处理
|
|
193
|
-
this.config = conf({
|
|
194
|
-
...this.config,
|
|
195
|
-
...config
|
|
196
|
-
}, this.config_file);
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
Object.assign(this.config, config);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
return this.config;
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* 获取配置
|
|
207
|
-
* @returns {object} 配置项
|
|
208
|
-
*/
|
|
209
|
-
Item.prototype.getConfig = function () {
|
|
210
|
-
return this.config;
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* 获取当前文件
|
|
215
|
-
* @returns {object} 当前文件对象
|
|
216
|
-
*/
|
|
217
|
-
Item.prototype._getDir = function () {
|
|
218
|
-
let dir = this._dir;
|
|
219
|
-
if (!dir) {
|
|
220
|
-
if (this.script_file) {
|
|
221
|
-
dir = this.script_file.dirname();
|
|
222
|
-
this._dir = dir;
|
|
223
|
-
}
|
|
224
|
-
else if (this.config_file) {
|
|
225
|
-
dir = this.config_file.dirname();
|
|
226
|
-
this._dir = dir;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
return dir;
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* 获取模块目录
|
|
234
|
-
* @returns {string} 模块目录
|
|
235
|
-
*/
|
|
236
|
-
Item.prototype._getBaseDir = function () {
|
|
237
|
-
return this.getParent().getBaseDir();
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* 创建脚本
|
|
242
|
-
* @param {string} file 文件路径
|
|
243
|
-
* @param {object} model 模板数据
|
|
244
|
-
* @param {string} tpl_dir 模板文件路径
|
|
245
|
-
* @returns {boolean} 创建是否成功
|
|
246
|
-
*/
|
|
247
|
-
Item.prototype._createScriptFile = function (file, model = {}, tpl_dir = '') {
|
|
248
|
-
var tpl = this.getScriptTpl(tpl_dir);
|
|
249
|
-
var content = $.tpl.render(tpl, model);
|
|
250
|
-
file.saveText(content);
|
|
251
|
-
return file;
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* 获取脚本模板
|
|
256
|
-
* @param {string} tpl_dir 模板文件路径
|
|
257
|
-
* @returns {string} 脚本模板内容
|
|
258
|
-
*/
|
|
259
|
-
Item.prototype.getScriptTpl = function (tpl_dir = '') {
|
|
260
|
-
var f = './script.tpl.js'.fullname(tpl_dir || this.constructor.base_dir);
|
|
261
|
-
if (f.hasFile()) {
|
|
262
|
-
return f.loadText();
|
|
263
|
-
} else {
|
|
264
|
-
return `module.exports = {
|
|
265
|
-
/**
|
|
266
|
-
* 初始化
|
|
267
|
-
*/
|
|
268
|
-
async _init() {
|
|
269
|
-
this.log('debug', \`初始化!\`);
|
|
270
|
-
},
|
|
271
|
-
/**
|
|
272
|
-
* 销毁
|
|
273
|
-
*/
|
|
274
|
-
async _destroy(...args) {
|
|
275
|
-
this.log('debug', \`销毁!\`);
|
|
276
|
-
},
|
|
277
|
-
/**
|
|
278
|
-
* 主要逻辑
|
|
279
|
-
*/
|
|
280
|
-
async main(...args) {
|
|
281
|
-
// 主要代码写在这
|
|
282
|
-
}
|
|
283
|
-
}`;
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* 移除脚本
|
|
289
|
-
*/
|
|
290
|
-
Item.prototype._remove = function () {
|
|
291
|
-
let file = this._getScriptFile();
|
|
292
|
-
if (!file) return;
|
|
293
|
-
|
|
294
|
-
try {
|
|
295
|
-
if (this.mode === 3 || this.mode === 4) {
|
|
296
|
-
// 移除模块和监听
|
|
297
|
-
$.mod.unload(file);
|
|
298
|
-
} else {
|
|
299
|
-
// 移除模块缓存
|
|
300
|
-
let filename = require.resolve(file);
|
|
301
|
-
if (require.cache[filename]) {
|
|
302
|
-
require.cache[filename] = null;
|
|
303
|
-
delete require.cache[filename];
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
} catch (err) {
|
|
307
|
-
this.log('error', `移除脚本失败: `, err);
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* 卸载脚本
|
|
313
|
-
*/
|
|
314
|
-
Item.prototype.unloadScript = function () {
|
|
315
|
-
this._remove();
|
|
316
|
-
this.is_loaded = false;
|
|
317
|
-
};
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* 重新加载脚本
|
|
321
|
-
* @returns {object | null} 返回加载的模块对象
|
|
322
|
-
*/
|
|
323
|
-
Item.prototype.reloadScript = function () {
|
|
324
|
-
this.unloadScript();
|
|
325
|
-
return this.loadScript();
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* 卸载钩子方法
|
|
330
|
-
*/
|
|
331
|
-
Item.prototype.unload = async function () {
|
|
332
|
-
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* 卸载之后处理
|
|
337
|
-
* @param {boolean} remove 是否删除文件
|
|
338
|
-
*/
|
|
339
|
-
Item.prototype.unloadAfter = async function (remove) {
|
|
340
|
-
// 删除脚本
|
|
341
|
-
this.unloadScript();
|
|
342
|
-
if (remove) {
|
|
343
|
-
this.removeFile();
|
|
344
|
-
}
|
|
345
|
-
};
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* 获取脚本文件路径
|
|
349
|
-
* @param {string} file 文件路径
|
|
350
|
-
* @returns {string | null} 完整文件路径
|
|
351
|
-
*/
|
|
352
|
-
Item.prototype._getScriptFile = function () {
|
|
353
|
-
let main = this.config.main || '';
|
|
354
|
-
if (!main) return null;
|
|
355
|
-
|
|
356
|
-
let filename = main.fullname(this._getDir());
|
|
357
|
-
if (!filename.hasFile()) {
|
|
358
|
-
this.newScript(filename);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
return filename;
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* 加载脚本文件,支持热重载模式
|
|
366
|
-
* 在开发模式(mode=3或4)下使用 $.require 进行热重载
|
|
367
|
-
* 在生产模式下使用标准的 require 加载
|
|
368
|
-
* @returns {object | null} 加载的模块对象
|
|
369
|
-
*/
|
|
370
|
-
Item.prototype.loadScript = function () {
|
|
371
|
-
let file = this._getScriptFile();
|
|
372
|
-
if (!file) return null;
|
|
373
|
-
if (this.mode === 3 || this.mode === 4) {
|
|
374
|
-
// 开发模式:使用 $.require 进行热重载,绑定热更新回调
|
|
375
|
-
var cs = $.require(file, (mod) => {
|
|
376
|
-
this._setMainMethod(mod);
|
|
377
|
-
});
|
|
378
|
-
this._setMainMethod(cs);
|
|
379
|
-
return cs;
|
|
380
|
-
} else {
|
|
381
|
-
var cs = require(file);
|
|
382
|
-
this._setMainMethod(cs);
|
|
383
|
-
return cs;
|
|
384
|
-
}
|
|
385
|
-
};
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* 设置主方法
|
|
389
|
-
* @param {object} mod 模块对象
|
|
390
|
-
*/
|
|
391
|
-
Item.prototype._setMainMethod = function (mod) {
|
|
392
|
-
if (!mod) return;
|
|
393
|
-
let name = this.config.func_name || 'main';
|
|
394
|
-
if (name && mod[name]) {
|
|
395
|
-
this.main = mod[name];
|
|
396
|
-
}
|
|
397
|
-
if ($.push) {
|
|
398
|
-
$.push(this, mod, true);
|
|
399
|
-
}
|
|
400
|
-
else {
|
|
401
|
-
Object.assign(this, mod);
|
|
402
|
-
}
|
|
403
|
-
this.is_loaded = true;
|
|
404
|
-
};
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* 获取配置文件作用域
|
|
408
|
-
* @param {object} file 文件对象
|
|
409
|
-
* @returns {string} 配置文件作用域
|
|
410
|
-
*/
|
|
411
|
-
Item.prototype._getScope = function (file) {
|
|
412
|
-
return file.replace(/\\/g, '/').between('app/', '/');
|
|
413
|
-
};
|
|
414
|
-
|
|
415
|
-
/**
|
|
416
|
-
* 新建配置文件
|
|
417
|
-
* @param {string} file 目标文件路径
|
|
418
|
-
*/
|
|
419
|
-
Item.prototype.newConfig = function (file) {
|
|
420
|
-
if (!this.config.name) {
|
|
421
|
-
this.config.name = this._getName(file);
|
|
422
|
-
this.config.scope = this._getScope(file);
|
|
423
|
-
}
|
|
424
|
-
this._createConfigFile(file);
|
|
425
|
-
};
|
|
426
|
-
|
|
427
|
-
/**
|
|
428
|
-
* 创建配置文件
|
|
429
|
-
* @param {string} file 目标文件路径
|
|
430
|
-
* @returns {string} 配置文件内容
|
|
431
|
-
*/
|
|
432
|
-
Item.prototype._createConfigFile = function (file) {
|
|
433
|
-
var tpl = this.getConfigTpl();
|
|
434
|
-
var content = $.tpl.render(tpl, this.config);
|
|
435
|
-
file.saveText(content);
|
|
436
|
-
return file;
|
|
437
|
-
};
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
* 获取配置模板
|
|
441
|
-
* @param {string} tpl_dir 模板文件路径
|
|
442
|
-
* @returns {string} 配置模板内容
|
|
443
|
-
*/
|
|
444
|
-
Item.prototype.getConfigTpl = function (tpl_dir = '') {
|
|
445
|
-
var f = './config.tpl.json'.fullname(tpl_dir || this.constructor.base_dir);
|
|
446
|
-
if (f.hasFile()) {
|
|
447
|
-
return f.loadText();
|
|
448
|
-
} else {
|
|
449
|
-
return `{
|
|
450
|
-
// 模块名称,必填
|
|
451
|
-
"name": "\${name}",
|
|
452
|
-
// 模块标题,可选,默认"示例标题"
|
|
453
|
-
"title": "\${title || "示例标题"}",
|
|
454
|
-
// 模块描述,可选,默认"示例描述"
|
|
455
|
-
"description": "\${description || "示例描述"}",
|
|
456
|
-
// 主脚本文件路径,可选,默认"./index.js"
|
|
457
|
-
"main": "\${main || "./index.js"}",
|
|
458
|
-
// 模块作用域,可选,默认"server"
|
|
459
|
-
"scope": "\${scope || "server"}",
|
|
460
|
-
// 模块状态,可选,默认1
|
|
461
|
-
"state": \${state || 1},
|
|
462
|
-
// 模块排序,可选,默认100
|
|
463
|
-
"sort": \${sort || 100},
|
|
464
|
-
// 是否结束,可选,默认false
|
|
465
|
-
"end": \${end || false}
|
|
466
|
-
}`;
|
|
467
|
-
}
|
|
468
|
-
};
|
|
469
|
-
|
|
470
|
-
/**
|
|
471
|
-
* 加载配置文件
|
|
472
|
-
* @param {string} file 文件路径
|
|
473
|
-
* @param {string} name 配置项名称
|
|
474
|
-
* @returns {object | null} 配置对象
|
|
475
|
-
*/
|
|
476
|
-
Item.prototype.loadFile = function (file, name) {
|
|
477
|
-
try {
|
|
478
|
-
let filename = file.fullname(this._getDir());
|
|
479
|
-
let text = filename.loadText();
|
|
480
|
-
|
|
481
|
-
// 如果文件不存在,创建新的配置文件
|
|
482
|
-
if (!text) {
|
|
483
|
-
this.newConfig(filename);
|
|
484
|
-
text = filename.loadText();
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
if (!text) return null;
|
|
488
|
-
|
|
489
|
-
let config = this._loadHotReload(filename);
|
|
490
|
-
let final_config = this._findConfigByName(config, name);
|
|
491
|
-
return final_config;
|
|
492
|
-
} catch (err) {
|
|
493
|
-
this.log('error', `加载配置文件失败: `, err);
|
|
494
|
-
return null;
|
|
495
|
-
}
|
|
496
|
-
};
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* 根据模式加载配置(支持热更新)
|
|
500
|
-
* @param {string} file 完整文件路径
|
|
501
|
-
* @returns {object | Array | null} 配置对象
|
|
502
|
-
*/
|
|
503
|
-
Item.prototype._loadHotReload = function (file) {
|
|
504
|
-
if (this.mode === 2 || this.mode === 3 || this.mode === 4) {
|
|
505
|
-
return $.loadJson(file, this._handleHotReload.bind(this));
|
|
506
|
-
}
|
|
507
|
-
return file.loadJson();
|
|
508
|
-
};
|
|
509
|
-
|
|
510
|
-
/**
|
|
511
|
-
* 根据名称在配置数组中查找配置项
|
|
512
|
-
* @param {object | Array} config 配置对象或数组
|
|
513
|
-
* @param {string} name 配置项名称
|
|
514
|
-
* @returns {object | null} 匹配的配置项
|
|
515
|
-
*/
|
|
516
|
-
Item.prototype._findConfigByName = function (config, name) {
|
|
517
|
-
if (!name || !Array.isArray(config)) return config;
|
|
518
|
-
return config.find((item) => item.name === name) || null;
|
|
519
|
-
};
|
|
520
|
-
|
|
521
|
-
/**
|
|
522
|
-
* 根据模式决定是否重新加载脚本
|
|
523
|
-
*/
|
|
524
|
-
Item.prototype._reloadIfNeeded = function () {
|
|
525
|
-
if (this.mode === 3 || this.mode === 4) {
|
|
526
|
-
this.reloadScript();
|
|
527
|
-
}
|
|
528
|
-
};
|
|
529
|
-
|
|
530
|
-
/**
|
|
531
|
-
* 删除目录
|
|
532
|
-
*/
|
|
533
|
-
Item.prototype.delDir = function () {
|
|
534
|
-
let main = this.config.main;
|
|
535
|
-
if (main && $.dir && $.dir.del) {
|
|
536
|
-
$.dir.del(this.dir);
|
|
537
|
-
}
|
|
538
|
-
};
|
|
539
|
-
|
|
540
|
-
/**
|
|
541
|
-
* 删除配置和脚本文件
|
|
542
|
-
* @returns {string | null} 错误消息,如果没有错误则返回null
|
|
543
|
-
*/
|
|
544
|
-
Item.prototype.removeFile = function () {
|
|
545
|
-
let name = this.config.name;
|
|
546
|
-
let file = this.script_file;
|
|
547
|
-
|
|
548
|
-
let error_message = null;
|
|
549
|
-
try {
|
|
550
|
-
if (!file || !file.hasFile) return null;
|
|
551
|
-
|
|
552
|
-
if (!file.hasFile()) {
|
|
553
|
-
return '配置文件不存在';
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
error_message = this._removeConfigFile(file, name);
|
|
557
|
-
} catch (err) {
|
|
558
|
-
this.log('error', `删除文件失败: `, err);
|
|
559
|
-
error_message = `删除失败: ${err.message}`;
|
|
560
|
-
}
|
|
561
|
-
return error_message;
|
|
562
|
-
};
|
|
563
|
-
|
|
564
|
-
/**
|
|
565
|
-
* 删除配置文件
|
|
566
|
-
* @param {object} file 文件对象
|
|
567
|
-
* @param {string} name 配置名称
|
|
568
|
-
* @returns {string | null} 错误消息
|
|
569
|
-
*/
|
|
570
|
-
Item.prototype._removeConfigFile = function (file, name) {
|
|
571
|
-
let text = file.loadText();
|
|
572
|
-
if (!text) {
|
|
573
|
-
this.delDir();
|
|
574
|
-
return null;
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
let config = text.toJson();
|
|
578
|
-
if (Array.isArray(config)) {
|
|
579
|
-
return this._delArray(file, config, name);
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
this.delDir();
|
|
583
|
-
return null;
|
|
584
|
-
};
|
|
585
|
-
|
|
586
|
-
/**
|
|
587
|
-
* 从数组配置中删除指定项
|
|
588
|
-
* @param {object} file 文件对象
|
|
589
|
-
* @param {Array} config 配置数组
|
|
590
|
-
* @param {string} name 配置名称
|
|
591
|
-
* @returns {string | null} 错误消息
|
|
592
|
-
*/
|
|
593
|
-
Item.prototype._delArray = function (file, config, name) {
|
|
594
|
-
let index = config.findIndex((item) => item.name === name);
|
|
595
|
-
if (index === -1) return null;
|
|
596
|
-
|
|
597
|
-
this.delDir();
|
|
598
|
-
config.splice(index, 1);
|
|
599
|
-
|
|
600
|
-
if (config.length > 0) {
|
|
601
|
-
file.saveText(JSON.stringify(config, null, 4));
|
|
602
|
-
} else if (file.delFile) {
|
|
603
|
-
file.delFile();
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
return null;
|
|
607
|
-
};
|
|
608
|
-
|
|
609
|
-
/**
|
|
610
|
-
* 获取配置文件名称
|
|
611
|
-
* @param {object} file 文件对象
|
|
612
|
-
* @returns {string} 配置文件名称
|
|
613
|
-
*/
|
|
614
|
-
Item.prototype._getName = function (file) {
|
|
615
|
-
return file.dirname().basename();
|
|
616
|
-
};
|
|
617
|
-
|
|
618
|
-
/**
|
|
619
|
-
* 加载前处理
|
|
620
|
-
*/
|
|
621
|
-
Item.prototype.loadBefore = async function () {
|
|
622
|
-
try {
|
|
623
|
-
let module = this.loadScript();
|
|
624
|
-
if (module) {
|
|
625
|
-
this.is_loaded = true;
|
|
626
|
-
}
|
|
627
|
-
} catch (err) {
|
|
628
|
-
this.log('error', `加载前处理失败: `, err);
|
|
629
|
-
this.is_loaded = false;
|
|
630
|
-
}
|
|
631
|
-
};
|
|
632
|
-
|
|
633
|
-
/**
|
|
634
|
-
* 加载处理
|
|
635
|
-
*/
|
|
636
|
-
Item.prototype.load = async function () {
|
|
637
|
-
this.loadConfig();
|
|
638
|
-
this.loadScript();
|
|
639
|
-
};
|
|
640
|
-
|
|
641
|
-
/**
|
|
642
|
-
* 重载配置和脚本
|
|
643
|
-
*/
|
|
644
|
-
Item.prototype.reload = async function () {
|
|
645
|
-
await this.exec('unload');
|
|
646
|
-
await this.exec('load');
|
|
647
|
-
};
|
|
648
|
-
|
|
649
|
-
/**
|
|
650
|
-
* 保存配置
|
|
651
|
-
*/
|
|
652
|
-
Item.prototype.save = function () {
|
|
653
|
-
try {
|
|
654
|
-
if (!this.script_file) return;
|
|
655
|
-
|
|
656
|
-
let file = this.script_file.fullname(this._getDir());
|
|
657
|
-
let text = file.loadText();
|
|
658
|
-
|
|
659
|
-
if (text && text.trim().startsWith('[')) {
|
|
660
|
-
// 数组格式配置
|
|
661
|
-
let config = text.toJson();
|
|
662
|
-
if (Array.isArray(config)) {
|
|
663
|
-
// 查找并更新现有配置项
|
|
664
|
-
let index = config.findIndex((item) => item.name === this.config.name);
|
|
665
|
-
if (index !== -1) {
|
|
666
|
-
config[index] = this.config;
|
|
667
|
-
} else {
|
|
668
|
-
// 如果不存在,添加新配置项
|
|
669
|
-
config.push(this.config);
|
|
670
|
-
}
|
|
671
|
-
file.saveText(JSON.stringify(config, null, 4));
|
|
672
|
-
return;
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
// 单对象格式配置,直接保存
|
|
677
|
-
file.saveText(JSON.stringify(this.config, null, 4));
|
|
678
|
-
} catch (err) {
|
|
679
|
-
this.log('error', `保存配置失败: `, err);
|
|
680
|
-
}
|
|
681
|
-
};
|
|
682
|
-
|
|
683
|
-
/**
|
|
684
|
-
* 触发事件
|
|
685
|
-
* @param {string} event 事件名
|
|
686
|
-
* @param {...any} args 事件参数
|
|
687
|
-
*/
|
|
688
|
-
Item.prototype.emitEvent = function (event, ...args) {
|
|
689
|
-
this._eventer?.emit(event, ...args);
|
|
690
|
-
};
|
|
691
|
-
|
|
692
|
-
/**
|
|
693
|
-
* @module 导出Item类
|
|
694
|
-
*/
|
|
695
|
-
module.exports = {
|
|
696
|
-
Item
|
|
697
|
-
};
|