mm_machine 2.2.4 → 2.2.5

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.
Files changed (4) hide show
  1. package/README.md +7 -7
  2. package/index.js +501 -641
  3. package/item.js +697 -837
  4. package/package.json +11 -8
package/index.js CHANGED
@@ -1,641 +1,501 @@
1
- /**
2
- * @file 机制构建帮助类函数
3
- * @author <a href="http://qww.elins.cn">邱文武</a>
4
- * @version 1.6
5
- */
6
- const { Item } = require('./item.js');
7
-
8
- /**
9
- * @class Index索引类
10
- */
11
- class Index {
12
- /**
13
- * 构造函数
14
- * @param {object} scope 作用域
15
- * @param {string} dir_base 模块目录
16
- * @class
17
- */
18
- constructor(scope, dir_base) {
19
- // 作用域(同时作为检索的后缀名)
20
- this.scope = scope || ($.val && $.val.scope) ? $.val.scope + '' : '';
21
- // Index接口列表
22
- this.list = [];
23
-
24
- /**
25
- * 机制类型
26
- */
27
- this.type = '';
28
-
29
- /**
30
- * 排序项
31
- */
32
- this.sort_key = 'sort';
33
-
34
- /**
35
- * 模块目录
36
- */
37
- this.dir_base = dir_base;
38
-
39
- /**
40
- * 模式
41
- * 1.生产模式,改变文件不会重新加载
42
- * 2.热更新模式,改变配置文件会重新加载配置,不重新加载脚本
43
- * 3.热重载模式,改变配置文件都会加载配置和脚本
44
- * 4.重载模式,执行完后重新加载脚本,避免变量污染
45
- * 5.热更新+重载模式,改变配置文件重新加载配置和脚本,执行完后重新加载脚本
46
- */
47
- this.mode = 1;
48
-
49
- /**
50
- * 日志输出
51
- */
52
- this._logger = $.log || console;
53
- }
54
- }
55
-
56
- /**
57
- * 日志输出
58
- * @param {string} level - 日志级别(debug/info/warn/error)
59
- * @param {string} message - 日志消息
60
- * @param {...*} args - 可选参数
61
- */
62
- Index.prototype.log = function (level, message, ...args) {
63
- this._logger[level](`[${this.constructor.name}.${this.type}] ${message}`, ...args);
64
- };
65
-
66
- /**
67
- * 清除接口缓存
68
- */
69
- Index.prototype.clear = function () {
70
- this.list = [];
71
- };
72
-
73
- /**
74
- * 默认驱动
75
- */
76
- Index.prototype.Drive = Item;
77
-
78
- /**
79
- * 私有方法:执行模块方法
80
- * @param {object} module 模块对象
81
- * @param {string} method 方法名称
82
- * @param {Array} params 参数数组
83
- * @returns {Promise<any>} 执行结果
84
- * @private
85
- */
86
- Index.prototype._exec = async function (module, method, params = []) {
87
- if (!module || !method) return null;
88
-
89
- try {
90
- // 确保模块已加载
91
- if (!module.complete) {
92
- await module.exec('load');
93
- }
94
-
95
- // 执行方法
96
- let ret = await module.exec(method, ...params);
97
-
98
- // 根据模式决定是否重载
99
- if (this.mode >= 4) {
100
- module.exec('reload');
101
- }
102
-
103
- return ret;
104
- } catch (err) {
105
- $.log.error(`[${this.type}] 执行模块方法失败: `, err);
106
- return null;
107
- }
108
- };
109
-
110
- /**
111
- * 加载项
112
- * @param {string} dir 文件路径
113
- * @param {object} cg 配置参数
114
- * @param {string} file 配置文件
115
- * @returns {Promise<object | null>} 加载的驱动或配置对象
116
- */
117
- Index.prototype.loadDrive = async function (dir, cg, file) {
118
- if (!dir || !file) {
119
- $.log.error(`[${this.type}] load: 缺少必要参数`);
120
- return null;
121
- }
122
-
123
- try {
124
- if (this.Drive) {
125
- const drive = new this.Drive(dir, this.dir_base.fullname());
126
- drive.mode = this.mode;
127
- if (cg) {
128
- await drive.exec('loadConfig', file, cg.name);
129
- await drive.exec('setConfig', cg);
130
- } else {
131
- await drive.exec('loadConfig', file);
132
- }
133
- this.list.push(drive);
134
- return drive;
135
- } else {
136
- let json = file.loadJson();
137
- if (!json) {
138
- let fl = './config.tpl.json'.fullname(this.dir_base);
139
- if (fl.hasFile()) {
140
- fl.copyFile(file);
141
- json = file.loadJson();
142
- }
143
- }
144
- if (json) {
145
- this.list.push(json);
146
- }
147
- return json;
148
- }
149
- } catch (err) {
150
- $.log.error(`[${this.type}] 加载项失败: `, err);
151
- return null;
152
- }
153
- };
154
-
155
- /**
156
- * 加载列表
157
- * @param {Array} list 文件列表
158
- * @returns {Promise<void>}
159
- */
160
- Index.prototype.loads = async function (list) {
161
- // 遍历文件路径
162
- if (!Array.isArray(list)) {
163
- $.log.error(`[${this.type}] loads: 列表参数必须是数组`);
164
- return;
165
- }
166
-
167
- // 使用函数式编程,按顺序加载文件
168
- await list.reduce(async (prev_promise, file_item) => {
169
- await prev_promise;
170
- return this.loadFile(file_item, true);
171
- }, Promise.resolve());
172
- };
173
-
174
- /**
175
- * 排序
176
- */
177
- Index.prototype.sort = function () {
178
- this.list.sort((o1, o2) => {
179
- let p1 = o1.config?.[this.sort_key] || 0;
180
- let p2 = o2.config?.[this.sort_key] || 0;
181
- return p2 - p1;
182
- });
183
- };
184
-
185
- /**
186
- * 更新前
187
- * @param {string} dir_path 目录路径
188
- */
189
- Index.prototype.updateBefore = async function (dir_path) {
190
- // $.log.debug("更新前")
191
- };
192
-
193
- /**
194
- * 更新后
195
- * @param {string} dir_path 目录路径
196
- */
197
- Index.prototype.updateAfter = async function (dir_path) {
198
- // $.log.debug("更新后")
199
- };
200
-
201
- /**
202
- * 规范化检索路径
203
- * @param {string} search_path 检索路径
204
- * @returns {string} 规范化后的路径
205
- */
206
- Index.prototype._searchPath = function (search_path) {
207
- if (!search_path) {
208
- return './app/';
209
- }
210
- // 直接使用传入的路径,不强制添加app/
211
- return search_path.fullname();
212
- };
213
-
214
- /**
215
- * 获取目录列表
216
- * @param {string} norm_path 规范化路径
217
- * @returns {Array} 目录列表
218
- */
219
- Index.prototype._getDirList = function (norm_path) {
220
- try {
221
- // 使用精准模式总是获取所有目录
222
- // 这样可以确保找到test1和test2目录
223
- return $.dir.getAll(norm_path);
224
- } catch (err) {
225
- $.log.error(`[${this.type}] 检索目录失败!`, err);
226
- return [];
227
- }
228
- };
229
-
230
- /**
231
- * 处理单个目录的配置文件
232
- * @param {string} dir 目录路径
233
- * @returns {Promise<void>}
234
- */
235
- Index.prototype._runDirConfig = async function (dir) {
236
- // 直接检查并加载demo.json文件
237
- let config_file = `./${this.type}.json`.fullname(dir);
238
- if (config_file && config_file.hasFile && config_file.hasFile()) {
239
- await this.loadFile(config_file, true);
240
- }
241
-
242
- // 同时也检查config_demo.json文件
243
- let config_file2 = `./config_${this.type}.json`.fullname(dir);
244
- if (config_file2 && config_file2.hasFile && config_file2.hasFile()) {
245
- await this.loadFile(config_file2, true);
246
- }
247
- };
248
-
249
- /**
250
- * 更新所有配置
251
- * @param {string} search_path 检索路径
252
- * @param {boolean} accurate 精准路径,默认为false
253
- * @returns {Promise<void>}
254
- */
255
- Index.prototype.updateConfigAll = async function (search_path, accurate) {
256
- try {
257
- // 规范化路径
258
- let norm_path = this._searchPath(search_path);
259
-
260
- // 获取目录列表
261
- let list_scope = this._getDirList(norm_path);
262
-
263
- // 使用函数式编程处理目录
264
- await list_scope.reduce(async (prev_promise, dir) => {
265
- await prev_promise;
266
- return this._runDirConfig(dir);
267
- }, Promise.resolve());
268
- } catch (err) {
269
- $.log.error(`[${this.type}] 更新所有配置失败: `, err);
270
- }
271
- };
272
-
273
- /**
274
- * 更新已有配置文件
275
- * @param {string} dir_path 目录路径
276
- * @returns {Promise<void>}
277
- */
278
- Index.prototype.updateConfigHave = async function (dir_path) {
279
- let list = this.list;
280
- await list.reduce(async (prev_promise, o) => {
281
- await prev_promise;
282
- return this._updateSingleConfig(o);
283
- }, Promise.resolve());
284
- };
285
-
286
- /**
287
- * 更新单个配置项
288
- * @param {object} o 配置对象
289
- */
290
- Index.prototype._updateSingleConfig = async function (o) {
291
- let file = o.filename;
292
- if (!file) return;
293
-
294
- try {
295
- let config = file.loadJson();
296
- if (!config) return;
297
-
298
- let target_config = this._findConfig(config, o.config.name);
299
- if (target_config) {
300
- await o.exec('setConfig', target_config);
301
- }
302
- } catch (err) {
303
- $.log.error(`[${this.type}] 更新配置失败: `, err);
304
- }
305
- };
306
-
307
- /**
308
- * 查找配置项
309
- * @param {object | Array} config 配置对象
310
- * @param {string} name 配置名称
311
- * @returns {object | null} 目标配置
312
- */
313
- Index.prototype._findConfig = function (config, name) {
314
- if (Array.isArray(config)) {
315
- return config.find((cg) => cg.name === name) || null;
316
- }
317
- return config;
318
- };
319
-
320
- /**
321
- * 更新配置
322
- * @param {object} dir - 检索目录
323
- * @param {boolean} accurate - 精准路径,默认为false
324
- * @param {boolean} clear - 是否清除现有配置,默认为false
325
- * @returns {Promise<void>}
326
- */
327
- Index.prototype.updateConfig = async function (dir, accurate = false, clear = false) {
328
- try {
329
- if (clear) {
330
- this.clear();
331
- await this.updateConfigAll(dir, accurate);
332
- } else {
333
- // 如果没有指定目录,则更新已有的配置文件
334
- await this.updateConfigHave();
335
- }
336
- this.sort();
337
- } catch (err) {
338
- $.log.error(`[${this.type}] 配置更新失败: `, err);
339
- }
340
- };
341
-
342
- /**
343
- * 更新JS
344
- * @returns {Promise<void>}
345
- */
346
- Index.prototype.updateScript = async function () {
347
- let list = this.list;
348
- await list.reduce(async (prev_promise, o) => {
349
- await prev_promise;
350
- if (o.config?.state === 1) {
351
- return o.exec('loadScript');
352
- }
353
- }, Promise.resolve());
354
- };
355
-
356
- /**
357
- * 更新
358
- * @param {string} dir 检索的路径
359
- * @param {boolean} accurate 是否精准路径,默认为false
360
- * @param {boolean} loadJS 是否加载JS,默认为true
361
- * @param {boolean} clear 是否清除现有配置,默认为true
362
- * @returns {Promise<void>}
363
- */
364
- Index.prototype.updateMain = async function (dir, accurate = false, loadJS = true, clear = true) {
365
- await this.updateConfig(dir, accurate, clear);
366
- if (loadJS) {
367
- await this.updateScript();
368
- }
369
- };
370
-
371
- /**
372
- * 更新配置
373
- * @param {string} dir 检索的路径
374
- * @param {boolean} accurate 精准路径
375
- * @param {boolean} loadJS 是否加载JS
376
- * @param {boolean} clear 是否清除缓存
377
- */
378
- Index.prototype.update = async function (dir, accurate = false, loadJS = true, clear = true) {
379
- await this.updateBefore(dir);
380
- await this.updateMain(dir, accurate, loadJS, clear);
381
- await this.updateAfter(dir);
382
- };
383
-
384
- /**
385
- * 查询配置项
386
- * @param {string} name 名称
387
- * @returns {object | null} 返回单项配置
388
- */
389
- Index.prototype.get = function (name) {
390
- if (!name) return null;
391
- return this.list.find((item) => item.config?.name === name) || null;
392
- };
393
-
394
- /**
395
- * 设置配置项
396
- * @param {string} name 配置项名称
397
- * @param {object} cg 配置对象
398
- * @returns {boolean} 是否设置成功
399
- */
400
- Index.prototype.set = function (name, cg) {
401
- if (!name || !cg) return false;
402
-
403
- let item = this.get(name);
404
- if (item) {
405
- // 使用Object.assign合并属性
406
- Object.assign(item.config, cg);
407
- return true;
408
- }
409
- return false;
410
- };
411
-
412
- /**
413
- * 保存
414
- * @returns {boolean} 是否保存成功
415
- */
416
- Index.prototype.save = async function () {
417
- let list = this.list;
418
- await list.reduce(async (prev_promise, o) => {
419
- await prev_promise;
420
- if (o.config?.state === 1) {
421
- return o.exec('save');
422
- }
423
- }, Promise.resolve());
424
- };
425
-
426
- /**
427
- * 添加插件
428
- * @param {object} config 配置对象
429
- * @returns {Promise<object | null>} 新添加的插件对象
430
- */
431
- Index.prototype.add = async function (config) {
432
- if (!config || !config.name) {
433
- $.log.error(`[${this.type}] 添加插件失败: 缺少必要的配置信息`);
434
- return null;
435
- }
436
-
437
- try {
438
- // 检查是否已存在
439
- let existing = this.get(config.name);
440
- if (existing) {
441
- $.log.warn(`插件 ${config.name} 已存在`);
442
- return existing;
443
- }
444
-
445
- const item = new Item(this, config);
446
- this.list.push(item);
447
- this.sort();
448
- return item;
449
- } catch (err) {
450
- $.log.error(`[${this.type}] 添加插件失败: `, err);
451
- return null;
452
- }
453
- };
454
-
455
- /**
456
- * 删除插件
457
- * @param {string} name 插件名称
458
- * @returns {Promise<boolean>} 是否删除成功
459
- */
460
- Index.prototype.del = async function (name) {
461
- if (!name) return false;
462
-
463
- let index = this.list.findIndex((item) => item.config?.name === name);
464
- if (index === -1) return false;
465
-
466
- try {
467
- let item = this.list[index];
468
- await item.exec('unload');
469
- this.list.splice(index, 1);
470
- return true;
471
- } catch (err) {
472
- $.log.error(`[${this.type}] 删除插件失败: `, err);
473
- return false;
474
- }
475
- };
476
-
477
- /**
478
- * 加载插件
479
- * @param {string} name 插件名称
480
- * @returns {Promise<object | null>} 加载的插件对象
481
- */
482
- Index.prototype.load = async function (name) {
483
- if (!name) return null;
484
-
485
- let item = this.get(name);
486
- if (!item) return null;
487
-
488
- try {
489
- if (item.config?.state === 1) {
490
- await item.exec('load');
491
- }
492
- return item;
493
- } catch (err) {
494
- $.log.error(`[${this.type}] 加载插件 ${name} 失败: `, err);
495
- return null;
496
- }
497
- };
498
-
499
- /**
500
- * 卸载插件
501
- * @param {string} name 插件名称
502
- * @returns {Promise<boolean>} 是否卸载成功
503
- */
504
- Index.prototype.unload = async function (name) {
505
- if (!name) return false;
506
-
507
- let item = this.get(name);
508
- if (!item) return false;
509
-
510
- try {
511
- await item.exec('unload');
512
- return true;
513
- } catch (err) {
514
- $.log.error(`[${this.type}] 卸载插件 ${name} 失败: `, err);
515
- return false;
516
- }
517
- };
518
-
519
- /**
520
- * 重新加载插件
521
- * @param {string} name 插件名称
522
- * @returns {Promise<object | null>} 重新加载的插件对象
523
- */
524
- Index.prototype.reload = async function (name) {
525
- if (!name) return null;
526
-
527
- let item = this.get(name);
528
- if (!item) return null;
529
-
530
- try {
531
- await item.exec('reload');
532
- return item;
533
- } catch (err) {
534
- $.log.error(`[${this.type}] 重新加载插件 ${name} 失败: `, err);
535
- return null;
536
- }
537
- };
538
-
539
- /**
540
- * 通过文件加载配置
541
- * @param {string} file 文件名
542
- * @param {boolean} create 不存在则进行创建
543
- * @returns {Promise<object | null | string>} 加载的驱动对象、null或错误信息
544
- */
545
- Index.prototype.loadFile = async function (file, create = false) {
546
- try {
547
- let dir = file.dirname();
548
- // 载入文件
549
- let obj = file.loadJson();
550
- if (obj) {
551
- if (Array.isArray(obj)) {
552
- // 使用函数式编程处理数组
553
- await obj.reduce(async (prev_promise, o) => {
554
- await prev_promise;
555
- // 实例化一个驱动
556
- return this.loadDrive(dir, o, file);
557
- }, Promise.resolve());
558
- } else {
559
- return await this.loadDrive(dir, null, file);
560
- }
561
- } else if (create) {
562
- return await this.loadDrive(dir, null, file);
563
- } else {
564
- return `${file}文件不存在`;
565
- }
566
- return null;
567
- } catch (err) {
568
- $.log.error(`[${this.type}] 加载文件失败: `, err);
569
- return `加载文件失败: ${err.message}`;
570
- }
571
- };
572
-
573
- /**
574
- * 调用函数
575
- * @param {string} name 模块名
576
- * @param {string} method 函数名
577
- * @param {object} params 参数集合
578
- * @returns {Promise<any>} 执行结果
579
- */
580
- Index.prototype.run = async function (name, method, ...params) {
581
- if (name) {
582
- let module = await this.get(name);
583
- if (module && module.config?.state === 1) {
584
- return await this._exec(module, method, params);
585
- }
586
- return null;
587
- } else if (name === null) {
588
- let result = null;
589
- // 修复:使用for循环替代some,正确处理异步迭代
590
- for (let module of this.list) {
591
- if (module.config?.state === 1) {
592
- result = await this._exec(module, method, params);
593
- // 如果结果不为空且有结束标志,则停止迭代
594
- if (result && module.config?.end) {
595
- break;
596
- }
597
- }
598
- }
599
- return result;
600
- }
601
- return null;
602
- };
603
-
604
- /**
605
- * 执行方法
606
- * @param {string} name 插件名称
607
- * @param {string} method 方法名称
608
- * @param {...any} params 方法参数
609
- * @returns {Promise<any>} 执行结果
610
- */
611
- Index.prototype.exec = async function (name, method, ...params) {
612
- if (name) {
613
- let module = await this.get(name);
614
- if (module) {
615
- return await this._exec(module, method, params);
616
- }
617
- return null;
618
- } else if (name === null) {
619
- let result = null;
620
- // 使用函数式编程处理列表,使用reduce模拟break逻辑
621
- await this.list.reduce(async (prev_promise, module) => {
622
- await prev_promise;
623
- // 如果已经得到结果且有结束标志,则跳过后续处理
624
- if (result && module.config?.end) {
625
- return;
626
- }
627
- let current = await this._exec(module, method, params);
628
- if (current) {
629
- result = current;
630
- }
631
- }, Promise.resolve());
632
- return result;
633
- }
634
- return null;
635
- };
636
-
637
- /**
638
- * @module 导出Index类
639
- */
640
- exports.Index = Index;
641
- exports.Item = Item;
1
+ const { Drive } = require('./drive');
2
+ const { Item } = require('./item.js');
3
+
4
+ /**
5
+ * 管理器类
6
+ */
7
+ class Manager extends Drive {
8
+ static config = {
9
+ // 管理器名称
10
+ name: 'manager',
11
+ // 管理器描述
12
+ description: '管理模块',
13
+ // 基础目录,加载模块内置资源
14
+ base_dir: '../common/manager'.fullname(__dirname),
15
+ // 自定义目录,加载项目自定义资源
16
+ dir: './ai/manager'.fullname(),
17
+ // 文件拓展名
18
+ filename: 'manager.json',
19
+ // 懒加载
20
+ lazy_load: true,
21
+ // 作用域(同时作为检索的后缀名)
22
+ scope: ($.val && $.val.scope) ? $.val.scope + '' : 'server',
23
+ // 排序项
24
+ sort_key: 'sort',
25
+ // 模式 script脚本 | json配置 | drive驱动
26
+ type: 'drive',
27
+ // 模式 1.生产模式 2.热更新模式 3.热重载模式 4.热更新+重载模式 5.重载模式
28
+ mode: 3
29
+ };
30
+
31
+ /**
32
+ * 构造函数
33
+ * @param {object} config 配置项
34
+ * @param {object} parent 父项对象
35
+ */
36
+ constructor(config, parent) {
37
+ super({
38
+ ...Manager.config,
39
+ ...config
40
+ }, parent);
41
+
42
+ // 模块信息列表 { name: '', sort: 0, available: true, enabled: true }
43
+ this.infos = [];
44
+ // 模块
45
+ this.mods = {};
46
+ }
47
+ }
48
+
49
+ /**
50
+ * 创建模块状态模型
51
+ * @param {string} name 模块名
52
+ * @param {number} sort 排序值
53
+ * @param {boolean} state 状态
54
+ * @returns {object} 模块状态模型
55
+ */
56
+ Manager.prototype.newInfo = function (name, sort, state) {
57
+ return {
58
+ name,
59
+ sort,
60
+ available: state == true,
61
+ enabled: true
62
+ };
63
+ };
64
+
65
+ /**
66
+ * 获取基础目录
67
+ * @returns {string} 基础目录
68
+ */
69
+ Manager.prototype.getBaseDir = function () {
70
+ return this.config.base_dir;
71
+ };
72
+
73
+ /**
74
+ * 默认驱动
75
+ */
76
+ Manager.prototype.Drive = Item;
77
+
78
+ /**
79
+ * 更新模块信息
80
+ */
81
+ Manager.prototype.updateInfo = function () {
82
+ this.infos = [];
83
+ for (let name in this.mods) {
84
+ let o = this.mods[name];
85
+ let info = this.newInfo(name, o.config.sort, o.config.state);
86
+ this.infos.push(info);
87
+ }
88
+ this.sort();
89
+ };
90
+
91
+ /**
92
+ * 排序
93
+ */
94
+ Manager.prototype.sort = function () {
95
+ var sort_key = this.config.sort_key || 'sort';
96
+ this.infos.sort((o1, o2) => {
97
+ let p1 = o1[sort_key] || 0;
98
+ let p2 = o2[sort_key] || 0;
99
+ return p1 - p2;
100
+ });
101
+ };
102
+
103
+ // ==== 模块管理接口 ====
104
+ /**
105
+ * 删除模块
106
+ * @param {string} name 模块名
107
+ * @returns {object|null} 删除的模块对象
108
+ */
109
+ Manager.prototype.delMod = function (name) {
110
+ let mod = this.mods[name];
111
+ if (mod) {
112
+ delete this.mods[name];
113
+ }
114
+ return mod;
115
+ };
116
+
117
+ /**
118
+ * 设置模块
119
+ * @param {string} name 模块名
120
+ * @param {object} mod 模块对象
121
+ * @returns {object|null} 设置的模块对象
122
+ */
123
+ Manager.prototype.setMod = function (name, mod) {
124
+ this.mods[name] = mod;
125
+ return this.getMod(name);
126
+ };
127
+
128
+ /**
129
+ * 获取模块
130
+ * @param {string} name 模块名
131
+ * @returns {object|null} 模块对象,若模块则返回模块对象,否则返回null
132
+ */
133
+ Manager.prototype.getMod = function (name) {
134
+ return this.mods[name];
135
+ };
136
+
137
+ /**
138
+ * 获取所有模块
139
+ * @returns {object[]} 模块对象数组
140
+ */
141
+ Manager.prototype.getMods = function () {
142
+ return this.mods;
143
+ };
144
+
145
+ /**
146
+ * 创建模块
147
+ * @param {string} config_file 配置文件路径
148
+ * @param {object} config 配置项
149
+ * @param {object} script 模块对象
150
+ * @returns {object} 模块对象
151
+ */
152
+ Manager.prototype.newMod = function (config_file, config, script) {
153
+ let mod;
154
+ switch (this.config.type) {
155
+ case 'script':
156
+ mod = new Item(config, this);
157
+ break;
158
+ default:
159
+ // 创建模块
160
+ mod = new this.Drive(config, this);
161
+ break;
162
+ }
163
+ mod.mode = this.config.mode;
164
+ mod.loadConfig(config_file);
165
+ mod.setMethods(script);
166
+ mod.setConfig(config);
167
+ return mod;
168
+ };
169
+
170
+ /**
171
+ * 注册模块
172
+ * @param {string} config_file 配置文件路径
173
+ * @param {object} config 配置项
174
+ * @param {object} script 模块对象
175
+ * @returns {object} 配置项
176
+ */
177
+ Manager.prototype.register = function (config_file, config = {}, script = {}) {
178
+ let mod = this.newMod(config_file, config, script);
179
+ this.setMod(mod.config.name, mod);
180
+ return mod;
181
+ };
182
+
183
+ /**
184
+ * 加载模块
185
+ * @param {string} name 模块名
186
+ * @returns {Promise<any>} 加载结果
187
+ */
188
+ Manager.prototype.load = async function (name) {
189
+ let mod = this.getMod(name);
190
+ if (mod) {
191
+ return await mod.exec('load');
192
+ }
193
+ return null;
194
+ };
195
+
196
+ /**
197
+ * 卸载模块
198
+ * @param {string} name 模块名
199
+ * @returns {Promise<any>} 卸载结果
200
+ */
201
+ Manager.prototype.unload = async function (name) {
202
+ let mod = this.getMod(name);
203
+ if (mod) {
204
+ return await mod.exec('unload');
205
+ }
206
+ return null;
207
+ };
208
+
209
+ /**
210
+ * 重载模块
211
+ * @param {string} name 模块名
212
+ * @returns {Promise<any>} 重载结果
213
+ */
214
+ Manager.prototype.reload = async function (name) {
215
+ let mod = this.getMod(name);
216
+ if (mod) {
217
+ return await mod.exec('reload');
218
+ }
219
+ return null;
220
+ };
221
+
222
+ /**
223
+ * 注销模块
224
+ * @param {string} name 模块名
225
+ * @returns {Promise<any>} 注销结果
226
+ */
227
+ Manager.prototype.unregister = function (name) {
228
+ // 卸载模块
229
+ this.unload(name);
230
+ // 删除模块
231
+ this.delMod(name);
232
+ return mod;
233
+ };
234
+
235
+ /**
236
+ * 批量注册模块
237
+ * @param {string[]} files 配置文件路径数组
238
+ * @param {object} config 配置项
239
+ * @param {object} script 模块对象
240
+ */
241
+ Manager.prototype.batchRegister = function (files, config = {}, script = {}) {
242
+ for (let file of files) {
243
+ this.register(file, config, script);
244
+ }
245
+ };
246
+
247
+ /**
248
+ * 加载所有模块
249
+ */
250
+ Manager.prototype.loads = async function () {
251
+ var promises = [];
252
+ for (let name in this.mods) {
253
+ let mod = this.mods[name];
254
+ promises.push(mod.exec('load'));
255
+ }
256
+ await Promise.all(promises);
257
+ };
258
+
259
+ /**
260
+ * 检索目录下所有文件
261
+ * @private
262
+ * @param {string} dir 目录路径
263
+ * @returns {Array} 文件路径数组
264
+ */
265
+ Manager.prototype._findFiles = function (dir) {
266
+ // 检查目录是否存在
267
+ if (!dir) {
268
+ this.log('error', '目录不能为空');
269
+ return [];
270
+ }
271
+ // 检查目录是否存在
272
+ if (!dir.hasDir()) {
273
+ this.log('warn', '目录不存在', dir);
274
+ return [];
275
+ }
276
+ // 检索目录下所有文件
277
+ return $.file.getAll(dir, this.config.filename);
278
+ };
279
+
280
+ /**
281
+ * 加载所有模块的脚本
282
+ */
283
+ Manager.prototype.loadScripts = async function () {
284
+ var promises = [];
285
+ for (let name in this.mods) {
286
+ let mod = this.mods[name];
287
+ promises.push(mod.exec('loadScript'));
288
+ }
289
+ await Promise.all(promises);
290
+ };
291
+
292
+ /**
293
+ * 更新配置前的钩子函数
294
+ */
295
+ Manager.prototype.updateBefore = function () {
296
+ this.log('info', '更新配置前的钩子函数');
297
+ };
298
+
299
+ /**
300
+ * 更新配置前的钩子函数
301
+ */
302
+ Manager.prototype.updateAfter = function () {
303
+ this.log('info', '更新配置后钩子函数');
304
+ };
305
+
306
+ /**
307
+ * 更新配置
308
+ * @param {string} dir 检索的路径
309
+ * @param {boolean} clear 是否清除缓存
310
+ */
311
+ Manager.prototype.update = async function (dir, clear = true) {
312
+ if (clear) {
313
+ // 初始化方法
314
+ this.mods = {};
315
+ }
316
+
317
+ // 查找所有json文件
318
+ let files = this._findFiles(dir);
319
+ // 批量注册模块
320
+ this.batchRegister(files);
321
+ // 更新配置信息
322
+ this.updateInfo();
323
+ if (!this.config.lazy_load) {
324
+ // 批量加载脚本
325
+ await this.loadScripts();
326
+ }
327
+ };
328
+
329
+ // ==== 高性能调用接口 ====
330
+ Manager.prototype.run = async function (name, method, ...params) {
331
+ return await this.main(name, method, ...params);
332
+ };
333
+
334
+ /**
335
+ * 调用模块的方法(高性能版本)
336
+ * @param {string} name 模块名
337
+ * @param {string} method 方法名
338
+ * @param {...any} params 参数集合
339
+ * @returns {Promise<any>} 执行结果
340
+ */
341
+ Manager.prototype.main = async function (name, method, ...params) {
342
+ var result = null;
343
+ if (name) {
344
+ let mod = this.getMod(name);
345
+ if (mod && mod.config?.state === 1) {
346
+ result = await this._runSub(mod, method, ...params);
347
+ }
348
+ } else if (name === null) {
349
+ result = await this._runAllEnabled(method, ...params);
350
+ }
351
+ return result;
352
+ };
353
+
354
+ /**
355
+ * 私有方法:执行所有模块方法
356
+ * @param {string} method 方法名称
357
+ * @param {...any} params 方法参数集合
358
+ * @returns {Promise<any>} 执行结果
359
+ * @private
360
+ */
361
+ Manager.prototype._runAllEnabled = async function (method, ...params) {
362
+ var result;
363
+ for (let i = 0; i < this.infos.length; i++) {
364
+ let config = this.infos[i];
365
+ let mod = this.getMod(config.name);
366
+ if (mod && mod.config?.state === 1) {
367
+ var ret = await this._runSub(mod, method, ...params);
368
+ if (ret !== null && ret !== undefined) {
369
+ result = ret;
370
+ // 如果结果不为空且有结束标志,则停止迭代
371
+ if (mod.config?.end) {
372
+ break;
373
+ }
374
+ }
375
+ }
376
+ }
377
+ return result;
378
+ };
379
+
380
+ /**
381
+ * 执行方法
382
+ * @param {string} name 模块名称
383
+ * @param {string} method 方法名称
384
+ * @param {...any} params 方法参数集合
385
+ * @returns {Promise<any>} 执行结果
386
+ */
387
+ Manager.prototype.runAsync = async function (name, method, ...params) {
388
+ // 使用mods的顺序(按配置顺序调用)
389
+ var result = null;
390
+ if (name) {
391
+ let mod = await this.getMod(name);
392
+ if (mod) {
393
+ result = await this._runSub(mod, method, ...params);
394
+ }
395
+ } else if (name === null) {
396
+ result = await this._runAll(method, ...params);
397
+ }
398
+ return result;
399
+ };
400
+
401
+ /**
402
+ * 私有方法:执行所有模块方法
403
+ * @param {string} method 方法名称
404
+ * @param {...any} params 方法参数集合
405
+ * @returns {Promise<any>} 执行结果
406
+ * @private
407
+ */
408
+ Manager.prototype._runAll = async function (method, ...params) {
409
+ var result = null;
410
+ for (let i = 0; i < this.infos.length; i++) {
411
+ let config = this.infos[i];
412
+ let mod = this.getMod(config.name);
413
+ if (mod) {
414
+ var ret = await this._runSub(mod, method, ...params);
415
+ if (ret !== null && ret !== undefined) {
416
+ result = ret;
417
+ }
418
+ }
419
+ }
420
+ return result;
421
+ };
422
+
423
+ /**
424
+ * 私有方法:执行模块方法
425
+ * @param {object} mod 模块对象
426
+ * @param {string} method 方法名称
427
+ * @param {...any} params 参数集合
428
+ * @returns {Promise<any>} 执行结果
429
+ * @private
430
+ */
431
+ Manager.prototype._runSub = async function (mod, method, ...params) {
432
+ if (!mod || !method) return null;
433
+
434
+ try {
435
+ // 确保模块已加载
436
+ if (!mod.isLoaded()) {
437
+ await mod.exec('loadScript');
438
+ }
439
+
440
+ // 执行方法
441
+ let ret = await mod.exec(method, ...params);
442
+ // 根据模式决定是否重载
443
+ if (this.mode >= 4) {
444
+ mod.exec('reload');
445
+ }
446
+
447
+ return ret;
448
+ } catch (err) {
449
+ $.log.error(`[${this.type}] 执行模块方法失败: `, err);
450
+ return null;
451
+ }
452
+ };
453
+
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
+ /**
465
+ * 初始化管理器
466
+ */
467
+ Manager.prototype._initManager = function () {
468
+
469
+ };
470
+
471
+ /**
472
+ * 加载资源
473
+ */
474
+ Manager.prototype._loadSources = function () {
475
+ };
476
+
477
+ /**
478
+ * 初始化资源
479
+ */
480
+ Manager.prototype._initSources = function () {
481
+ };
482
+
483
+ /**
484
+ * 初始化公共属性
485
+ */
486
+ Manager.prototype._initCore = function () {
487
+ // 初始化管理器
488
+ this._initManager();
489
+ // 加载资源
490
+ this._loadSources();
491
+ // 初始化AI客户端
492
+ this._initSources();
493
+ };
494
+
495
+ module.exports = {
496
+ Manager,
497
+ Item,
498
+ Drive,
499
+ // 向后兼容
500
+ Index: Manager
501
+ };