mm_machine 2.8.1 → 2.8.2

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 (2) hide show
  1. package/index.js +189 -21
  2. package/package.json +4 -4
package/index.js CHANGED
@@ -79,7 +79,17 @@ class Manager extends Mod {
79
79
  * 作用域
80
80
  * @type {string}
81
81
  */
82
- scope: $.val && $.val.scope ? $.val.scope + '' : 'server'
82
+ scope: $.val && $.val.scope ? $.val.scope + '' : 'server',
83
+ /**
84
+ * 是否启用快照加速
85
+ * @type {boolean}
86
+ */
87
+ use_snapshot: true,
88
+ /**
89
+ * 快照文件路径
90
+ * @type {string}
91
+ */
92
+ snapshot_file: './snapshot.json'
83
93
  };
84
94
 
85
95
  /**
@@ -102,8 +112,6 @@ class Manager extends Mod {
102
112
  this.infos = [];
103
113
  // 模块
104
114
  this.mods = mods;
105
- // getList 缓存
106
- this._list_cache = null;
107
115
  if (Drive) {
108
116
  this.Drive = Drive;
109
117
  }
@@ -156,7 +164,6 @@ Manager.prototype.newInfo = function (name, sort, state, file = '') {
156
164
  * @param {object} info 模块信息
157
165
  */
158
166
  Manager.prototype.setInfo = function (info) {
159
- this._list_cache = null;
160
167
  let has = false;
161
168
  for (let i = 0; i < this.infos.length; i++) {
162
169
  let o = this.infos[i];
@@ -176,17 +183,15 @@ Manager.prototype.setInfo = function (info) {
176
183
  * @returns {object[]} 模块对象数组
177
184
  */
178
185
  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);
186
+ let list = [];
187
+ for (let i = 0; i < this.infos.length; i++) {
188
+ let info = this.infos[i];
189
+ let mod = this.getMod(info.name);
184
190
  if (mod) {
185
191
  mod.config.state = info.state;
186
192
  }
187
193
  list.push(mod);
188
194
  }
189
- this._list_cache = list;
190
195
  return list;
191
196
  };
192
197
 
@@ -215,7 +220,6 @@ Manager.prototype.Drive = Drive;
215
220
  * 更新模块信息
216
221
  */
217
222
  Manager.prototype.updateInfo = function () {
218
- this._list_cache = null;
219
223
  this.infos = [];
220
224
  let mods = this.getMods();
221
225
  for (let name in mods) {
@@ -242,7 +246,6 @@ Manager.prototype._sort = function () {
242
246
  * 排序
243
247
  */
244
248
  Manager.prototype.sort = function () {
245
- this._list_cache = null;
246
249
  this._sort();
247
250
  };
248
251
 
@@ -251,7 +254,6 @@ Manager.prototype.sort = function () {
251
254
  * 清除所有模块
252
255
  */
253
256
  Manager.prototype.clearMods = function () {
254
- this._list_cache = null;
255
257
  for (let name in this.mods) {
256
258
  delete this.mods[name];
257
259
  }
@@ -263,7 +265,6 @@ Manager.prototype.clearMods = function () {
263
265
  * @returns {object|null} 删除的模块对象
264
266
  */
265
267
  Manager.prototype.delMod = function (name) {
266
- this._list_cache = null;
267
268
  let mod = this.mods[name];
268
269
  if (mod) {
269
270
  delete this.mods[name];
@@ -278,7 +279,6 @@ Manager.prototype.delMod = function (name) {
278
279
  * @returns {object|null} 设置的模块对象
279
280
  */
280
281
  Manager.prototype.setMod = function (name, mod) {
281
- this._list_cache = null;
282
282
  this.mods[name] = mod;
283
283
  return this.getMod(name);
284
284
  };
@@ -477,6 +477,149 @@ Manager.prototype._findFiles = async function (dir) {
477
477
  return await $.file.getAllAsync(dir, this.config.filename);
478
478
  };
479
479
 
480
+ /**
481
+ * 获取快照文件路径
482
+ * @returns {string} 快照文件完整路径
483
+ */
484
+ Manager.prototype.getSnapshotPath = function () {
485
+ var snapshot_file = this.config.snapshot_file || './snapshot.json';
486
+ return snapshot_file.fullname(__dirname);
487
+ };
488
+
489
+ /**
490
+ * 保存快照数据
491
+ * @param {object} files_map 目录到文件列表的映射 { dir: [file_path, ...] }
492
+ */
493
+ Manager.prototype._saveSnapshot = function (files_map) {
494
+ try {
495
+ var snapshot_path = this.getSnapshotPath();
496
+ var snapshot = {
497
+ files_map: files_map,
498
+ updated_at: Date.now()
499
+ };
500
+ snapshot_path.saveJson(snapshot);
501
+ } catch (err) {
502
+ this.log('error', '保存快照失败', err);
503
+ }
504
+ };
505
+
506
+ /**
507
+ * 加载快照数据
508
+ * @returns {object|null} 快照数据,不存在时返回null
509
+ */
510
+ Manager.prototype._loadSnapshot = function () {
511
+ try {
512
+ var snapshot_path = this.getSnapshotPath();
513
+ if (!snapshot_path.hasFile()) {
514
+ return null;
515
+ }
516
+ var snapshot = snapshot_path.loadJson();
517
+ if (!snapshot || !snapshot.files_map) {
518
+ return null;
519
+ }
520
+ return snapshot;
521
+ } catch (err) {
522
+ this.log('error', '加载快照失败', err);
523
+ return null;
524
+ }
525
+ };
526
+
527
+ /**
528
+ * 从快照快速加载模块,不进行文件系统扫描
529
+ * @param {object} files_map 目录到文件列表的映射
530
+ * @param {boolean} clear 是否清除已有模块
531
+ */
532
+ Manager.prototype._loadFromSnapshot = function (files_map, clear = true) {
533
+ if (clear) {
534
+ this.clearMods();
535
+ }
536
+ for (var dir in files_map) {
537
+ var files = files_map[dir];
538
+ if (files && files.length > 0) {
539
+ this.registerMods(files);
540
+ }
541
+ }
542
+ this.updateInfo();
543
+ this.is_loaded = true;
544
+ };
545
+
546
+ /**
547
+ * 后台增量同步:扫描文件系统并与快照进行diff,增减模块
548
+ * @param {object} snapshot 快照数据
549
+ */
550
+ Manager.prototype._syncFromFile = async function (snapshot) {
551
+ try {
552
+ var old_dirs = snapshot.files_map || {};
553
+ var old = this._buildSet(old_dirs);
554
+
555
+ // 扫描目录并注册新模块
556
+ for (var dir in old_dirs) {
557
+ var current = await this._findFiles(dir);
558
+ for (var fi = 0; fi < current.length; fi++) {
559
+ var f = current[fi];
560
+ if (!old[f]) {
561
+ this.registerMod(f);
562
+ this.log('info', '快照同步: 新增模块 ' + f);
563
+ }
564
+ old[f] = false;
565
+ }
566
+ }
567
+
568
+ // 移除已删除的模块
569
+ this._removeStale(old);
570
+ this.updateInfo();
571
+ await this._saveSnapshotDirs(Object.keys(old_dirs));
572
+ } catch (err) {
573
+ this.log('error', '快照增量同步失败', err);
574
+ }
575
+ };
576
+
577
+ /**
578
+ * 构建文件集合
579
+ * @param {object} dirs 目录到文件列表的映射
580
+ * @returns {object} 文件集合 { file: true }
581
+ */
582
+ Manager.prototype._buildSet = function (dirs) {
583
+ var set = {};
584
+ for (var dir in dirs) {
585
+ var files = dirs[dir];
586
+ for (var i = 0; i < files.length; i++) {
587
+ set[files[i]] = true;
588
+ }
589
+ }
590
+ return set;
591
+ };
592
+
593
+ /**
594
+ * 移除已删除的模块
595
+ * @param {object} old 旧文件集合,标记为false表示仍存在
596
+ */
597
+ Manager.prototype._removeStale = function (old) {
598
+ for (var file in old) {
599
+ if (old[file] === true) {
600
+ var mod = this.getMod(file);
601
+ if (mod) {
602
+ this.unloadMod(mod.config.name);
603
+ this.delMod(mod.config.name);
604
+ this.log('info', '快照同步: 移除模块 ' + file);
605
+ }
606
+ }
607
+ }
608
+ };
609
+
610
+ /**
611
+ * 保存快照目录
612
+ * @param {string[]} dirs 目录列表
613
+ */
614
+ Manager.prototype._saveSnapshotDirs = async function (dirs) {
615
+ var new_dirs = {};
616
+ for (var i = 0; i < dirs.length; i++) {
617
+ var dir = dirs[i];
618
+ new_dirs[dir] = await this._findFiles(dir);
619
+ }
620
+ this._saveSnapshot(new_dirs);
621
+ };
622
+
480
623
  /**
481
624
  * 加载所有模块的脚本
482
625
  */
@@ -514,8 +657,9 @@ Manager.prototype.update = async function (dir, clear = true) {
514
657
  this.clearMods();
515
658
  }
516
659
 
660
+ var search_dir = dir || this.config.dir;
517
661
  // 查找所有json文件
518
- let files = await this._findFiles(dir || this.config.dir);
662
+ var files = await this._findFiles(search_dir);
519
663
  // 批量注册模块
520
664
  this.registerMods(files);
521
665
  // 更新配置信息
@@ -634,14 +778,38 @@ Manager.prototype.getDir = function () {
634
778
  * 加载资源
635
779
  */
636
780
  Manager.prototype._loadSources = async function () {
637
- // 通过更新函数加载资源信息
638
- let base_dir = this.getBaseDir();
639
- let dir = this.getDir();
781
+ var base_dir = this.getBaseDir();
782
+ var dir = this.getDir();
783
+
784
+ // 启用快照加速时,优先从快照加载
785
+ if (this.config.use_snapshot) {
786
+ var snapshot = this._loadSnapshot();
787
+ if (snapshot) {
788
+ // 快照存在,快速加载模块
789
+ this._loadFromSnapshot(snapshot.files_map);
790
+ this.log('info', '已从快照快速加载模块,正在后台同步文件变更...');
791
+ // 异步增量同步,不阻塞启动
792
+ this._syncFromFile(snapshot);
793
+ return;
794
+ }
795
+ }
796
+
797
+ // 无快照时走正常流程
640
798
  if (base_dir) {
641
- await this.call('update', base_dir);
799
+ await this.call('update', base_dir, true);
642
800
  await this.call('update', dir, false);
643
801
  } else {
644
- await this.call('update', dir);
802
+ await this.call('update', dir, true);
803
+ }
804
+
805
+ // 首次扫描后保存快照
806
+ if (this.config.use_snapshot) {
807
+ var files_map = {};
808
+ if (base_dir) {
809
+ files_map[base_dir] = await this._findFiles(base_dir);
810
+ }
811
+ files_map[dir] = await this._findFiles(dir);
812
+ this._saveSnapshot(files_map);
645
813
  }
646
814
  };
647
815
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mm_machine",
3
- "version": "2.8.1",
3
+ "version": "2.8.2",
4
4
  "description": "A flexible Node.js plugin mechanism system for dynamic loading, management and execution of modules. Supports hot reload, lifecycle management, and modern JavaScript features.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -34,9 +34,9 @@
34
34
  ],
35
35
  "dependencies": {
36
36
  "@prettier/sync": "^0.6.1",
37
- "mm_config": "^2.4.2",
38
- "mm_hot_reload": "^1.3.9",
39
- "mm_tpl": "^2.6.1"
37
+ "mm_config": "^2.4.3",
38
+ "mm_hot_reload": "^1.4.0",
39
+ "mm_tpl": "^2.6.2"
40
40
  },
41
41
  "devDependencies": {
42
42
  "eslint": "^10.6.0",