mm_machine 2.7.7 → 2.7.9

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 (3) hide show
  1. package/drive.js +716 -705
  2. package/index.js +1006 -1000
  3. package/package.json +4 -4
package/index.js CHANGED
@@ -1,1000 +1,1006 @@
1
- const { Mod } = require('./mod');
2
- const { Drive } = require('./drive.js');
3
-
4
- /**
5
- * 管理器类
6
- */
7
- class Manager extends Mod {
8
- /**
9
- * 配置项
10
- * @type {object}
11
- */
12
- static config = {
13
- /**
14
- * 管理器名称
15
- * @type {string}
16
- */
17
- name: 'manager',
18
- /**
19
- * 管理器标题
20
- * @type {string}
21
- */
22
- title: '管理器',
23
- /**
24
- * 管理器描述
25
- * @type {string}
26
- */
27
- description: '用于管理驱动',
28
- /**
29
- * 检索文件名
30
- * @type {string}
31
- */
32
- filename: 'manager.json',
33
- /**
34
- * 模板目录
35
- * @type {string}
36
- */
37
- tpl_dir: __dirname,
38
- /**
39
- * 基础目录,加载模块内置资源
40
- * @type {string}
41
- */
42
- base_dir: '', // '../common/manager'.fullname(__dirname),
43
- /**
44
- * 自定义目录,加载项目自定义资源
45
- * @type {string}
46
- */
47
- dir: '', // './ai/manager'.fullname(),
48
- /**
49
- * 搜索模式 dir按目录搜索 | file按文件名搜索
50
- * @type {string}
51
- */
52
- search_way: 'file',
53
- /**
54
- * 类型 script脚本 | json配置 | drive驱动
55
- * @type {string}
56
- */
57
- mod_type: 'drive',
58
- /**
59
- * 是否懒加载
60
- * @type {boolean}
61
- */
62
- lazy_load: true,
63
- /**
64
- * 模式
65
- * 1.生产模式,改变文件不会重新加载
66
- * 2.热更新模式,改变配置文件会重新加载配置,不重新加载脚本
67
- * 3.热重载模式,改变配置文件都会加载配置和脚本
68
- * 4.热更新+重载模式,改变配置文件重新加载配置和脚本,执行完后重新加载脚本
69
- * 5.重载模式,执行完后重新加载脚本,避免变量污染
70
- * @type {number}
71
- */
72
- mode: 3,
73
- /**
74
- * 排序项
75
- * @type {string}
76
- */
77
- sort_key: 'sort',
78
- /**
79
- * 作用域
80
- * @type {string}
81
- */
82
- scope: ($.val && $.val.scope) ? $.val.scope + '' : 'server'
83
- };
84
-
85
- /**
86
- * 构造函数
87
- * @param {object} config 配置项
88
- * @param {object} parent 父项对象
89
- * @param {object} mods 模块对象列表
90
- * @param {object} Drive 驱动对象
91
- */
92
- constructor(config, parent, mods = {}, Drive) {
93
- super({
94
- ...Manager.config,
95
- ...config
96
- }, parent);
97
-
98
- // 模块信息列表 { name: '', sort: 0, available: true, enabled: true }
99
- this.infos = [];
100
- // 模块
101
- this.mods = mods;
102
- if (Drive) {
103
- this.Drive = Drive;
104
- }
105
- }
106
-
107
- get list() {
108
- return this.getList();
109
- }
110
- }
111
-
112
- /**
113
- * 获取事件触发器
114
- * @returns {object} 事件触发器
115
- */
116
- Manager.prototype.getEventer = function () {
117
- return $.eventer;
118
- };
119
-
120
- /**
121
- * 获取所有模块信息
122
- * @returns {object[]} 模块信息数组
123
- */
124
- Manager.prototype.getInfos = function () {
125
- return this.infos;
126
- };
127
-
128
- /**
129
- * 创建模块状态模型
130
- * @param {string} name 模块名
131
- * @param {number} sort 排序值
132
- * @param {boolean} state 状态
133
- * @param {string} file 文件名
134
- * @returns {object} 模块状态模型
135
- */
136
- Manager.prototype.newInfo = function (name, sort, state, file = '') {
137
- return {
138
- name,
139
- sort,
140
- state,
141
- enabled: true,
142
- file: file || '',
143
- get available() {
144
- return this.state == true && this.enabled;
145
- }
146
- };
147
- };
148
-
149
- /**
150
- * 设置模块信息
151
- * @param {object} info 模块信息
152
- */
153
- Manager.prototype.setInfo = function (info) {
154
- let has = false;
155
- for (let i = 0; i < this.infos.length; i++) {
156
- let o = this.infos[i];
157
- if (o.name == info.name) {
158
- this.infos[i] = info;
159
- has = true;
160
- break;
161
- }
162
- }
163
- if (!has) {
164
- this.infos.push(info);
165
- }
166
- };
167
-
168
- /**
169
- * 获取所有模块对象
170
- * @returns {object[]} 模块对象数组
171
- */
172
- Manager.prototype.getList = function () {
173
- let list = [];
174
- for (let i = 0; i < this.infos.length; i++) {
175
- let info = this.infos[i];
176
- let mod = this.getMod(info.name);
177
- if (mod) {
178
- mod.config.state = info.state;
179
- }
180
- list.push(mod);
181
- }
182
- return list;
183
- };
184
-
185
- /**
186
- * 获取基础目录
187
- * @returns {string} 基础目录
188
- */
189
- Manager.prototype.getBaseDir = function () {
190
- return this.config.base_dir || __dirname;
191
- };
192
-
193
- /**
194
- * 获取模板目录
195
- * @returns {string} 模板目录
196
- */
197
- Manager.prototype.getTplDir = function () {
198
- return this.config.tpl_dir || __dirname;
199
- };
200
-
201
- /**
202
- * 默认驱动
203
- */
204
- Manager.prototype.Drive = Drive;
205
-
206
- /**
207
- * 更新模块信息
208
- */
209
- Manager.prototype.updateInfo = function () {
210
- this.infos = [];
211
- let mods = this.getMods();
212
- for (let name in mods) {
213
- let o = mods[name];
214
- let info = this.newInfo(name, o.config.sort, o.config.state, o.config_file);
215
- this.infos.push(info);
216
- }
217
- this.sort();
218
- };
219
-
220
- /**
221
- * 排序
222
- */
223
- Manager.prototype._sort = function () {
224
- var sort_key = this.config.sort_key || 'sort';
225
- this.infos.sort((o1, o2) => {
226
- let p1 = o1[sort_key] || 100;
227
- let p2 = o2[sort_key] || 100;
228
- return p1 - p2;
229
- });
230
- };
231
-
232
- /**
233
- * 排序
234
- */
235
- Manager.prototype.sort = function () {
236
- this._sort();
237
- };
238
-
239
- // ==== 模块管理接口 ====
240
- /**
241
- * 清除所有模块
242
- */
243
- Manager.prototype.clearMods = function () {
244
- for (let name in this.mods) {
245
- delete this.mods[name];
246
- }
247
- };
248
-
249
- /**
250
- * 删除模块
251
- * @param {string} name 模块名
252
- * @returns {object|null} 删除的模块对象
253
- */
254
- Manager.prototype.delMod = function (name) {
255
- let mod = this.mods[name];
256
- if (mod) {
257
- delete this.mods[name];
258
- }
259
- return mod;
260
- };
261
-
262
- /**
263
- * 设置模块
264
- * @param {string} name 模块名
265
- * @param {object} mod 模块对象
266
- * @returns {object|null} 设置的模块对象
267
- */
268
- Manager.prototype.setMod = function (name, mod) {
269
- this.mods[name] = mod;
270
- return this.getMod(name);
271
- };
272
-
273
- /**
274
- * 获取模块
275
- * @param {string} name 模块名
276
- * @returns {object|null} 模块对象,若模块则返回模块对象,否则返回null
277
- */
278
- Manager.prototype.getMod = function (name) {
279
- return this.mods[name];
280
- };
281
-
282
- /**
283
- * 获取所有模块
284
- * @returns {object[]} 模块对象数组
285
- */
286
- Manager.prototype.getMods = function () {
287
- return this.mods;
288
- };
289
-
290
- /**
291
- * 创建模块
292
- * @param {string} config_file 配置文件路径
293
- * @param {object} config 配置项
294
- * @param {object} script 模块对象
295
- * @returns {object} 模块对象
296
- */
297
- Manager.prototype.newMod = function (config_file, config, script) {
298
- let mod;
299
- switch (this.config.mod_type) {
300
- case 'script':
301
- mod = new Mod(config, this);
302
- break;
303
- default:
304
- // 创建模块
305
- mod = new this.Drive(config, this);
306
- break;
307
- }
308
- mod.mode = this.config.mode;
309
- mod.loadConfig(config_file);
310
- if (script) {
311
- for (let key in script) {
312
- let obj = script[key];
313
- if (typeof obj == 'function') {
314
- mod.setMethod(key, obj);
315
- }
316
- else {
317
- mod.setData(key, obj);
318
- }
319
- }
320
- }
321
- if (config) {
322
- mod.setConfig(config);
323
- }
324
- return mod;
325
- };
326
-
327
- /**
328
- * 注册模块
329
- * @param {string} config_file 配置文件路径
330
- * @param {object} config 配置项
331
- * @param {object} script 模块对象
332
- * @returns {object} 模块对象
333
- */
334
- Manager.prototype.registerMod = function (config_file, config = {}, script = {}) {
335
- let mod = this.newMod(config_file, config, script);
336
- this.setMod(mod.config.name, mod);
337
- return mod;
338
- };
339
-
340
- /**
341
- * 加载模块
342
- * @param {string} name 模块名
343
- * @returns {Promise<any>} 加载结果
344
- */
345
- Manager.prototype.loadMod = async function (name) {
346
- let mod = this.getMod(name);
347
- if (mod) {
348
- return await mod.do('load');
349
- }
350
- return null;
351
- };
352
-
353
- /**
354
- * 卸载模块
355
- * @param {string} name 模块名
356
- * @returns {Promise<any>} 卸载结果
357
- */
358
- Manager.prototype.unloadMod = async function (name) {
359
- let mod = this.getMod(name);
360
- if (mod) {
361
- return await mod.do('unload');
362
- }
363
- return null;
364
- };
365
-
366
- /**
367
- * 重载模块
368
- * @param {string} name 模块名
369
- * @returns {Promise<any>} 重载结果
370
- */
371
- Manager.prototype.reloadMod = async function (name) {
372
- let mod = this.getMod(name);
373
- if (mod) {
374
- return await mod.do('reload');
375
- }
376
- return null;
377
- };
378
-
379
- /**
380
- * 注销模块
381
- * @param {string} name 模块名
382
- * @returns {Promise<any>} 注销结果
383
- */
384
- Manager.prototype.unregisterMod = function (name) {
385
- // 卸载模块
386
- this.unloadMod(name);
387
- // 删除模块
388
- let mod = this.delMod(name);
389
- return mod;
390
- };
391
-
392
- /**
393
- * 批量注册模块
394
- * @param {string[]} files 配置文件路径数组
395
- * @param {object} config 配置项
396
- * @param {object} script 模块对象
397
- */
398
- Manager.prototype.registerMods = function (files, config = {}, script = {}) {
399
- for (let file of files) {
400
- this.registerMod(file, config, script);
401
- }
402
- };
403
-
404
- /**
405
- * 加载所有模块
406
- */
407
- Manager.prototype.loadMods = async function () {
408
- var promises = [];
409
- let mods = this.getMods();
410
- for (let name in mods) {
411
- let mod = mods[name];
412
- promises.push(mod.do('load'));
413
- }
414
- await Promise.all(promises);
415
- };
416
-
417
- /**
418
- * 获取目录名
419
- * @returns {string} 目录名
420
- */
421
- Manager.prototype.getDirName = function () {
422
- // 前缀,为当前类名
423
- let prefix = this.constructor.name.toLowerCase();
424
- // 后缀,为配置项名称
425
- let name = this.config.name.toLowerCase();
426
- // 目录名,为前缀加下划线加后缀
427
- return prefix + '_' + name;
428
- };
429
-
430
- /**
431
- * 获取所有目录下的文件
432
- * @param {string} dir 目录路径
433
- * @returns {Array} 文件路径数组
434
- */
435
- Manager.prototype._getAllDirFiles = async function (dir) {
436
- let files = [];
437
- let dirs = await $.dir.getAllAsync(dir, this.getDirName());
438
- for (let i = 0; i < dirs.length; i++) {
439
- let d = dirs[i];
440
- let lt = await $.file.getAllAsync(d, this.config.filename);
441
- if (lt.length > 0) {
442
- files.push(...lt);
443
- }
444
- }
445
- return files;
446
- };
447
-
448
- /**
449
- * 检索目录下所有文件
450
- * @private
451
- * @param {string} dir 目录路径
452
- * @returns {Array} 文件路径数组
453
- */
454
- Manager.prototype._findFiles = async function (dir) {
455
- // 检查目录是否存在
456
- if (!dir) {
457
- this.log('error', '目录不能为空');
458
- return [];
459
- }
460
- // 检查目录是否存在
461
- if (!dir.hasDir()) {
462
- return [];
463
- }
464
- if (this.config.search_way === 'dir') {
465
- return await this._getAllDirFiles(dir);
466
- }
467
- // 检索目录下所有文件
468
- return await $.file.getAllAsync(dir, this.config.filename);
469
- };
470
-
471
- /**
472
- * 加载所有模块的脚本
473
- */
474
- Manager.prototype.loadScripts = async function () {
475
- var promises = [];
476
- let mods = this.getMods();
477
- for (let name in mods) {
478
- let mod = mods[name];
479
- promises.push(mod.call('loadScript'));
480
- }
481
- await Promise.all(promises);
482
- };
483
-
484
- /**
485
- * 更新配置前的钩子函数
486
- */
487
- Manager.prototype.updateBefore = function () {
488
- // this.log('info', '更新配置前的钩子函数');
489
- };
490
-
491
- /**
492
- * 更新配置前的钩子函数
493
- */
494
- Manager.prototype.updateAfter = function () {
495
- // this.log('info', '更新配置后钩子函数');
496
- };
497
-
498
- /**
499
- * 更新配置
500
- * @param {string} dir 检索的路径
501
- * @param {boolean} clear 是否清除缓存
502
- */
503
- Manager.prototype.update = async function (dir, clear = true) {
504
- if (clear) {
505
- this.clearMods();
506
- }
507
-
508
- // 查找所有json文件
509
- let files = await this._findFiles(dir || this.config.dir);
510
- // 批量注册模块
511
- this.registerMods(files);
512
- // 更新配置信息
513
- this.updateInfo();
514
- if (!this.config.lazy_load) {
515
- // 批量加载脚本
516
- await this.loadScripts();
517
- }
518
- this.is_loaded = true;
519
- };
520
-
521
- // ==== 高性能调用接口 ====
522
- /**
523
- * 调用模块的方法(高性能版本)
524
- * @param {string} name 模块名
525
- * @param {string} method 方法名
526
- * @param {...any} params 参数集合
527
- * @returns {Promise<any>} 执行结果
528
- */
529
- Manager.prototype.main = async function (name, method, ...params) {
530
- var result = null;
531
- if (name) {
532
- let mod = this.getMod(name);
533
- if (mod && mod.config?.state === 1) {
534
- result = await this._runMod(mod, method, ...params);
535
- }
536
- } else if (name === null) {
537
- result = await this._runAllEnabled(method, ...params);
538
- }
539
- return result;
540
- };
541
-
542
- /**
543
- * 私有方法:执行所有模块方法
544
- * @param {string} method 方法名称
545
- * @param {...any} params 方法参数集合
546
- * @returns {Promise<any>} 执行结果
547
- * @private
548
- */
549
- Manager.prototype._runAllEnabled = async function (method, ...params) {
550
- var result;
551
- for (let i = 0; i < this.infos.length; i++) {
552
- let config = this.infos[i];
553
- let mod = this.getMod(config.name);
554
- if (mod && mod.config?.state === 1) {
555
- var ret = null;
556
- try {
557
- ret = await this._runMod(mod, method, ...params);
558
- } catch (err) {
559
- $.log.error(`执行模块方法失败: `, err);
560
- }
561
- if (ret !== null && ret !== undefined) {
562
- result = ret;
563
- // 如果结果不为空且有结束标志,则停止迭代
564
- if (mod.config?.end) {
565
- break;
566
- }
567
- }
568
- }
569
- }
570
- return result;
571
- };
572
-
573
- /**
574
- * 私有方法:执行模块方法
575
- * @param {object} mod 模块对象
576
- * @param {string} method 方法名称
577
- * @param {...any} params 参数集合
578
- * @returns {Promise<any>} 执行结果
579
- * @private
580
- */
581
- Manager.prototype._runMod = async function (mod, method, ...params) {
582
- if (!mod || !method) return null;
583
-
584
- // 确保模块已加载
585
- if (!mod.isLoaded()) {
586
- try {
587
- await mod.call('loadScript');
588
- }
589
- catch (err) {
590
- $.log.error(`加载模块脚本失败: `, err);
591
- }
592
- }
593
-
594
- // 执行方法
595
- let ret = await mod.call(method, ...params);
596
- // 根据模式决定是否重载
597
- if (this.mode >= 4) {
598
- mod.do('reload');
599
- }
600
-
601
- return ret;
602
- };
603
-
604
- /**
605
- * 初始化管理器
606
- */
607
- Manager.prototype._initManager = function () {
608
-
609
- };
610
-
611
- /**
612
- * 获取公共模块目录
613
- * @returns {string} 公共模块目录
614
- */
615
- Manager.prototype.getBaseDir = function () {
616
- return this.config.base_dir;
617
- };
618
-
619
- /**
620
- * 获取二次开发模块目录
621
- * @returns {string} 二次开发模块目录
622
- */
623
- Manager.prototype.getDir = function () {
624
- return this.config.dir || this.getDir();
625
- };
626
-
627
- /**
628
- * 加载资源
629
- */
630
- Manager.prototype._loadSources = async function () {
631
- // 通过更新函数加载资源信息
632
- let base_dir = this.getBaseDir();
633
- let dir = this.getDir();
634
- if (base_dir) {
635
- await this.call('update', base_dir);
636
- await this.call('update', dir, false);
637
- }
638
- else {
639
- await this.call('update', dir);
640
- }
641
- };
642
-
643
- /**
644
- * 初始化资源
645
- */
646
- Manager.prototype._initSources = async function () {
647
- // 通过
648
- };
649
-
650
- /**
651
- * 初始化公共属性
652
- */
653
- Manager.prototype._initCore = async function () {
654
- // 初始化管理器
655
- this._initManager();
656
- // 加载资源
657
- await this._loadSources();
658
- // 初始化AI客户端
659
- await this._initSources();
660
- };
661
-
662
- /**
663
- * 执行方法 - 内部方法
664
- * @param {string} mod 模块对象
665
- * @param {string} method 方法名称
666
- * @param {...any} params 参数列表
667
- * @returns {any} 返回执行结果
668
- */
669
- Manager.prototype._exec = async function (mod, method, ...params) {
670
- if (mod[method]) {
671
- return await mod[method](...params);
672
- }
673
- else {
674
- throw new Error(`方法${method}不存在`);
675
- }
676
- };
677
-
678
- /**
679
- * 执行方法
680
- * @param {string} name 模块名
681
- * @param {string} method 方法名称
682
- * @param {...any} params 参数列表
683
- * @returns {any} 返回执行结果
684
- */
685
- Manager.prototype.exec = async function (name, method, ...params) {
686
- let ret;
687
- try {
688
- let mod = this.getMod(name);
689
- if (!mod) {
690
- throw new Error(`模块${name}不存在`);
691
- }
692
- ret = await this._exec(mod, method, ...params);
693
- }
694
- catch (error) {
695
- this.log('error', `${method}方法执行失败!`, error);
696
- }
697
- return ret;
698
- };
699
-
700
- /**
701
- * 确保所有模块都已加载
702
- * @returns {Promise} 加载完成
703
- */
704
- Manager.prototype._ensureAllLoaded = async function () {
705
- let infos = this.getInfos();
706
-
707
- for (let i = 0; i < infos.length; i++) {
708
- let info = infos[i];
709
- let mod = this.getMod(info.name);
710
-
711
- if (!mod.isLoaded()) {
712
- try {
713
- await mod.call('loadScript');
714
- } catch (error) {
715
- this.log('error', `模块${info.name}加载失败`, error);
716
- continue; // 跳过加载失败的模块
717
- }
718
- }
719
- }
720
- };
721
-
722
- /**
723
- * 异步触发事件,按顺序执行等待完成
724
- * @param {string} method 方法名称
725
- * @param {...any} params 事件参数
726
- * @returns {Promise} 事件触发结果
727
- */
728
- Manager.prototype.runWait = async function (method, ...params) {
729
- // 参数校验
730
- if (typeof method !== 'string') {
731
- throw new TypeError('方法名称必须是字符串');
732
- }
733
-
734
- let result;
735
- let infos = this.getInfos();
736
-
737
- for (let i = 0; i < infos.length; i++) {
738
- let info = infos[i];
739
- let mod = this.getMod(info.name);
740
- if (!mod) {
741
- continue; // 跳过不存在的模块
742
- }
743
- // 确保模块已加载
744
- if (!mod.isLoaded()) {
745
- try {
746
- await mod.call('loadScript');
747
- } catch (error) {
748
- this.log('error', `模块${info.name}加载失败`, error);
749
- continue; // 跳过加载失败的模块
750
- }
751
- }
752
-
753
- // 执行方法
754
- try {
755
- let ret = await mod.do(method, ...params);
756
- if (ret !== null && ret !== undefined) {
757
- result = ret;
758
- }
759
- } catch (error) {
760
- this.log('error', `模块${info.name}执行${method}方法失败`, error);
761
- }
762
- }
763
-
764
- return result;
765
- };
766
-
767
- /**
768
- * 异步触发事件,并发执行不等待
769
- * @param {string} method 方法名称
770
- * @param {...any} params 事件参数
771
- * @returns {boolean} 是否成功触发事件
772
- */
773
- Manager.prototype.runAsync = async function (method, ...params) {
774
- // 参数校验
775
- if (typeof method !== 'string') {
776
- throw new TypeError('方法名称必须是字符串');
777
- }
778
-
779
- // 确保所有模块都已加载
780
- await this._ensureAllLoaded();
781
-
782
- let infos = this.getInfos();
783
-
784
- // 并发执行所有方法,不等待结果
785
- for (let i = 0; i < infos.length; i++) {
786
- let info = infos[i];
787
- let mod = this.getMod(info.name);
788
- try {
789
- mod.do(method, ...params);
790
- } catch (error) {
791
- this.log('error', `模块${info.name}执行${method}方法失败`, error);
792
- }
793
- }
794
-
795
- return true;
796
- };
797
-
798
- /**
799
- * 异步触发事件,并发执行等待完成
800
- * @param {string} method 方法名称
801
- * @param {...any} params 事件参数
802
- * @returns {Promise} 事件触发结果
803
- */
804
- Manager.prototype.runAll = async function (method, ...params) {
805
- // 参数校验
806
- if (typeof method !== 'string') {
807
- throw new TypeError('方法名称必须是字符串');
808
- }
809
-
810
- // 确保所有模块都已加载
811
- await this._ensureAllLoaded();
812
-
813
- const promises = [];
814
- let infos = this.getInfos();
815
-
816
- // 并发执行所有方法
817
- for (let i = 0; i < infos.length; i++) {
818
- let info = infos[i];
819
- let mod = this.getMod(info.name);
820
- promises.push(
821
- mod.do(method, ...params).catch(error => {
822
- this.log('error', `模块${info.name}执行${method}方法失败`, error);
823
- return null; // 失败时返回null
824
- })
825
- );
826
- }
827
-
828
- return await Promise.all(promises);
829
- };
830
-
831
- /**
832
- * 异步触发事件,竞争执行
833
- * @param {string} method 方法名称
834
- * @param {...any} params 事件参数
835
- * @returns {Promise} 第一个完成的结果
836
- */
837
- Manager.prototype.runRace = async function (method, ...params) {
838
- // 参数校验
839
- if (typeof method !== 'string') {
840
- throw new TypeError('方法名称必须是字符串');
841
- }
842
-
843
- // 确保所有模块都已加载
844
- await this._ensureAllLoaded();
845
-
846
- const promises = [];
847
- let infos = this.getInfos();
848
-
849
- // 竞争执行所有方法
850
- for (let i = 0; i < infos.length; i++) {
851
- let info = infos[i];
852
- let mod = this.getMod(info.name);
853
- promises.push(
854
- mod.do(method, ...params).catch(error => {
855
- this.log('error', `模块${info.name}执行${method}方法失败`, error);
856
- throw error; // 竞争执行中,失败应该抛出错误
857
- })
858
- );
859
- }
860
-
861
- return await Promise.race(promises);
862
- };
863
-
864
- /**
865
- * 异步触发事件,瀑布流执行
866
- * @param {string} method 方法名称
867
- * @param {*} result 初始值
868
- * @param {...any} params 事件参数
869
- * @returns {Promise} 最后一个事件监听者的结果
870
- */
871
- Manager.prototype.runWaterfall = async function (method, result, ...params) {
872
- // 参数校验
873
- if (typeof method !== 'string') {
874
- throw new TypeError('方法名称必须是字符串');
875
- }
876
-
877
- let infos = this.getInfos();
878
-
879
- for (let i = 0; i < infos.length; i++) {
880
- let info = infos[i];
881
- let mod = this.getMod(info.name);
882
-
883
- // 确保模块已加载
884
- if (!mod.isLoaded()) {
885
- try {
886
- await mod.call('loadScript');
887
- } catch (error) {
888
- this.log('error', `模块${info.name}加载失败`, error);
889
- continue; // 跳过加载失败的模块
890
- }
891
- }
892
-
893
- // 执行方法,将前一个结果作为参数传递给下一个
894
- try {
895
- let ret = await mod.do(method, result, ...params);
896
- if (ret !== null && ret !== undefined) {
897
- result = ret;
898
- }
899
- } catch (error) {
900
- this.log('error', `模块${info.name}执行${method}方法失败`, error);
901
- }
902
- }
903
-
904
- return result;
905
- };
906
-
907
- /**
908
- * 异步触发事件,子模块执行
909
- * @param {string} name 子模块名称
910
- * @param {string} method 方法名称
911
- * @param {...any} params 事件参数
912
- * @returns {Promise} 事件触发结果
913
- */
914
- Manager.prototype.runSubMod = async function (name, method, ...params) {
915
- // 参数校验
916
- if (typeof method !== 'string') {
917
- throw new TypeError('方法名称必须是字符串');
918
- }
919
- let mod = this.getMod(name);
920
- if (!mod) {
921
- throw new Error(`模块${name}不存在`);
922
- }
923
- return await mod.do(method, ...params);
924
- };
925
-
926
- /**
927
- * 移除事件监听
928
- * @param {string} event 事件名
929
- */
930
- Manager.prototype.offEvent = function (event) {
931
- this.getEventer()?.off(event);
932
- };
933
-
934
- /**
935
- * 创建模块
936
- * @param {object} config 模块配置
937
- * @param {string} file 模块文件路径
938
- * @returns {string} 创建的模块文件路径
939
- */
940
- Manager.prototype.createFile = function (config, file) {
941
- if (!config.name) {
942
- throw new TypeError('模块名称不能为空');
943
- }
944
- if (!config.title) {
945
- throw new TypeError('模块标题不能为空');
946
- }
947
- if (!config.description) {
948
- throw new TypeError('模块描述不能为空');
949
- }
950
- if (this.getMod(config.name)) {
951
- throw new Error(`创建失败,原因:模块${config.name}已存在`);
952
- }
953
- let mod = new this.Drive(config, this);
954
- let f = file;
955
- if (!f) {
956
- f = `${config.name}/${this.config.filename}`;
957
- if (this.config.search_way === 'dir') {
958
- let dir_name = this.getDirName();
959
- f = `${dir_name}/${f}`;
960
- }
961
- }
962
- f = f.fullname(this.config.dir);
963
- mod.createConfigFile(f, config);
964
- return f;
965
- };
966
-
967
- /**
968
- * 创建模块
969
- * @param {object} config 模块配置
970
- * @param {string} file 模块文件路径
971
- * @returns {object} 创建的模块实例
972
- */
973
- Manager.prototype.create = function (config, file = '') {
974
- let f = this.createFile(config, file);
975
- let mod = this.registerMod(f, config);
976
- return mod;
977
- };
978
-
979
- /**
980
- * 删除模块
981
- * @param {string} name 模块名称
982
- * @returns {object} 删除的模块实例
983
- */
984
- Manager.prototype.remove = async function (name) {
985
- let mod = this.getMod(name);
986
- if (mod) {
987
- await mod.remove();
988
- }
989
- this.unregisterMod(name);
990
- return mod;
991
- };
992
-
993
- module.exports = {
994
- Manager,
995
- Drive,
996
- Mod,
997
- // 向后兼容
998
- Index: Manager,
999
- Item: Drive
1000
- };
1
+ const { Mod } = require('./mod');
2
+ const { Drive } = require('./drive.js');
3
+
4
+ /**
5
+ * 管理器类
6
+ */
7
+ class Manager extends Mod {
8
+ /**
9
+ * 配置项
10
+ * @type {object}
11
+ */
12
+ static config = {
13
+ /**
14
+ * 管理器名称
15
+ * @type {string}
16
+ */
17
+ name: 'manager',
18
+ /**
19
+ * 管理器标题
20
+ * @type {string}
21
+ */
22
+ title: '管理器',
23
+ /**
24
+ * 管理器描述
25
+ * @type {string}
26
+ */
27
+ description: '用于管理驱动',
28
+ /**
29
+ * 检索文件名
30
+ * @type {string}
31
+ */
32
+ filename: 'manager.json',
33
+ /**
34
+ * 模板目录
35
+ * @type {string}
36
+ */
37
+ tpl_dir: __dirname,
38
+ /**
39
+ * 基础目录,加载模块内置资源
40
+ * @type {string}
41
+ */
42
+ base_dir: '', // '../common/manager'.fullname(__dirname),
43
+ /**
44
+ * 自定义目录,加载项目自定义资源
45
+ * @type {string}
46
+ */
47
+ dir: '', // './ai/manager'.fullname(),
48
+ /**
49
+ * 搜索模式 dir按目录搜索 | file按文件名搜索
50
+ * @type {string}
51
+ */
52
+ search_way: 'file',
53
+ /**
54
+ * 类型 script脚本 | json配置 | drive驱动
55
+ * @type {string}
56
+ */
57
+ mod_type: 'drive',
58
+ /**
59
+ * 是否懒加载
60
+ * @type {boolean}
61
+ */
62
+ lazy_load: true,
63
+ /**
64
+ * 模式
65
+ * 1.生产模式,改变文件不会重新加载
66
+ * 2.热更新模式,改变配置文件会重新加载配置,不重新加载脚本
67
+ * 3.热重载模式,改变配置文件都会加载配置和脚本
68
+ * 4.热更新+重载模式,改变配置文件重新加载配置和脚本,执行完后重新加载脚本
69
+ * 5.重载模式,执行完后重新加载脚本,避免变量污染
70
+ * @type {number}
71
+ */
72
+ mode: 3,
73
+ /**
74
+ * 排序项
75
+ * @type {string}
76
+ */
77
+ sort_key: 'sort',
78
+ /**
79
+ * 作用域
80
+ * @type {string}
81
+ */
82
+ scope: $.val && $.val.scope ? $.val.scope + '' : 'server'
83
+ };
84
+
85
+ /**
86
+ * 构造函数
87
+ * @param {object} config 配置项
88
+ * @param {object} parent 父项对象
89
+ * @param {object} mods 模块对象列表
90
+ * @param {object} Drive 驱动对象
91
+ */
92
+ constructor(config, parent, mods = {}, Drive) {
93
+ super(
94
+ {
95
+ ...Manager.config,
96
+ ...config
97
+ },
98
+ parent
99
+ );
100
+
101
+ // 模块信息列表 { name: '', sort: 0, available: true, enabled: true }
102
+ this.infos = [];
103
+ // 模块
104
+ this.mods = mods;
105
+ // getList 缓存
106
+ this._list_cache = null;
107
+ if (Drive) {
108
+ this.Drive = Drive;
109
+ }
110
+ }
111
+
112
+ get list() {
113
+ return this.getList();
114
+ }
115
+ }
116
+
117
+ /**
118
+ * 获取事件触发器
119
+ * @returns {object} 事件触发器
120
+ */
121
+ Manager.prototype.getEventer = function () {
122
+ return $.eventer;
123
+ };
124
+
125
+ /**
126
+ * 获取所有模块信息
127
+ * @returns {object[]} 模块信息数组
128
+ */
129
+ Manager.prototype.getInfos = function () {
130
+ return this.infos;
131
+ };
132
+
133
+ /**
134
+ * 创建模块状态模型
135
+ * @param {string} name 模块名
136
+ * @param {number} sort 排序值
137
+ * @param {boolean} state 状态
138
+ * @param {string} file 文件名
139
+ * @returns {object} 模块状态模型
140
+ */
141
+ Manager.prototype.newInfo = function (name, sort, state, file = '') {
142
+ return {
143
+ name,
144
+ sort,
145
+ state,
146
+ enabled: true,
147
+ file: file || '',
148
+ get available() {
149
+ return this.state == true && this.enabled;
150
+ }
151
+ };
152
+ };
153
+
154
+ /**
155
+ * 设置模块信息
156
+ * @param {object} info 模块信息
157
+ */
158
+ Manager.prototype.setInfo = function (info) {
159
+ this._list_cache = null;
160
+ let has = false;
161
+ for (let i = 0; i < this.infos.length; i++) {
162
+ let o = this.infos[i];
163
+ if (o.name == info.name) {
164
+ this.infos[i] = info;
165
+ has = true;
166
+ break;
167
+ }
168
+ }
169
+ if (!has) {
170
+ this.infos.push(info);
171
+ }
172
+ };
173
+
174
+ /**
175
+ * 获取所有模块对象
176
+ * @returns {object[]} 模块对象数组
177
+ */
178
+ Manager.prototype.getList = function () {
179
+ if (this._list_cache) return this._list_cache;
180
+ var list = [];
181
+ for (var i = 0; i < this.infos.length; i++) {
182
+ var info = this.infos[i];
183
+ var mod = this.getMod(info.name);
184
+ if (mod) {
185
+ mod.config.state = info.state;
186
+ }
187
+ list.push(mod);
188
+ }
189
+ this._list_cache = list;
190
+ return list;
191
+ };
192
+
193
+ /**
194
+ * 获取基础目录
195
+ * @returns {string} 基础目录
196
+ */
197
+ Manager.prototype.getBaseDir = function () {
198
+ return this.config.base_dir || __dirname;
199
+ };
200
+
201
+ /**
202
+ * 获取模板目录
203
+ * @returns {string} 模板目录
204
+ */
205
+ Manager.prototype.getTplDir = function () {
206
+ return this.config.tpl_dir || __dirname;
207
+ };
208
+
209
+ /**
210
+ * 默认驱动
211
+ */
212
+ Manager.prototype.Drive = Drive;
213
+
214
+ /**
215
+ * 更新模块信息
216
+ */
217
+ Manager.prototype.updateInfo = function () {
218
+ this._list_cache = null;
219
+ this.infos = [];
220
+ let mods = this.getMods();
221
+ for (let name in mods) {
222
+ let o = mods[name];
223
+ let info = this.newInfo(name, o.config.sort, o.config.state, o.config_file);
224
+ this.infos.push(info);
225
+ }
226
+ this.sort();
227
+ };
228
+
229
+ /**
230
+ * 排序
231
+ */
232
+ Manager.prototype._sort = function () {
233
+ var sort_key = this.config.sort_key || 'sort';
234
+ this.infos.sort((o1, o2) => {
235
+ let p1 = o1[sort_key] || 100;
236
+ let p2 = o2[sort_key] || 100;
237
+ return p1 - p2;
238
+ });
239
+ };
240
+
241
+ /**
242
+ * 排序
243
+ */
244
+ Manager.prototype.sort = function () {
245
+ this._list_cache = null;
246
+ this._sort();
247
+ };
248
+
249
+ // ==== 模块管理接口 ====
250
+ /**
251
+ * 清除所有模块
252
+ */
253
+ Manager.prototype.clearMods = function () {
254
+ this._list_cache = null;
255
+ for (let name in this.mods) {
256
+ delete this.mods[name];
257
+ }
258
+ };
259
+
260
+ /**
261
+ * 删除模块
262
+ * @param {string} name 模块名
263
+ * @returns {object|null} 删除的模块对象
264
+ */
265
+ Manager.prototype.delMod = function (name) {
266
+ this._list_cache = null;
267
+ let mod = this.mods[name];
268
+ if (mod) {
269
+ delete this.mods[name];
270
+ }
271
+ return mod;
272
+ };
273
+
274
+ /**
275
+ * 设置模块
276
+ * @param {string} name 模块名
277
+ * @param {object} mod 模块对象
278
+ * @returns {object|null} 设置的模块对象
279
+ */
280
+ Manager.prototype.setMod = function (name, mod) {
281
+ this._list_cache = null;
282
+ this.mods[name] = mod;
283
+ return this.getMod(name);
284
+ };
285
+
286
+ /**
287
+ * 获取模块
288
+ * @param {string} name 模块名
289
+ * @returns {object|null} 模块对象,若模块则返回模块对象,否则返回null
290
+ */
291
+ Manager.prototype.getMod = function (name) {
292
+ return this.mods[name];
293
+ };
294
+
295
+ /**
296
+ * 获取所有模块
297
+ * @returns {object[]} 模块对象数组
298
+ */
299
+ Manager.prototype.getMods = function () {
300
+ return this.mods;
301
+ };
302
+
303
+ /**
304
+ * 创建模块
305
+ * @param {string} config_file 配置文件路径
306
+ * @param {object} config 配置项
307
+ * @param {object} script 模块对象
308
+ * @returns {object} 模块对象
309
+ */
310
+ Manager.prototype.newMod = function (config_file, config, script) {
311
+ let mod;
312
+ switch (this.config.mod_type) {
313
+ case 'script':
314
+ mod = new Mod(config, this);
315
+ break;
316
+ default:
317
+ // 创建模块
318
+ mod = new this.Drive(config, this);
319
+ break;
320
+ }
321
+ mod.mode = this.config.mode;
322
+ mod.loadConfig(config_file);
323
+ if (script) {
324
+ for (let key in script) {
325
+ let obj = script[key];
326
+ if (typeof obj == 'function') {
327
+ mod.setMethod(key, obj);
328
+ } else {
329
+ mod.setData(key, obj);
330
+ }
331
+ }
332
+ }
333
+ return mod;
334
+ };
335
+
336
+ /**
337
+ * 注册模块
338
+ * @param {string} config_file 配置文件路径
339
+ * @param {object} config 配置项
340
+ * @param {object} script 模块对象
341
+ * @returns {object} 模块对象
342
+ */
343
+ Manager.prototype.registerMod = function (config_file, config = {}, script = {}) {
344
+ let mod = this.newMod(config_file, config, script);
345
+ this.setMod(mod.config.name, mod);
346
+ return mod;
347
+ };
348
+
349
+ /**
350
+ * 加载模块
351
+ * @param {string} name 模块名
352
+ * @returns {Promise<any>} 加载结果
353
+ */
354
+ Manager.prototype.loadMod = async function (name) {
355
+ let mod = this.getMod(name);
356
+ if (mod) {
357
+ return await mod.do('load');
358
+ }
359
+ return null;
360
+ };
361
+
362
+ /**
363
+ * 卸载模块
364
+ * @param {string} name 模块名
365
+ * @returns {Promise<any>} 卸载结果
366
+ */
367
+ Manager.prototype.unloadMod = async function (name) {
368
+ let mod = this.getMod(name);
369
+ if (mod) {
370
+ return await mod.do('unload');
371
+ }
372
+ return null;
373
+ };
374
+
375
+ /**
376
+ * 重载模块
377
+ * @param {string} name 模块名
378
+ * @returns {Promise<any>} 重载结果
379
+ */
380
+ Manager.prototype.reloadMod = async function (name) {
381
+ let mod = this.getMod(name);
382
+ if (mod) {
383
+ return await mod.do('reload');
384
+ }
385
+ return null;
386
+ };
387
+
388
+ /**
389
+ * 注销模块
390
+ * @param {string} name 模块名
391
+ * @returns {Promise<any>} 注销结果
392
+ */
393
+ Manager.prototype.unregisterMod = function (name) {
394
+ // 卸载模块
395
+ this.unloadMod(name);
396
+ // 删除模块
397
+ let mod = this.delMod(name);
398
+ return mod;
399
+ };
400
+
401
+ /**
402
+ * 批量注册模块
403
+ * @param {string[]} files 配置文件路径数组
404
+ * @param {object} config 配置项
405
+ * @param {object} script 模块对象
406
+ */
407
+ Manager.prototype.registerMods = function (files, config = {}, script = {}) {
408
+ for (let file of files) {
409
+ this.registerMod(file, config, script);
410
+ }
411
+ };
412
+
413
+ /**
414
+ * 加载所有模块
415
+ */
416
+ Manager.prototype.loadMods = async function () {
417
+ var promises = [];
418
+ let mods = this.getMods();
419
+ for (let name in mods) {
420
+ let mod = mods[name];
421
+ promises.push(mod.do('load'));
422
+ }
423
+ await Promise.all(promises);
424
+ };
425
+
426
+ /**
427
+ * 获取目录名
428
+ * @returns {string} 目录名
429
+ */
430
+ Manager.prototype.getDirName = function () {
431
+ // 前缀,为当前类名
432
+ let prefix = this.constructor.name.toLowerCase();
433
+ // 后缀,为配置项名称
434
+ let name = this.config.name.toLowerCase();
435
+ // 目录名,为前缀加下划线加后缀
436
+ return prefix + '_' + name;
437
+ };
438
+
439
+ /**
440
+ * 获取所有目录下的文件
441
+ * @param {string} dir 目录路径
442
+ * @returns {Array} 文件路径数组
443
+ */
444
+ Manager.prototype._getAllDirFiles = async function (dir) {
445
+ var dirs = await $.dir.getAllAsync(dir, this.getDirName());
446
+ var filename = this.config.filename;
447
+ var results = await Promise.all(dirs.map((d) => $.file.getAllAsync(d, filename)));
448
+ var files = [];
449
+ for (var i = 0; i < results.length; i++) {
450
+ if (results[i].length > 0) {
451
+ files.push(...results[i]);
452
+ }
453
+ }
454
+ return files;
455
+ };
456
+
457
+ /**
458
+ * 检索目录下所有文件
459
+ * @private
460
+ * @param {string} dir 目录路径
461
+ * @returns {Array} 文件路径数组
462
+ */
463
+ Manager.prototype._findFiles = async function (dir) {
464
+ // 检查目录是否存在
465
+ if (!dir) {
466
+ this.log('error', '目录不能为空');
467
+ return [];
468
+ }
469
+ // 检查目录是否存在
470
+ if (!dir.hasDir()) {
471
+ return [];
472
+ }
473
+ if (this.config.search_way === 'dir') {
474
+ return await this._getAllDirFiles(dir);
475
+ }
476
+ // 检索目录下所有文件
477
+ return await $.file.getAllAsync(dir, this.config.filename);
478
+ };
479
+
480
+ /**
481
+ * 加载所有模块的脚本
482
+ */
483
+ Manager.prototype.loadScripts = async function () {
484
+ var promises = [];
485
+ let mods = this.getMods();
486
+ for (let name in mods) {
487
+ let mod = mods[name];
488
+ promises.push(mod.call('loadScript'));
489
+ }
490
+ await Promise.all(promises);
491
+ };
492
+
493
+ /**
494
+ * 更新配置前的钩子函数
495
+ */
496
+ Manager.prototype.updateBefore = function () {
497
+ // this.log('info', '更新配置前的钩子函数');
498
+ };
499
+
500
+ /**
501
+ * 更新配置前的钩子函数
502
+ */
503
+ Manager.prototype.updateAfter = function () {
504
+ // this.log('info', '更新配置后钩子函数');
505
+ };
506
+
507
+ /**
508
+ * 更新配置
509
+ * @param {string} dir 检索的路径
510
+ * @param {boolean} clear 是否清除缓存
511
+ */
512
+ Manager.prototype.update = async function (dir, clear = true) {
513
+ if (clear) {
514
+ this.clearMods();
515
+ }
516
+
517
+ // 查找所有json文件
518
+ let files = await this._findFiles(dir || this.config.dir);
519
+ // 批量注册模块
520
+ this.registerMods(files);
521
+ // 更新配置信息
522
+ this.updateInfo();
523
+ if (!this.config.lazy_load) {
524
+ // 批量加载脚本
525
+ await this.loadScripts();
526
+ }
527
+ this.is_loaded = true;
528
+ };
529
+
530
+ // ==== 高性能调用接口 ====
531
+ /**
532
+ * 调用模块的方法(高性能版本)
533
+ * @param {string} name 模块名
534
+ * @param {string} method 方法名
535
+ * @param {...any} params 参数集合
536
+ * @returns {Promise<any>} 执行结果
537
+ */
538
+ Manager.prototype.main = async function (name, method, ...params) {
539
+ var result = null;
540
+ if (name) {
541
+ let mod = this.getMod(name);
542
+ if (mod && mod.config?.state === 1) {
543
+ result = await this._runMod(mod, method, ...params);
544
+ }
545
+ } else if (name === null) {
546
+ result = await this._runAllEnabled(method, ...params);
547
+ }
548
+ return result;
549
+ };
550
+
551
+ /**
552
+ * 私有方法:执行所有模块方法
553
+ * @param {string} method 方法名称
554
+ * @param {...any} params 方法参数集合
555
+ * @returns {Promise<any>} 执行结果
556
+ * @private
557
+ */
558
+ Manager.prototype._runAllEnabled = async function (method, ...params) {
559
+ var result;
560
+ for (let i = 0; i < this.infos.length; i++) {
561
+ let config = this.infos[i];
562
+ let mod = this.getMod(config.name);
563
+ if (mod && mod.config?.state === 1) {
564
+ var ret = null;
565
+ try {
566
+ ret = await this._runMod(mod, method, ...params);
567
+ } catch (err) {
568
+ $.log.error(`执行模块方法失败: `, err);
569
+ }
570
+ if (ret !== null && ret !== undefined) {
571
+ result = ret;
572
+ // 如果结果不为空且有结束标志,则停止迭代
573
+ if (mod.config?.end) {
574
+ break;
575
+ }
576
+ }
577
+ }
578
+ }
579
+ return result;
580
+ };
581
+
582
+ /**
583
+ * 私有方法:执行模块方法
584
+ * @param {object} mod 模块对象
585
+ * @param {string} method 方法名称
586
+ * @param {...any} params 参数集合
587
+ * @returns {Promise<any>} 执行结果
588
+ * @private
589
+ */
590
+ Manager.prototype._runMod = async function (mod, method, ...params) {
591
+ if (!mod || !method) return null;
592
+
593
+ // 确保模块已加载
594
+ if (!mod.isLoaded()) {
595
+ try {
596
+ await mod.call('loadScript');
597
+ } catch (err) {
598
+ $.log.error(`加载模块脚本失败: `, err);
599
+ }
600
+ }
601
+
602
+ // 执行方法
603
+ let ret = await mod.call(method, ...params);
604
+ // 根据模式决定是否重载
605
+ if (this.mode >= 4) {
606
+ mod.do('reload');
607
+ }
608
+
609
+ return ret;
610
+ };
611
+
612
+ /**
613
+ * 初始化管理器
614
+ */
615
+ Manager.prototype._initManager = function () {};
616
+
617
+ /**
618
+ * 获取公共模块目录
619
+ * @returns {string} 公共模块目录
620
+ */
621
+ Manager.prototype.getBaseDir = function () {
622
+ return this.config.base_dir;
623
+ };
624
+
625
+ /**
626
+ * 获取二次开发模块目录
627
+ * @returns {string} 二次开发模块目录
628
+ */
629
+ Manager.prototype.getDir = function () {
630
+ return this.config.dir || this.getDir();
631
+ };
632
+
633
+ /**
634
+ * 加载资源
635
+ */
636
+ Manager.prototype._loadSources = async function () {
637
+ // 通过更新函数加载资源信息
638
+ let base_dir = this.getBaseDir();
639
+ let dir = this.getDir();
640
+ if (base_dir) {
641
+ await this.call('update', base_dir);
642
+ await this.call('update', dir, false);
643
+ } else {
644
+ await this.call('update', dir);
645
+ }
646
+ };
647
+
648
+ /**
649
+ * 初始化资源
650
+ */
651
+ Manager.prototype._initSources = async function () {
652
+ // 通过
653
+ };
654
+
655
+ /**
656
+ * 初始化公共属性
657
+ */
658
+ Manager.prototype._initCore = async function () {
659
+ // 初始化管理器
660
+ this._initManager();
661
+ // 加载资源
662
+ await this._loadSources();
663
+ // 初始化AI客户端
664
+ await this._initSources();
665
+ };
666
+
667
+ /**
668
+ * 执行方法 - 内部方法
669
+ * @param {string} mod 模块对象
670
+ * @param {string} method 方法名称
671
+ * @param {...any} params 参数列表
672
+ * @returns {any} 返回执行结果
673
+ */
674
+ Manager.prototype._exec = async function (mod, method, ...params) {
675
+ if (mod[method]) {
676
+ return await mod[method](...params);
677
+ } else {
678
+ throw new Error(`方法${method}不存在`);
679
+ }
680
+ };
681
+
682
+ /**
683
+ * 执行方法
684
+ * @param {string} name 模块名
685
+ * @param {string} method 方法名称
686
+ * @param {...any} params 参数列表
687
+ * @returns {any} 返回执行结果
688
+ */
689
+ Manager.prototype.exec = async function (name, method, ...params) {
690
+ let ret;
691
+ try {
692
+ let mod = this.getMod(name);
693
+ if (!mod) {
694
+ throw new Error(`模块${name}不存在`);
695
+ }
696
+ ret = await this._exec(mod, method, ...params);
697
+ } catch (error) {
698
+ this.log('error', `${method}方法执行失败!`, error);
699
+ }
700
+ return ret;
701
+ };
702
+
703
+ /**
704
+ * 确保所有模块都已加载
705
+ * @returns {Promise} 加载完成
706
+ */
707
+ Manager.prototype._ensureAllLoaded = async function () {
708
+ var infos = this.getInfos();
709
+ var promises = [];
710
+
711
+ for (var i = 0; i < infos.length; i++) {
712
+ var mod = this.getMod(infos[i].name);
713
+ if (mod && !mod.isLoaded()) {
714
+ ((info) => {
715
+ promises.push(
716
+ mod.call('loadScript').catch((err) => {
717
+ this.log('error', `模块${info.name}加载失败`, err);
718
+ })
719
+ );
720
+ })(infos[i]);
721
+ }
722
+ }
723
+ if (promises.length > 0) {
724
+ await Promise.all(promises);
725
+ }
726
+ };
727
+
728
+ /**
729
+ * 异步触发事件,按顺序执行等待完成
730
+ * @param {string} method 方法名称
731
+ * @param {...any} params 事件参数
732
+ * @returns {Promise} 事件触发结果
733
+ */
734
+ Manager.prototype.runWait = async function (method, ...params) {
735
+ // 参数校验
736
+ if (typeof method !== 'string') {
737
+ throw new TypeError('方法名称必须是字符串');
738
+ }
739
+
740
+ let result;
741
+ let infos = this.getInfos();
742
+
743
+ for (let i = 0; i < infos.length; i++) {
744
+ let info = infos[i];
745
+ let mod = this.getMod(info.name);
746
+ if (!mod) {
747
+ continue; // 跳过不存在的模块
748
+ }
749
+ // 确保模块已加载
750
+ if (!mod.isLoaded()) {
751
+ try {
752
+ await mod.call('loadScript');
753
+ } catch (error) {
754
+ this.log('error', `模块${info.name}加载失败`, error);
755
+ continue; // 跳过加载失败的模块
756
+ }
757
+ }
758
+
759
+ // 执行方法
760
+ try {
761
+ let ret = await mod.do(method, ...params);
762
+ if (ret !== null && ret !== undefined) {
763
+ result = ret;
764
+ }
765
+ } catch (error) {
766
+ this.log('error', `模块${info.name}执行${method}方法失败`, error);
767
+ }
768
+ }
769
+
770
+ return result;
771
+ };
772
+
773
+ /**
774
+ * 异步触发事件,并发执行不等待
775
+ * @param {string} method 方法名称
776
+ * @param {...any} params 事件参数
777
+ * @returns {boolean} 是否成功触发事件
778
+ */
779
+ Manager.prototype.runAsync = async function (method, ...params) {
780
+ // 参数校验
781
+ if (typeof method !== 'string') {
782
+ throw new TypeError('方法名称必须是字符串');
783
+ }
784
+
785
+ // 确保所有模块都已加载
786
+ await this._ensureAllLoaded();
787
+
788
+ let infos = this.getInfos();
789
+
790
+ // 并发执行所有方法,不等待结果
791
+ for (let i = 0; i < infos.length; i++) {
792
+ let info = infos[i];
793
+ let mod = this.getMod(info.name);
794
+ try {
795
+ mod.do(method, ...params);
796
+ } catch (error) {
797
+ this.log('error', `模块${info.name}执行${method}方法失败`, error);
798
+ }
799
+ }
800
+
801
+ return true;
802
+ };
803
+
804
+ /**
805
+ * 异步触发事件,并发执行等待完成
806
+ * @param {string} method 方法名称
807
+ * @param {...any} params 事件参数
808
+ * @returns {Promise} 事件触发结果
809
+ */
810
+ Manager.prototype.runAll = async function (method, ...params) {
811
+ // 参数校验
812
+ if (typeof method !== 'string') {
813
+ throw new TypeError('方法名称必须是字符串');
814
+ }
815
+
816
+ // 确保所有模块都已加载
817
+ await this._ensureAllLoaded();
818
+
819
+ const promises = [];
820
+ let infos = this.getInfos();
821
+
822
+ // 并发执行所有方法
823
+ for (let i = 0; i < infos.length; i++) {
824
+ let info = infos[i];
825
+ let mod = this.getMod(info.name);
826
+ promises.push(
827
+ mod.do(method, ...params).catch((error) => {
828
+ this.log('error', `模块${info.name}执行${method}方法失败`, error);
829
+ return null; // 失败时返回null
830
+ })
831
+ );
832
+ }
833
+
834
+ return await Promise.all(promises);
835
+ };
836
+
837
+ /**
838
+ * 异步触发事件,竞争执行
839
+ * @param {string} method 方法名称
840
+ * @param {...any} params 事件参数
841
+ * @returns {Promise} 第一个完成的结果
842
+ */
843
+ Manager.prototype.runRace = async function (method, ...params) {
844
+ // 参数校验
845
+ if (typeof method !== 'string') {
846
+ throw new TypeError('方法名称必须是字符串');
847
+ }
848
+
849
+ // 确保所有模块都已加载
850
+ await this._ensureAllLoaded();
851
+
852
+ const promises = [];
853
+ let infos = this.getInfos();
854
+
855
+ // 竞争执行所有方法
856
+ for (let i = 0; i < infos.length; i++) {
857
+ let info = infos[i];
858
+ let mod = this.getMod(info.name);
859
+ promises.push(
860
+ mod.do(method, ...params).catch((error) => {
861
+ this.log('error', `模块${info.name}执行${method}方法失败`, error);
862
+ throw error; // 竞争执行中,失败应该抛出错误
863
+ })
864
+ );
865
+ }
866
+
867
+ return await Promise.race(promises);
868
+ };
869
+
870
+ /**
871
+ * 异步触发事件,瀑布流执行
872
+ * @param {string} method 方法名称
873
+ * @param {*} result 初始值
874
+ * @param {...any} params 事件参数
875
+ * @returns {Promise} 最后一个事件监听者的结果
876
+ */
877
+ Manager.prototype.runWaterfall = async function (method, result, ...params) {
878
+ // 参数校验
879
+ if (typeof method !== 'string') {
880
+ throw new TypeError('方法名称必须是字符串');
881
+ }
882
+
883
+ let infos = this.getInfos();
884
+
885
+ for (let i = 0; i < infos.length; i++) {
886
+ let info = infos[i];
887
+ let mod = this.getMod(info.name);
888
+
889
+ // 确保模块已加载
890
+ if (!mod.isLoaded()) {
891
+ try {
892
+ await mod.call('loadScript');
893
+ } catch (error) {
894
+ this.log('error', `模块${info.name}加载失败`, error);
895
+ continue; // 跳过加载失败的模块
896
+ }
897
+ }
898
+
899
+ // 执行方法,将前一个结果作为参数传递给下一个
900
+ try {
901
+ let ret = await mod.do(method, result, ...params);
902
+ if (ret !== null && ret !== undefined) {
903
+ result = ret;
904
+ }
905
+ } catch (error) {
906
+ this.log('error', `模块${info.name}执行${method}方法失败`, error);
907
+ }
908
+ }
909
+
910
+ return result;
911
+ };
912
+
913
+ /**
914
+ * 异步触发事件,子模块执行
915
+ * @param {string} name 子模块名称
916
+ * @param {string} method 方法名称
917
+ * @param {...any} params 事件参数
918
+ * @returns {Promise} 事件触发结果
919
+ */
920
+ Manager.prototype.runSubMod = async function (name, method, ...params) {
921
+ // 参数校验
922
+ if (typeof method !== 'string') {
923
+ throw new TypeError('方法名称必须是字符串');
924
+ }
925
+ let mod = this.getMod(name);
926
+ if (!mod) {
927
+ throw new Error(`模块${name}不存在`);
928
+ }
929
+ return await mod.do(method, ...params);
930
+ };
931
+
932
+ /**
933
+ * 移除事件监听
934
+ * @param {string} event 事件名
935
+ */
936
+ Manager.prototype.offEvent = function (event) {
937
+ this.getEventer()?.off(event);
938
+ };
939
+
940
+ /**
941
+ * 创建模块
942
+ * @param {object} config 模块配置
943
+ * @param {string} file 模块文件路径
944
+ * @returns {string} 创建的模块文件路径
945
+ */
946
+ Manager.prototype.createFile = function (config, file) {
947
+ if (!config.name) {
948
+ throw new TypeError('模块名称不能为空');
949
+ }
950
+ if (!config.title) {
951
+ throw new TypeError('模块标题不能为空');
952
+ }
953
+ if (!config.description) {
954
+ throw new TypeError('模块描述不能为空');
955
+ }
956
+ if (this.getMod(config.name)) {
957
+ throw new Error(`创建失败,原因:模块${config.name}已存在`);
958
+ }
959
+ let mod = new this.Drive(config, this);
960
+ let f = file;
961
+ if (!f) {
962
+ f = `${config.name}/${this.config.filename}`;
963
+ if (this.config.search_way === 'dir') {
964
+ let dir_name = this.getDirName();
965
+ f = `${dir_name}/${f}`;
966
+ }
967
+ }
968
+ f = f.fullname(this.config.dir);
969
+ mod.createConfigFile(f, config);
970
+ return f;
971
+ };
972
+
973
+ /**
974
+ * 创建模块
975
+ * @param {object} config 模块配置
976
+ * @param {string} file 模块文件路径
977
+ * @returns {object} 创建的模块实例
978
+ */
979
+ Manager.prototype.create = function (config, file = '') {
980
+ let f = this.createFile(config, file);
981
+ let mod = this.registerMod(f, config);
982
+ return mod;
983
+ };
984
+
985
+ /**
986
+ * 删除模块
987
+ * @param {string} name 模块名称
988
+ * @returns {object} 删除的模块实例
989
+ */
990
+ Manager.prototype.remove = async function (name) {
991
+ let mod = this.getMod(name);
992
+ if (mod) {
993
+ await mod.remove();
994
+ }
995
+ this.unregisterMod(name);
996
+ return mod;
997
+ };
998
+
999
+ module.exports = {
1000
+ Manager,
1001
+ Drive,
1002
+ Mod,
1003
+ // 向后兼容
1004
+ Index: Manager,
1005
+ Item: Drive
1006
+ };