mm_machine 2.9.3 → 2.9.4

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/drive.js +668 -490
  2. package/index.js +1141 -921
  3. package/mod.js +742 -711
  4. package/package.json +2 -2
package/mod.js CHANGED
@@ -1,711 +1,742 @@
1
- const { Base } = require('mm_expand');
2
- require('mm_hot_reload');
3
-
4
- /**
5
- * 增强require函数,专门用于脚本文件(.js)热重载
6
- * 当脚本文件内容发生变化时,自动重新加载并触发回调
7
- * @param {string} file 脚本文件路径(.js)
8
- * @param {Function} func 热更新回调函数,文件变化时触发
9
- * @returns {object} 加载的模块对象
10
- * @throws {TypeError} 文件路径不是字符串或回调不是函数时抛出
11
- */
12
- $.require = function (file, func) {
13
- // 参数校验
14
- if (typeof file !== 'string') {
15
- throw new TypeError('第一个参数(file)必须是字符串');
16
- }
17
-
18
- if (func && typeof func !== 'function') {
19
- throw new TypeError('第二个参数(func)必须是函数');
20
- }
21
-
22
- // 确保文件是.js文件
23
- if (!file.endsWith('.js')) {
24
- throw new TypeError('$.require 只能用于.js脚本文件');
25
- }
26
-
27
- return $.mod.load(file, func);
28
- };
29
-
30
- /**
31
- * 增强JSON加载函数,专门用于配置文件(.json)热重载
32
- * 当配置文件内容发生变化时,自动重新加载并触发回调
33
- * @param {string} file 配置文件路径(.json)
34
- * @param {Function} func 热更新回调函数,文件变化时触发
35
- * @returns {object} 解析的JSON对象
36
- * @throws {TypeError} 文件路径不是字符串或回调不是函数时抛出
37
- */
38
- $.loadJson = function (file, func) {
39
- // 参数校验
40
- if (typeof file !== 'string') {
41
- throw new TypeError('第一个参数(file)必须是字符串');
42
- }
43
-
44
- if (func && typeof func !== 'function') {
45
- throw new TypeError('第二个参数(func)必须是函数');
46
- }
47
-
48
- // 确保文件是.json文件
49
- if (!file.endsWith('.json')) {
50
- throw new TypeError('$.loadJson 只能用于.json配置文件');
51
- }
52
- return $.mod.load(file, func);
53
- };
54
-
55
- /**
56
- * 模块类
57
- */
58
- class Mod extends Base {
59
- /**
60
- * 配置项
61
- */
62
- static config = {
63
- // 模块名称
64
- name: '',
65
- // 模块描述
66
- description: '',
67
- // 状态, 可选值: 1-启用, 0-禁用
68
- state: 1,
69
- // 是否需要缓存数据
70
- need_cache: false,
71
- // 缓存文件路径
72
- cache_file: ''
73
- };
74
-
75
- /**
76
- * 构造函数
77
- * @param {object} config 配置项
78
- * @param {object|null} parent 父对象
79
- */
80
- constructor(config, parent = null) {
81
- super(config);
82
- // 脚本方法
83
- this._methods = {};
84
- // 脚本数据
85
- this._datas = {};
86
- // 是否已加载
87
- this.is_loaded = false;
88
- // 追加查询到上级的方法
89
- if (parent) {
90
- this.getParent = function () {
91
- return parent;
92
- };
93
- }
94
- }
95
- }
96
-
97
- /**
98
- * 检查模块是否已加载
99
- * @returns {boolean} 是否已加载
100
- */
101
- Mod.prototype.isLoaded = function () {
102
- return this.is_loaded;
103
- };
104
-
105
- /**
106
- * 日志输出
107
- * @param {string} level 日志级别
108
- * @param {string} message 日志消息
109
- * @param {...any} params 日志参数
110
- */
111
- Mod.prototype.log = function (level, message, ...params) {
112
- this.getLogger()[level](`[${this.constructor.name}.${this.config.name}] ${message}`, ...params);
113
- };
114
-
115
- /**
116
- * 监听事件
117
- */
118
- Mod.prototype._listen = function () {
119
- this._onLoad();
120
- this._onInit();
121
- this._onStart();
122
- this._onStop();
123
- this._onUnload();
124
- this._onDestroy();
125
- };
126
-
127
- /**
128
- * 监听销毁事件
129
- */
130
- Mod.prototype._onDestroy = function () {
131
- let status_last = 'stopped';
132
- // 销毁
133
- this.on('destroy:before', async (ctx) => {
134
- status_last = this.getState();
135
- this.setState('destroying');
136
- });
137
- this.on('destroy:after', async (ctx) => {
138
- await this._destroyCore(...ctx.params);
139
- });
140
- this.on('destroy:success', (ctx) => {
141
- this.setState('destroyed');
142
- });
143
- this.on('destroy:error', (ctx) => {
144
- this.setState(status_last);
145
- });
146
- };
147
-
148
- /**
149
- * 监听加载事件
150
- * @param {object} ctx 上下文对象
151
- */
152
- Mod.prototype._onLoad = async function (ctx) {
153
- // 1. 加载
154
- this.on('load:before', async (ctx) => {
155
- this.setState('loading');
156
- await this._loadCore(...ctx.params);
157
- });
158
- this.on('load:after', (ctx) => {
159
- this.setState('loaded');
160
- this.is_loaded = true;
161
- });
162
- };
163
-
164
- /**
165
- * 监听启动事件
166
- * @param {object} ctx 上下文对象
167
- */
168
- Mod.prototype._onStart = async function (ctx) {
169
- let status_last = 'inited';
170
- // 3. 启动
171
- this.on('start:before', async (ctx) => {
172
- status_last = this.getState();
173
- this.setState('starting');
174
- await this._startCore(...ctx.params);
175
- });
176
- this.on('start:success', (ctx) => {
177
- this.setState('running');
178
- });
179
- this.on('start:error', (ctx) => {
180
- this.setState(status_last);
181
- });
182
- };
183
-
184
- /**
185
- * 监听停止事件
186
- * @param {object} ctx 上下文对象
187
- */
188
- Mod.prototype._onStop = async function (ctx) {
189
- let status_last = 'running';
190
- // 4. 停止
191
- this.on('stop:before', async (ctx) => {
192
- status_last = this.getState();
193
- this.setState('stopping');
194
- });
195
- this.on('stop:after', async (ctx) => {
196
- await this._stopCore(...ctx.params);
197
- });
198
- this.on('stop:success', async (ctx) => {
199
- this.setState('stopped');
200
- });
201
- this.on('stop:error', (ctx) => {
202
- this.setState(status_last);
203
- });
204
- };
205
-
206
- /**
207
- * 监听卸载事件
208
- * @param {object} ctx 上下文对象
209
- */
210
- Mod.prototype._onUnload = async function (ctx) {
211
- let status_last = 'stopped';
212
- // 5. 卸载
213
- this.on('unload:before', (ctx) => {
214
- status_last = this.getState();
215
- this.setState('unloading');
216
- });
217
- this.on('unload:check', (ctx) => {
218
- if (status_last !== 'stopped') {
219
- status_last = this.getState();
220
- ctx.error = new Error('卸载前必须先停止');
221
- }
222
- });
223
- this.on('unload:after', async (ctx) => {
224
- this.setState('unloaded');
225
- this.is_loaded = false;
226
- await this._unloadCore(...ctx.params);
227
- });
228
- };
229
-
230
- /**
231
- * 初始化监听事件
232
- * @param {object} ctx 上下文对象
233
- */
234
- Mod.prototype._onDestroy = async function (ctx) {
235
- let status_last = 'unloaded';
236
- // 6. 销毁
237
- this.on('destroy:before', async (ctx) => {
238
- status_last = this.getState();
239
- this.setState('destroying');
240
- });
241
- this.on('destroy:check', (ctx) => {
242
- if (status_last !== 'unloaded') {
243
- this.setState(status_last);
244
- ctx.error = new Error('销毁前必须先卸载');
245
- }
246
- });
247
- };
248
-
249
- /**
250
- * 加载 - 内部方法
251
- * @param {...any} args 加载参数
252
- * @returns {object} 模块对象
253
- * @private
254
- */
255
- Mod.prototype._load = async function (...args) {
256
- return this;
257
- };
258
-
259
- /**
260
- * 加载
261
- * @param {...any} args 加载参数
262
- * @returns {object} 模块对象
263
- */
264
- Mod.prototype.load = async function (...args) {
265
- return await this._load(...args);
266
- };
267
-
268
- /**
269
- * 加载核心
270
- * @private
271
- * @param {...any} args 加载参数
272
- */
273
- Mod.prototype._loadCore = async function (...args) {
274
- };
275
-
276
- /**
277
- * 启动 - 内部方法
278
- * @private
279
- * @param {...any} args 初始化参数
280
- * @returns {object} 模块对象
281
- */
282
- Mod.prototype._start = async function (...args) {
283
- return this;
284
- };
285
-
286
- /**
287
- * 启动
288
- * @param {...any} args 初始化参数
289
- * @returns {object} 模块对象
290
- */
291
- Mod.prototype.start = async function (...args) {
292
- return await this._start(...args);
293
- };
294
-
295
- /**
296
- * 启动核心
297
- * @private
298
- * @param {...any} args 初始化参数
299
- */
300
- Mod.prototype._startCore = async function (...args) {
301
-
302
- };
303
-
304
- /**
305
- * 停止 - 内部方法
306
- * @private
307
- * @returns {object} 模块对象
308
- */
309
- Mod.prototype._stop = async function () {
310
- return this;
311
- };
312
-
313
- /**
314
- * 停止
315
- * @returns {object} 模块对象
316
- */
317
- Mod.prototype.stop = async function () {
318
- return await this._stop();
319
- };
320
-
321
- /**
322
- * 停止核心
323
- * @private
324
- */
325
- Mod.prototype._stopCore = async function () {
326
-
327
- };
328
-
329
- /**
330
- * 卸载 - 内部方法
331
- * @private
332
- * @returns {object} 模块对象
333
- */
334
- Mod.prototype._unload = async function () {
335
- return this;
336
- };
337
-
338
- /**
339
- * 卸载
340
- * @returns {object} 模块对象
341
- */
342
- Mod.prototype.unload = async function () {
343
- return await this._unload();
344
- };
345
-
346
- /**
347
- * 卸载核心
348
- */
349
- Mod.prototype._unloadCore = async function () {
350
- if (this._methods) {
351
- for (let key in this._methods) {
352
- delete this[key];
353
- }
354
- this._methods = {};
355
- }
356
- if (this._datas) {
357
- for (let key in this._datas) {
358
- delete this[key];
359
- }
360
- this._datas = {};
361
- }
362
- };
363
-
364
- /**
365
- * 重载
366
- */
367
- Mod.prototype.reload = async function () {
368
- await this.do('unload');
369
- await this.do('load');
370
- };
371
-
372
- /**
373
- * 重启
374
- */
375
- Mod.prototype.restart = async function () {
376
- await this.do('stop');
377
- await this.do('start');
378
- };
379
-
380
- /**
381
- * 是否运行中
382
- * @returns {boolean} 是否运行中
383
- */
384
- Mod.prototype.isRunning = function () {
385
- return this.getState() === 'running';
386
- };
387
-
388
- /**
389
- * 结束
390
- */
391
- Mod.prototype.end = async function () {
392
- await this.do('stop');
393
- await this.do('unload');
394
- await this.do('destroy');
395
- };
396
-
397
- /**
398
- * 获取事件管理器
399
- * @returns {object} 事件管理器
400
- */
401
- Mod.prototype.getEventer = function () {
402
- return this._eventer || $.eventer;
403
- };
404
-
405
- /**
406
- * 设置事件管理器
407
- * @param {object} eventer 事件管理器
408
- */
409
- Mod.prototype.setEventer = function (eventer) {
410
- this._eventer = eventer;
411
- };
412
-
413
- /**
414
- * 触发事件
415
- * @param {string} event 事件名
416
- * @param {...any} args 事件参数
417
- */
418
- Mod.prototype.emitEvent = function (event, ...args) {
419
- this.getEventer()?.emit(event, ...args);
420
- };
421
-
422
- /**
423
- * 触发事件 - 随机触发
424
- * @param {string} event 事件名
425
- * @param {...any} args 事件参数
426
- * @returns {Promise<any>} 事件触发结果
427
- */
428
- Mod.prototype.emitEventRace = async function (event, ...args) {
429
- return await this.getEventer()?.emitRace(event, ...args);
430
- };
431
-
432
- /**
433
- * 触发事件 - 返回第一个非空结果
434
- * @param {string} event 事件名
435
- * @param {...any} args 事件参数
436
- * @returns {Promise<any>} 事件触发结果
437
- */
438
- Mod.prototype.emitEventFirst = async function (event, ...args) {
439
- return await this.getEventer()?.emitFirst(event, ...args);
440
- };
441
-
442
- /**
443
- * 注册事件监听
444
- * @param {string} event 事件名
445
- * @param {Function} callback 事件回调函数
446
- */
447
- Mod.prototype.onEvent = function (event, callback) {
448
- this.getEventer()?.on(event, callback);
449
- };
450
-
451
- /**
452
- * 移除事件监听
453
- * @param {string} event 事件名
454
- */
455
- Mod.prototype.offEvent = function (event) {
456
- this.getEventer()?.off(event);
457
- };
458
-
459
- /**
460
- * 主方法名
461
- * @param {...any} args 方法参数
462
- * @returns {Promise<any>} 方法执行结果
463
- */
464
- Mod.prototype.main = async function (...args) {
465
- let method = args[0];
466
- let func = this.getMethod(method);
467
- if (!func) {
468
- throw new Error(`方法${method}不存在`);
469
- }
470
- let params = args.slice(1);
471
- return await func(...params);
472
- };
473
-
474
- /**
475
- * 设置脚本方法
476
- * @param {object} methods 脚本方法对象
477
- */
478
- Mod.prototype.setMethods = function (methods) {
479
- if (typeof methods !== 'object') {
480
- throw new Error(`参数(methods)必须是对象`);
481
- }
482
- if (!methods) return;
483
- if (!this._methods) {
484
- this._methods = {};
485
- }
486
- for (let key in methods) {
487
- this.setMethod(key, methods[key]);
488
- }
489
- };
490
-
491
- /**
492
- * 设置脚本方法
493
- * @param {string} method 方法名
494
- * @param {Function} func 方法函数
495
- */
496
- Mod.prototype.setMethod = function (method, func) {
497
- if (typeof method !== 'string') {
498
- throw new Error(`第一个参数(method)必须是字符串`);
499
- }
500
- if (method === '_datas') {
501
- throw new Error(`第一个参数(method)不能为_datas键`);
502
- }
503
- if (method === '_methods') {
504
- throw new Error(`第一个参数(method)不能为_methods键`);
505
- }
506
- if (!func) throw new Error(`第二个参数(func)不能为空`);
507
- if (typeof func !== 'function') {
508
- throw new Error(`第二个参数(func)必须是函数`);
509
- }
510
- if (!this._methods) {
511
- this._methods = {};
512
- }
513
- this._methods[method] = true;
514
- this[method] = func;
515
- };
516
-
517
- /**
518
- * 获取方法函数
519
- * @param {string} method 方法名
520
- * @returns {Function} 方法函数
521
- */
522
- Mod.prototype.getMethod = function (method) {
523
- if (typeof method !== 'string') {
524
- throw new Error(`第一个参数(method)必须是字符串`);
525
- }
526
- return this[method];
527
- };
528
-
529
- /**
530
- * 获取数据
531
- * @returns {object} 数据对象
532
- */
533
- Mod.prototype.getDatas = function () {
534
- let datas = this._datas;
535
- let result = {};
536
- for (let key in datas) {
537
- result[key] = this[key];
538
- }
539
- return result;
540
- };
541
-
542
- /**
543
- * 获取数据
544
- * @returns {object} 数据对象
545
- */
546
- Mod.prototype.getData = function (key) {
547
- return this[key];
548
- };
549
-
550
- /**
551
- * 设置数据
552
- * @param {object} datas 数据对象
553
- */
554
- Mod.prototype.setDatas = function (datas) {
555
- if (typeof datas !== 'object') {
556
- throw new Error(`参数(datas)必须是对象`);
557
- }
558
- if (!this._datas) {
559
- this._datas = {};
560
- }
561
- for (let key in datas) {
562
- this.setData(key, datas[key]);
563
- }
564
- };
565
-
566
- /**
567
- * 设置数据
568
- * @param {string} key 数据键
569
- * @param {*} value 数据值
570
- */
571
- Mod.prototype.setData = function (key, value) {
572
- if (typeof key !== 'string') {
573
- throw new Error(`第一个参数(key)必须是字符串`);
574
- }
575
- if (key === '_datas') {
576
- throw new Error(`第一个参数(key)不能为_datas键`);
577
- }
578
- if (key === '_methods') {
579
- throw new Error(`第一个参数(key)不能为_methods键`);
580
- }
581
- if (value === undefined || value === null) throw new Error(`第二个参数(value)不能为undefined或null`);
582
- if (typeof value == 'function') {
583
- throw new Error(`第二个参数(value)不能为函数`);
584
- }
585
- this._datas[key] = typeof (value);
586
- this[key] = value;
587
- };
588
-
589
- /**
590
- * 保存数据
591
- */
592
- Mod.prototype.saveDatas = function () {
593
- let datas = this.getDatas();
594
- let file = this.config.cache_file || './cache.json'.fullname(__dirname);
595
- file.saveJson(datas);
596
- };
597
-
598
- /**
599
- * 加载数据
600
- */
601
- Mod.prototype.loadDatas = function () {
602
- let file = this.config.cache_file || './cache.json'.fullname(__dirname);
603
- let datas = file.loadJson();
604
- this.setDatas(datas);
605
- };
606
-
607
- /**
608
- * 调用函数(核心执行方法)
609
- * @param {string} method 函数名
610
- * @param {*} params 参数集合
611
- * @returns {Promise<any>} 执行结果
612
- */
613
- Mod.prototype.call = async function (method, ...params) {
614
- let method_func = this.getMethod(method);
615
- if (typeof method_func !== 'function') return null;
616
-
617
- let result;
618
-
619
- try {
620
- result = await this._callBefore(method, params);
621
- if (result) return result;
622
- result = await this._callMain(method_func, params, result);
623
- result = await this._callAfter(method, params, result);
624
- } catch (err) {
625
- this.log('error', `执行方法 ${method} 失败: `, err);
626
- return null;
627
- }
628
-
629
- return result;
630
- };
631
-
632
- /**
633
- * 执行前置钩子
634
- * @param {string} method 方法名
635
- * @param {Array} params 参数
636
- * @returns {Promise<any>} 前置钩子结果
637
- */
638
- Mod.prototype._callBefore = async function (method, params) {
639
- let before_method = `${method}Before`;
640
- let before_func = this.getMethod(before_method);
641
-
642
- if (typeof before_func !== 'function') return undefined;
643
-
644
- try {
645
- let result = await before_func.call(this, ...params);
646
- return result;
647
- } catch (err) {
648
- this.log('error', `执行前置钩子 ${before_method} 失败: `, err);
649
- return undefined;
650
- }
651
- };
652
-
653
- /**
654
- * 执行主方法
655
- * @param {Function} method_func 方法函数
656
- * @param {Array} params 参数
657
- * @param {any} result 前置钩子结果
658
- * @returns {Promise<any>} 主方法结果
659
- */
660
- Mod.prototype._callMain = async function (method_func, params, result) {
661
- let ret = await method_func.call(this, ...params);
662
- // 修复:如果主方法返回undefined,则使用前置钩子的结果
663
- return ret !== undefined ? ret : result;
664
- };
665
-
666
- /**
667
- * 执行后置钩子
668
- * @param {string} method 方法名
669
- * @param {Array} params 参数
670
- * @param {any} result 主方法结果
671
- * @returns {Promise<any>} 后置钩子结果
672
- */
673
- Mod.prototype._callAfter = async function (method, params, result) {
674
- let after_method = `${method}After`;
675
- let after_func = this.getMethod(after_method);
676
-
677
- if (typeof after_func !== 'function') return result;
678
-
679
- try {
680
- let after = await after_func.call(this, result, ...params);
681
- return after !== undefined ? after : result;
682
- } catch (err) {
683
- this.log('error', `执行后置钩子 ${after_method} 失败: `, err);
684
- return result;
685
- }
686
- };
687
-
688
- /**
689
- * 销毁核心
690
- * @returns {object} 返回当前对象
691
- */
692
- Mod.prototype._destroyCore = async function () {
693
- if(this.config.save_cache) {
694
- this.saveDatas();
695
- }
696
- this._datas = {};
697
- this._methods = {};
698
- };
699
-
700
- /**
701
- * 获取模块目录
702
- * @returns {string} 模块目录
703
- */
704
- Mod.prototype.getDir = function () {
705
- if (!this.getParent) return '';
706
- return this.getParent()?.getDir() || '';
707
- };
708
-
709
- module.exports = {
710
- Mod
711
- };
1
+ /**
2
+ * Mod 基础模块类
3
+ * 提供生命周期管理、方法/数据存储、事件系统、钩子机制等基础能力
4
+ * @class Mod
5
+ * @augments Base
6
+ */
7
+ // eslint-disable-next-line mm_eslint/object-name, mm_eslint/variable-name
8
+ var Base = require('mm_expand').Base;
9
+
10
+ class Mod extends Base {
11
+ /**
12
+ * 构造函数
13
+ * @param {object} config 配置参数
14
+ * @param {string} [config.name] 模块名称
15
+ * @param {string} [config.lifecycle_state='created'] 初始生命周期状态
16
+ */
17
+ constructor(config) {
18
+ super(config);
19
+ this._methods = {};
20
+ this._datas = {};
21
+ this.lifecycle_state = (config && config.lifecycle_state) || 'created';
22
+ this.is_loaded = false;
23
+
24
+ // 父对象
25
+ if (config && config.parent) {
26
+ this.getParent = function () {
27
+ return config.parent;
28
+ };
29
+ }
30
+ }
31
+ }
32
+
33
+ // ==================== 生命周期公共方法 ====================
34
+
35
+ /**
36
+ * 加载阶段:created loaded
37
+ * @returns {Promise<void>}
38
+ */
39
+ Mod.prototype.load = async function () {
40
+ return this._loadCore();
41
+ };
42
+
43
+ /**
44
+ * 初始化阶段:loaded inited
45
+ * @returns {Promise<void>}
46
+ */
47
+ Mod.prototype.init = async function () {
48
+ return this._initCore();
49
+ };
50
+
51
+ /**
52
+ * 启动阶段:inited → started
53
+ * @returns {Promise<void>}
54
+ */
55
+ Mod.prototype.start = async function () {
56
+ return this._startCore();
57
+ };
58
+
59
+ /**
60
+ * 暂停阶段:started → paused
61
+ * @returns {Promise<void>}
62
+ */
63
+ Mod.prototype.pause = async function () {
64
+ return this._pauseCore();
65
+ };
66
+
67
+ /**
68
+ * 恢复阶段:paused → started
69
+ * @returns {Promise<void>}
70
+ */
71
+ Mod.prototype.resume = async function () {
72
+ return this._resumeCore();
73
+ };
74
+
75
+ /**
76
+ * 结束阶段:started/paused → ended
77
+ * @returns {Promise<void>}
78
+ */
79
+ Mod.prototype.end = async function () {
80
+ return this._endCore();
81
+ };
82
+
83
+ /**
84
+ * 销毁阶段:ended → destroyed
85
+ * @returns {Promise<void>}
86
+ */
87
+ Mod.prototype.destroy = async function () {
88
+ return this._destroyCore();
89
+ };
90
+
91
+ // ==================== 生命周期 Core 方法 ====================
92
+
93
+ /**
94
+ * 加载核心
95
+ * 由 Drive 子类重写以添加脚本加载逻辑
96
+ * @returns {Promise<void>}
97
+ * @private
98
+ */
99
+ Mod.prototype._loadCore = async function () {
100
+ if (this.lifecycle_state !== 'created') {
101
+ throw new Error('模块未创建,无法加载');
102
+ }
103
+
104
+ this.emit('load:before');
105
+
106
+ try {
107
+ // 执行加载操作,由 Drive 子类重写
108
+ this.lifecycle_state = 'loaded';
109
+ this.emit('load:success');
110
+ } catch (err) {
111
+ this.emit('load:error', err);
112
+ throw err;
113
+ }
114
+ };
115
+
116
+ /**
117
+ * 初始化核心
118
+ * 调用 _init 钩子,Manager 类型自动调用 boot()
119
+ * @returns {Promise<void>}
120
+ * @private
121
+ */
122
+ Mod.prototype._initCore = async function () {
123
+ if (this.lifecycle_state !== 'loaded') {
124
+ throw new Error('模块未加载,无法初始化');
125
+ }
126
+
127
+ this.emit('init:before');
128
+
129
+ try {
130
+ var init_hook = this.getMethod('_init');
131
+ if (init_hook) {
132
+ var result = init_hook(this);
133
+ if (result instanceof Promise) {
134
+ var timeout = new Promise((resolve, reject) => {
135
+ setTimeout(() => {
136
+ reject(new Error('初始化超时'));
137
+ }, 30000);
138
+ });
139
+ await Promise.race([result, timeout]);
140
+ }
141
+ }
142
+
143
+ // Manager 类型模块自动调用 boot()(在设置状态前执行)
144
+ if (typeof this.boot === 'function') {
145
+ await this.boot();
146
+ }
147
+
148
+ this.lifecycle_state = 'inited';
149
+ this.emit('init:success');
150
+ } catch (err) {
151
+ this.emit('init:error', err);
152
+ throw err;
153
+ }
154
+ };
155
+
156
+ /**
157
+ * 启动核心
158
+ * 调用 _start 钩子,传播到子模块
159
+ * @returns {Promise<void>}
160
+ * @private
161
+ */
162
+ Mod.prototype._startCore = async function () {
163
+ if (this.lifecycle_state !== 'inited') {
164
+ if (this.lifecycle_state === 'started') {
165
+ return;
166
+ }
167
+ throw new Error('模块未初始化,无法启动');
168
+ }
169
+
170
+ this.emit('start:before');
171
+
172
+ try {
173
+ var start_hook = this.getMethod('_start');
174
+ if (start_hook) {
175
+ var result = start_hook(this);
176
+ if (result instanceof Promise) {
177
+ var timeout = new Promise((resolve, reject) => {
178
+ setTimeout(() => {
179
+ reject(new Error('启动超时'));
180
+ }, 30000);
181
+ });
182
+ await Promise.race([result, timeout]);
183
+ }
184
+ }
185
+
186
+ this.lifecycle_state = 'started';
187
+ this.emit('start:success');
188
+ } catch (err) {
189
+ this.emit('start:error', err);
190
+ throw err;
191
+ }
192
+ };
193
+
194
+ /**
195
+ * 暂停核心
196
+ * 调用 _pause 钩子,传播到子模块
197
+ * @returns {Promise<void>}
198
+ * @private
199
+ */
200
+ Mod.prototype._pauseCore = async function () {
201
+ if (this.lifecycle_state !== 'started') {
202
+ throw new Error('模块未启动,无法暂停');
203
+ }
204
+
205
+ this.emit('pause:before');
206
+
207
+ try {
208
+ var pause_hook = this.getMethod('_pause');
209
+ if (pause_hook) {
210
+ pause_hook(this);
211
+ }
212
+
213
+ this.lifecycle_state = 'paused';
214
+ this.emit('pause:success');
215
+ } catch (err) {
216
+ this.emit('pause:error', err);
217
+ throw err;
218
+ }
219
+ };
220
+
221
+ /**
222
+ * 恢复核心
223
+ * 调用 _resume 钩子,传播到子模块
224
+ * @returns {Promise<void>}
225
+ * @private
226
+ */
227
+ Mod.prototype._resumeCore = async function () {
228
+ if (this.lifecycle_state !== 'paused') {
229
+ throw new Error('模块未暂停,无法恢复');
230
+ }
231
+
232
+ this.emit('resume:before');
233
+
234
+ try {
235
+ var resume_hook = this.getMethod('_resume');
236
+ if (resume_hook) {
237
+ resume_hook(this);
238
+ }
239
+
240
+ this.lifecycle_state = 'started';
241
+ this.emit('resume:success');
242
+ } catch (err) {
243
+ this.emit('resume:error', err);
244
+ throw err;
245
+ }
246
+ };
247
+
248
+ /**
249
+ * 结束核心
250
+ * 调用 _end 钩子,传播到子模块
251
+ * @returns {Promise<void>}
252
+ * @private
253
+ */
254
+ Mod.prototype._endCore = async function () {
255
+ if (this.lifecycle_state !== 'started' && this.lifecycle_state !== 'paused') {
256
+ throw new Error('模块未启动或暂停,无法结束');
257
+ }
258
+
259
+ this.emit('end:before');
260
+
261
+ try {
262
+ var end_hook = this.getMethod('_end');
263
+ if (end_hook) {
264
+ end_hook(this);
265
+ }
266
+
267
+ this.lifecycle_state = 'ended';
268
+ this.emit('end:success');
269
+ } catch (err) {
270
+ this.emit('end:error', err);
271
+ throw err;
272
+ }
273
+ };
274
+
275
+ /**
276
+ * 销毁核心
277
+ * 调用 _onDestroy 钩子,释放引用
278
+ * @returns {Promise<void>}
279
+ * @private
280
+ */
281
+ Mod.prototype._destroyCore = async function () {
282
+ if (this.lifecycle_state !== 'ended') {
283
+ throw new Error('模块未结束,无法销毁');
284
+ }
285
+
286
+ this.emit('destroy:before');
287
+
288
+ try {
289
+ var destroy_hook = this.getMethod('_onDestroy');
290
+ if (destroy_hook) {
291
+ destroy_hook(this);
292
+ }
293
+
294
+ this._methods = {};
295
+ this._datas = {};
296
+ this.lifecycle_state = 'destroyed';
297
+ this.emit('destroy:success');
298
+ } catch (err) {
299
+ this.emit('destroy:error', err);
300
+ throw err;
301
+ }
302
+ };
303
+
304
+ // ==================== 实用方法 ====================
305
+
306
+ /**
307
+ * 检查模块是否已加载
308
+ * @returns {boolean} 是否已加载
309
+ */
310
+ Mod.prototype.isLoaded = function () {
311
+ return this.is_loaded;
312
+ };
313
+
314
+ /**
315
+ * 日志输出
316
+ * @param {string} level 日志级别
317
+ * @param {string} message 日志消息
318
+ * @param {...any} params 日志参数
319
+ */
320
+ Mod.prototype.log = function (level, message) {
321
+ var logger = this.getLogger ? this.getLogger() : console;
322
+ var prefix = '[' + (this.constructor.name || 'Mod') + '.' + ((this.config && this.config.name) || '') + ']';
323
+ if (logger[level]) {
324
+ logger[level](prefix + ' ' + message);
325
+ } else {
326
+ console.log(prefix + ' [' + level + '] ' + message);
327
+ }
328
+ };
329
+
330
+ /**
331
+ * 获取事件管理器
332
+ * @returns {object} 事件管理器
333
+ */
334
+ Mod.prototype.getEventer = function () {
335
+ return this._eventer || (typeof $.eventer !== 'undefined' ? $.eventer : this);
336
+ };
337
+
338
+ /**
339
+ * 设置事件管理器
340
+ * @param {object} eventer 事件管理器
341
+ */
342
+ Mod.prototype.setEventer = function (eventer) {
343
+ this._eventer = eventer;
344
+ };
345
+
346
+ /**
347
+ * 触发事件
348
+ * @param {string} event 事件名
349
+ * @param {...any} args 事件参数
350
+ */
351
+ Mod.prototype.emitEvent = async function (event) {
352
+ var eventer = this.getEventer();
353
+ if (eventer && eventer.emitWait) {
354
+ await eventer.emitWait(event);
355
+ } else if (eventer && eventer.emit) {
356
+ await eventer.emit(event);
357
+ } else if (this.emit) {
358
+ this.emit(event);
359
+ }
360
+ };
361
+
362
+ /**
363
+ * 触发事件 - 随机触发
364
+ * @param {string} event 事件名
365
+ * @param {...any} args 事件参数
366
+ * @returns {Promise<any>} 事件触发结果
367
+ */
368
+ Mod.prototype.emitEventRace = async function (event) {
369
+ var eventer = this.getEventer();
370
+ if (eventer && eventer.emitRace) {
371
+ return await eventer.emitRace(event);
372
+ }
373
+ return null;
374
+ };
375
+
376
+ /**
377
+ * 触发事件 - 返回第一个非空结果
378
+ * @param {string} event 事件名
379
+ * @param {...any} args 事件参数
380
+ * @returns {Promise<any>} 事件触发结果
381
+ */
382
+ Mod.prototype.emitEventFirst = async function (event) {
383
+ var eventer = this.getEventer();
384
+ if (eventer && eventer.emitFirst) {
385
+ return await eventer.emitFirst(event);
386
+ }
387
+ return null;
388
+ };
389
+
390
+ /**
391
+ * 注册事件监听
392
+ * @param {string} event 事件名
393
+ * @param {Function} callback 事件回调函数
394
+ */
395
+ Mod.prototype.onEvent = function (event, callback) {
396
+ var eventer = this.getEventer();
397
+ if (eventer && eventer.on) {
398
+ eventer.on(event, callback);
399
+ }
400
+ };
401
+
402
+ /**
403
+ * 移除事件监听
404
+ * @param {string} event 事件名
405
+ */
406
+ Mod.prototype.offEvent = function (event) {
407
+ var eventer = this.getEventer();
408
+ if (eventer && eventer.off) {
409
+ eventer.off(event);
410
+ }
411
+ };
412
+
413
+ /**
414
+ * 是否运行中
415
+ * @returns {boolean} 是否运行中
416
+ */
417
+ Mod.prototype.isRunning = function () {
418
+ return this.lifecycle_state === 'started';
419
+ };
420
+
421
+ /**
422
+ * 重载
423
+ * 记录当前状态,清除缓存,重新执行生命周期到原状态
424
+ * @returns {Promise<void>}
425
+ */
426
+ Mod.prototype.reload = async function () {
427
+ var state = this.lifecycle_state;
428
+ var priority = 0;
429
+ if (state === 'loaded') {
430
+ priority = 1;
431
+ } else if (state === 'inited') {
432
+ priority = 2;
433
+ } else if (state === 'started' || state === 'paused') {
434
+ priority = 3;
435
+ }
436
+
437
+ // 结束当前状态
438
+ if (this.lifecycle_state === 'started' || this.lifecycle_state === 'paused') {
439
+ await this._endCore();
440
+ }
441
+ if (this.lifecycle_state === 'ended') {
442
+ await this._destroyCore();
443
+ }
444
+ // 恢复为 created 以重新加载
445
+ this.lifecycle_state = 'created';
446
+
447
+ // 重新加载
448
+ if (priority >= 1) {
449
+ await this.load();
450
+ }
451
+ if (priority >= 2) {
452
+ await this.init();
453
+ }
454
+ if (priority >= 3) {
455
+ await this.start();
456
+ }
457
+ };
458
+
459
+ /**
460
+ * 重启
461
+ * started 重新执行 start
462
+ * @returns {Promise<void>}
463
+ */
464
+ Mod.prototype.restart = async function () {
465
+ if (this.lifecycle_state !== 'started') {
466
+ throw new Error('模块未启动,无法重启');
467
+ }
468
+ await this._endCore();
469
+ this.lifecycle_state = 'inited';
470
+ await this._startCore();
471
+ };
472
+
473
+ /**
474
+ * 主方法名
475
+ * @param {...any} args 方法参数
476
+ * @returns {Promise<any>} 方法执行结果
477
+ */
478
+ Mod.prototype.main = async function () {
479
+ var method = arguments[0];
480
+ var func = this.getMethod(method);
481
+ if (!func) {
482
+ throw new Error('方法 [' + method + '] 不存在');
483
+ }
484
+ var params = Array.prototype.slice.call(arguments, 1);
485
+ return await func.apply(this, params);
486
+ };
487
+
488
+ // ==================== 数据管理 ====================
489
+
490
+ /**
491
+ * 批量设置脚本方法
492
+ * @param {object} methods 脚本方法对象
493
+ */
494
+ Mod.prototype.setMethods = function (methods) {
495
+ if (typeof methods !== 'object') {
496
+ throw new Error('参数(methods)必须是对象');
497
+ }
498
+ if (!methods) return;
499
+ for (var key in methods) {
500
+ this.setMethod(key, methods[key]);
501
+ }
502
+ };
503
+
504
+ /**
505
+ * 获取数据
506
+ * @param {string} key 数据键
507
+ * @returns {*} 数据值
508
+ */
509
+ Mod.prototype.getData = function (key) {
510
+ return this[key];
511
+ };
512
+
513
+ /**
514
+ * 设置数据
515
+ * @param {string} key 数据键
516
+ * @param {*} value 数据值
517
+ */
518
+ Mod.prototype.setData = function (key, value) {
519
+ if (typeof key !== 'string') {
520
+ throw new Error('第一个参数(key)必须是字符串');
521
+ }
522
+ if (key === '_datas' || key === '_methods') {
523
+ throw new Error('key 不能为保留键');
524
+ }
525
+ if (value === undefined || value === null) {
526
+ throw new Error('第二个参数(value)不能为undefined或null');
527
+ }
528
+ if (typeof value === 'function') {
529
+ throw new Error('第二个参数(value)不能为函数');
530
+ }
531
+ this._datas[key] = typeof value;
532
+ this[key] = value;
533
+ };
534
+
535
+ /**
536
+ * 获取所有数据
537
+ * @returns {object} 数据对象
538
+ */
539
+ Mod.prototype.getDatas = function () {
540
+ var result = {};
541
+ for (var key in this._datas) {
542
+ result[key] = this[key];
543
+ }
544
+ return result;
545
+ };
546
+
547
+ /**
548
+ * 批量设置数据
549
+ * @param {object} datas 数据对象
550
+ */
551
+ Mod.prototype.setDatas = function (datas) {
552
+ if (typeof datas !== 'object') {
553
+ throw new Error('参数(datas)必须是对象');
554
+ }
555
+ if (!datas) return;
556
+ for (var key in datas) {
557
+ // eslint-disable-next-line mm_eslint/function-name
558
+ this.setData(key, datas[key]);
559
+ }
560
+ };
561
+
562
+ /**
563
+ * 保存数据到缓存文件
564
+ */
565
+ Mod.prototype.saveDatas = function () {
566
+ var fs = require('fs');
567
+ var path = require('path');
568
+ var file = (this.config && this.config.cache_file) || '';
569
+ if (!file) {
570
+ file = path.resolve(process.cwd(), 'cache', (this.config && this.config.name) || 'mod', 'data.json');
571
+ }
572
+ var dir = path.dirname(file);
573
+ if (!fs.existsSync(dir)) {
574
+ fs.mkdirSync(dir, { recursive: true });
575
+ }
576
+ var data = this.getDatas();
577
+ fs.writeFileSync(file, JSON.stringify(data, null, 2), 'utf8');
578
+ };
579
+
580
+ /**
581
+ * 从缓存文件加载数据
582
+ */
583
+ Mod.prototype.loadDatas = function () {
584
+ var fs = require('fs');
585
+ var path = require('path');
586
+ var file = (this.config && this.config.cache_file) || '';
587
+ if (!file) {
588
+ file = path.resolve(process.cwd(), 'cache', (this.config && this.config.name) || 'mod', 'data.json');
589
+ }
590
+ try {
591
+ if (fs.existsSync(file)) {
592
+ var content = fs.readFileSync(file, 'utf8');
593
+ var data = JSON.parse(content);
594
+ this.setDatas(data);
595
+ }
596
+ } catch {
597
+ // 文件不存在或解析失败
598
+ }
599
+ };
600
+
601
+ // ==================== 方法管理 ====================
602
+
603
+ /**
604
+ * 注册方法
605
+ * @param {string} name 方法名
606
+ * @param {Function} func 函数
607
+ */
608
+ Mod.prototype.setMethod = function (name, func) {
609
+ if (typeof name !== 'string') {
610
+ throw new TypeError('方法名必须是字符串');
611
+ }
612
+ if (typeof func !== 'function') {
613
+ throw new TypeError('方法必须是函数');
614
+ }
615
+ this._methods[name] = func;
616
+ this[name] = func;
617
+ };
618
+
619
+ /**
620
+ * 获取方法
621
+ * @param {string} name 方法名
622
+ * @returns {Function|null} 方法函数,不存在返回 null
623
+ */
624
+ Mod.prototype.getMethod = function (name) {
625
+ return this._methods[name] || null;
626
+ };
627
+
628
+ /**
629
+ * 删除方法
630
+ * @param {string} name 方法名
631
+ */
632
+ Mod.prototype.delMethod = function (name) {
633
+ delete this._methods[name];
634
+ };
635
+
636
+ /**
637
+ * 检查方法是否存在
638
+ * @param {string} name 方法名
639
+ * @returns {boolean} 是否存在
640
+ */
641
+ Mod.prototype.hasMethod = function (name) {
642
+ return typeof this._methods[name] === 'function';
643
+ };
644
+
645
+ /**
646
+ * 调用方法
647
+ * 检查 lifecycle_state 和 method 是否存在,使用 _callBefore/_callMain/_callAfter 钩子模式
648
+ * @param {string} name 方法名
649
+ * @param {*} [params] 参数
650
+ * @returns {Promise<*>} 方法执行结果
651
+ */
652
+ Mod.prototype.call = async function (name, params) {
653
+ var func = this.getMethod(name);
654
+ if (!func) {
655
+ return null;
656
+ }
657
+
658
+ if (this.lifecycle_state !== 'started' && this.lifecycle_state !== 'inited') {
659
+ return null;
660
+ }
661
+
662
+ var result;
663
+
664
+ try {
665
+ result = await this._callBefore(name, params);
666
+ if (result !== undefined) return result;
667
+ result = await this._callMain(func, params);
668
+ result = await this._callAfter(name, params, result);
669
+ } catch (err) {
670
+ this.log('error', '执行方法 ' + name + ' 失败: ', err);
671
+ return null;
672
+ }
673
+
674
+ return result;
675
+ };
676
+
677
+ /**
678
+ * 执行前置钩子
679
+ * 查找 methodBefore 方法并执行
680
+ * @param {string} method 方法名
681
+ * @param {*} params 参数
682
+ * @returns {Promise<*>} 前置钩子结果
683
+ * @private
684
+ */
685
+ Mod.prototype._callBefore = async function (method, params) {
686
+ var before_method = method + 'Before';
687
+ var before_func = this.getMethod(before_method);
688
+ if (typeof before_func !== 'function') return undefined;
689
+
690
+ try {
691
+ return await before_func.call(this, params);
692
+ } catch (err) {
693
+ this.log('error', '执行前置钩子 ' + before_method + ' 失败: ', err);
694
+ return undefined;
695
+ }
696
+ };
697
+
698
+ /**
699
+ * 执行主方法
700
+ * @param {Function} method_func 方法函数
701
+ * @param {*} params 参数
702
+ * @returns {Promise<*>} 主方法结果
703
+ * @private
704
+ */
705
+ Mod.prototype._callMain = async function (method_func, params) {
706
+ return await method_func.call(this, params);
707
+ };
708
+
709
+ /**
710
+ * 执行后置钩子
711
+ * 查找 methodAfter 方法并执行
712
+ * @param {string} method 方法名
713
+ * @param {*} params 参数
714
+ * @param {*} result 主方法结果
715
+ * @returns {Promise<*>} 后置钩子结果
716
+ * @private
717
+ */
718
+ Mod.prototype._callAfter = async function (method, params, result) {
719
+ var after_method = method + 'After';
720
+ var after_func = this.getMethod(after_method);
721
+ if (typeof after_func !== 'function') return result;
722
+
723
+ try {
724
+ var after = await after_func.call(this, result, params);
725
+ return after !== undefined ? after : result;
726
+ } catch (err) {
727
+ this.log('error', '执行后置钩子 ' + after_method + ' 失败: ', err);
728
+ return result;
729
+ }
730
+ };
731
+
732
+ /**
733
+ * 获取模块目录
734
+ * @returns {string} 模块目录
735
+ */
736
+ Mod.prototype.getDir = function () {
737
+ if (!this.getParent) return '';
738
+ var parent = this.getParent();
739
+ return parent ? parent.getDir() || '' : '';
740
+ };
741
+
742
+ module.exports = { Mod };