mm_machine 2.8.3 → 2.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/drive.js +25 -0
- package/index.js +164 -36
- package/package.json +1 -1
package/drive.js
CHANGED
|
@@ -135,9 +135,34 @@ Drive.prototype.setConfig = function (config) {
|
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
this._preset();
|
|
138
|
+
// 通知父级刷新快照
|
|
139
|
+
this._notifySnapshot();
|
|
138
140
|
return this.config;
|
|
139
141
|
};
|
|
140
142
|
|
|
143
|
+
/**
|
|
144
|
+
* 通知父级Manager刷新快照(防抖)
|
|
145
|
+
*/
|
|
146
|
+
Drive.prototype._notifySnapshot = function () {
|
|
147
|
+
if (!this.getParent) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
var parent = this.getParent();
|
|
151
|
+
if (!parent || !parent.config || !parent.config.use_snapshot) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
// 防抖:避免频繁写文件,500ms内只刷新一次
|
|
155
|
+
if (this._snapshot_timer) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
this._snapshot_timer = setTimeout(() => {
|
|
159
|
+
this._snapshot_timer = null;
|
|
160
|
+
if (parent.refreshSnapshot) {
|
|
161
|
+
parent.refreshSnapshot();
|
|
162
|
+
}
|
|
163
|
+
}, 500);
|
|
164
|
+
};
|
|
165
|
+
|
|
141
166
|
/**
|
|
142
167
|
* 获取配置
|
|
143
168
|
* @returns {object} 配置项
|
package/index.js
CHANGED
|
@@ -86,10 +86,10 @@ class Manager extends Mod {
|
|
|
86
86
|
*/
|
|
87
87
|
use_snapshot: true,
|
|
88
88
|
/**
|
|
89
|
-
*
|
|
89
|
+
* 快照文件路径,留空则自动生成到 cache/snapshot/ 目录下
|
|
90
90
|
* @type {string}
|
|
91
91
|
*/
|
|
92
|
-
snapshot_file: '
|
|
92
|
+
snapshot_file: ''
|
|
93
93
|
};
|
|
94
94
|
|
|
95
95
|
/**
|
|
@@ -479,23 +479,30 @@ Manager.prototype._findFiles = async function (dir) {
|
|
|
479
479
|
|
|
480
480
|
/**
|
|
481
481
|
* 获取快照文件路径
|
|
482
|
+
* 默认统一放到 /cache/snapshot/ 目录,文件名由类名+配置名组成
|
|
482
483
|
* @returns {string} 快照文件完整路径
|
|
483
484
|
*/
|
|
484
485
|
Manager.prototype.getSnapshotPath = function () {
|
|
485
|
-
var snapshot_file = this.config.snapshot_file
|
|
486
|
-
|
|
487
|
-
|
|
486
|
+
var snapshot_file = this.config.snapshot_file;
|
|
487
|
+
if (!snapshot_file) {
|
|
488
|
+
var class_name = this.constructor.name.toLowerCase();
|
|
489
|
+
var name = this.config.name || 'default';
|
|
490
|
+
snapshot_file = `./cache/snapshot/${class_name}_${name}.json`;
|
|
491
|
+
// 确保目录存在
|
|
492
|
+
snapshot_file.addDir();
|
|
493
|
+
}
|
|
494
|
+
return snapshot_file.fullname();
|
|
488
495
|
};
|
|
489
496
|
|
|
490
497
|
/**
|
|
491
498
|
* 保存快照数据
|
|
492
|
-
* @param {object}
|
|
499
|
+
* @param {object} mods_map 目录到模块条目的映射 { dir: [{ file, config }, ...] }
|
|
493
500
|
*/
|
|
494
|
-
Manager.prototype._saveSnapshot = function (
|
|
501
|
+
Manager.prototype._saveSnapshot = function (mods_map) {
|
|
495
502
|
try {
|
|
496
503
|
var snapshot_path = this.getSnapshotPath();
|
|
497
504
|
var snapshot = {
|
|
498
|
-
|
|
505
|
+
mods_map: mods_map,
|
|
499
506
|
updated_at: Date.now()
|
|
500
507
|
};
|
|
501
508
|
snapshot_path.saveJson(snapshot);
|
|
@@ -504,6 +511,47 @@ Manager.prototype._saveSnapshot = function (files_map) {
|
|
|
504
511
|
}
|
|
505
512
|
};
|
|
506
513
|
|
|
514
|
+
/**
|
|
515
|
+
* 从当前已加载模块刷新快照
|
|
516
|
+
* 确保快照与内存中模块状态一致
|
|
517
|
+
*/
|
|
518
|
+
Manager.prototype.refreshSnapshot = function () {
|
|
519
|
+
if (!this.config.use_snapshot) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
var mods_map = {};
|
|
523
|
+
for (var name in this.mods) {
|
|
524
|
+
var mod = this.mods[name];
|
|
525
|
+
var f = mod.config_file;
|
|
526
|
+
if (!f) {
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
var dir = this._findSnapshotDir(f);
|
|
530
|
+
if (!mods_map[dir]) {
|
|
531
|
+
mods_map[dir] = [];
|
|
532
|
+
}
|
|
533
|
+
mods_map[dir].push({ file: f, config: mod.config });
|
|
534
|
+
}
|
|
535
|
+
this._saveSnapshot(mods_map);
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* 推断配置文件所属的快照检索目录
|
|
540
|
+
* @param {string} file 配置文件路径
|
|
541
|
+
* @returns {string} 检索目录
|
|
542
|
+
*/
|
|
543
|
+
Manager.prototype._findSnapshotDir = function (file) {
|
|
544
|
+
var base_dir = this.getBaseDir();
|
|
545
|
+
if (base_dir && file.startsWith(base_dir)) {
|
|
546
|
+
return base_dir;
|
|
547
|
+
}
|
|
548
|
+
var dir = this.getDir();
|
|
549
|
+
if (dir && file.startsWith(dir)) {
|
|
550
|
+
return dir;
|
|
551
|
+
}
|
|
552
|
+
return file.dirname();
|
|
553
|
+
};
|
|
554
|
+
|
|
507
555
|
/**
|
|
508
556
|
* 加载快照数据
|
|
509
557
|
* @returns {object|null} 快照数据,不存在时返回null
|
|
@@ -515,7 +563,7 @@ Manager.prototype._loadSnapshot = function () {
|
|
|
515
563
|
return null;
|
|
516
564
|
}
|
|
517
565
|
var snapshot = snapshot_path.loadJson();
|
|
518
|
-
if (!snapshot || !snapshot.
|
|
566
|
+
if (!snapshot || !snapshot.mods_map) {
|
|
519
567
|
return null;
|
|
520
568
|
}
|
|
521
569
|
return snapshot;
|
|
@@ -526,31 +574,68 @@ Manager.prototype._loadSnapshot = function () {
|
|
|
526
574
|
};
|
|
527
575
|
|
|
528
576
|
/**
|
|
529
|
-
*
|
|
530
|
-
*
|
|
577
|
+
* 从快照快速加载模块,不进行文件系统扫描和磁盘配置读取
|
|
578
|
+
* 使用快照中的config直接创建模块,跳过loadConfig的IO
|
|
579
|
+
* @param {object} mods_map 目录到模块条目的映射 { dir: [{ file, config }, ...] }
|
|
531
580
|
* @param {boolean} clear 是否清除已有模块
|
|
532
581
|
*/
|
|
533
|
-
Manager.prototype._loadFromSnapshot = function (
|
|
582
|
+
Manager.prototype._loadFromSnapshot = function (mods_map, clear = true) {
|
|
534
583
|
if (clear) {
|
|
535
584
|
this.clearMods();
|
|
536
585
|
}
|
|
537
|
-
for (var dir in
|
|
538
|
-
var
|
|
539
|
-
if (
|
|
540
|
-
|
|
586
|
+
for (var dir in mods_map) {
|
|
587
|
+
var entries = mods_map[dir];
|
|
588
|
+
if (!entries || entries.length === 0) {
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
for (var i = 0; i < entries.length; i++) {
|
|
592
|
+
var entry = entries[i];
|
|
593
|
+
var f = entry.file;
|
|
594
|
+
// 跳过已不存在的文件,等待后台同步处理
|
|
595
|
+
if (!f.hasFile || !f.hasFile()) {
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
this._newModFromSnap(f, entry.config);
|
|
541
599
|
}
|
|
542
600
|
}
|
|
543
601
|
this.updateInfo();
|
|
544
602
|
this.is_loaded = true;
|
|
545
603
|
};
|
|
546
604
|
|
|
605
|
+
/**
|
|
606
|
+
* 用快照config创建模块,跳过磁盘读取
|
|
607
|
+
* @param {string} file 配置文件路径
|
|
608
|
+
* @param {object} config 模块配置
|
|
609
|
+
* @returns {object} 模块对象
|
|
610
|
+
*/
|
|
611
|
+
Manager.prototype._newModFromSnap = function (file, config) {
|
|
612
|
+
var mod;
|
|
613
|
+
if (this.config.mod_type === 'script') {
|
|
614
|
+
mod = new Mod(config || {}, this);
|
|
615
|
+
} else {
|
|
616
|
+
mod = new this.Drive(config || {}, this);
|
|
617
|
+
}
|
|
618
|
+
mod.mode = this.config.mode;
|
|
619
|
+
mod.config_file = file;
|
|
620
|
+
if (mod._preset) {
|
|
621
|
+
mod._preset();
|
|
622
|
+
}
|
|
623
|
+
return this.setMod(mod.config.name, mod);
|
|
624
|
+
};
|
|
625
|
+
|
|
547
626
|
/**
|
|
548
627
|
* 后台增量同步:扫描文件系统并与快照进行diff,增减模块
|
|
628
|
+
* 使用锁防止多次重入冲突
|
|
549
629
|
* @param {object} snapshot 快照数据
|
|
550
630
|
*/
|
|
551
631
|
Manager.prototype._syncFromFile = async function (snapshot) {
|
|
632
|
+
// 防重入锁,避免多次同步同时执行
|
|
633
|
+
if (this._syncing) {
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
this._syncing = true;
|
|
552
637
|
try {
|
|
553
|
-
var old_dirs = snapshot.
|
|
638
|
+
var old_dirs = snapshot.mods_map || {};
|
|
554
639
|
var old = this._buildSet(old_dirs);
|
|
555
640
|
|
|
556
641
|
// 扫描目录并注册新模块
|
|
@@ -567,25 +652,28 @@ Manager.prototype._syncFromFile = async function (snapshot) {
|
|
|
567
652
|
}
|
|
568
653
|
|
|
569
654
|
// 移除已删除的模块
|
|
570
|
-
this._removeStale(old);
|
|
655
|
+
await this._removeStale(old);
|
|
571
656
|
this.updateInfo();
|
|
572
657
|
await this._saveSnapshotDirs(Object.keys(old_dirs));
|
|
658
|
+
this.log('info', '快照同步完成');
|
|
573
659
|
} catch (err) {
|
|
574
660
|
this.log('error', '快照增量同步失败', err);
|
|
661
|
+
} finally {
|
|
662
|
+
this._syncing = false;
|
|
575
663
|
}
|
|
576
664
|
};
|
|
577
665
|
|
|
578
666
|
/**
|
|
579
667
|
* 构建文件集合
|
|
580
|
-
* @param {object} dirs
|
|
668
|
+
* @param {object} dirs 目录到模块条目的映射 { dir: [{ file, config }, ...] }
|
|
581
669
|
* @returns {object} 文件集合 { file: true }
|
|
582
670
|
*/
|
|
583
671
|
Manager.prototype._buildSet = function (dirs) {
|
|
584
672
|
var set = {};
|
|
585
673
|
for (var dir in dirs) {
|
|
586
|
-
var
|
|
587
|
-
for (var i = 0; i <
|
|
588
|
-
set[
|
|
674
|
+
var entries = dirs[dir];
|
|
675
|
+
for (var i = 0; i < entries.length; i++) {
|
|
676
|
+
set[entries[i].file] = true;
|
|
589
677
|
}
|
|
590
678
|
}
|
|
591
679
|
return set;
|
|
@@ -595,12 +683,12 @@ Manager.prototype._buildSet = function (dirs) {
|
|
|
595
683
|
* 移除已删除的模块
|
|
596
684
|
* @param {object} old 旧文件集合,标记为false表示仍存在
|
|
597
685
|
*/
|
|
598
|
-
Manager.prototype._removeStale = function (old) {
|
|
686
|
+
Manager.prototype._removeStale = async function (old) {
|
|
599
687
|
for (var file in old) {
|
|
600
688
|
if (old[file] === true) {
|
|
601
689
|
var mod = this.getMod(file);
|
|
602
690
|
if (mod) {
|
|
603
|
-
this.unloadMod(mod.config.name);
|
|
691
|
+
await this.unloadMod(mod.config.name);
|
|
604
692
|
this.delMod(mod.config.name);
|
|
605
693
|
this.log('info', '快照同步: 移除模块 ' + file);
|
|
606
694
|
}
|
|
@@ -609,16 +697,52 @@ Manager.prototype._removeStale = function (old) {
|
|
|
609
697
|
};
|
|
610
698
|
|
|
611
699
|
/**
|
|
612
|
-
*
|
|
700
|
+
* 构建文件到config的映射
|
|
701
|
+
* @returns {object} 文件到config的映射 { file_path: config }
|
|
702
|
+
*/
|
|
703
|
+
Manager.prototype._buildConfigMap = function () {
|
|
704
|
+
var map = {};
|
|
705
|
+
var mods = this.getMods();
|
|
706
|
+
for (var name in mods) {
|
|
707
|
+
var mod = mods[name];
|
|
708
|
+
if (mod.config_file) {
|
|
709
|
+
map[mod.config_file] = mod.config;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return map;
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* 构建模块条目列表
|
|
717
|
+
* @param {string[]} files 文件路径数组
|
|
718
|
+
* @param {object} config_dict 文件到config的映射
|
|
719
|
+
* @returns {object[]} 模块条目数组 [{ file, config }]
|
|
720
|
+
*/
|
|
721
|
+
Manager.prototype._buildEntries = function (files, config_dict) {
|
|
722
|
+
var entries = [];
|
|
723
|
+
for (var i = 0; i < files.length; i++) {
|
|
724
|
+
var f = files[i];
|
|
725
|
+
var config = config_dict[f];
|
|
726
|
+
if (config) {
|
|
727
|
+
entries.push({ file: f, config: config });
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
return entries;
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* 保存快照目录(含config)
|
|
613
735
|
* @param {string[]} dirs 目录列表
|
|
614
736
|
*/
|
|
615
737
|
Manager.prototype._saveSnapshotDirs = async function (dirs) {
|
|
616
|
-
var
|
|
738
|
+
var new_map = {};
|
|
739
|
+
var config_dict = this._buildConfigMap();
|
|
617
740
|
for (var i = 0; i < dirs.length; i++) {
|
|
618
741
|
var dir = dirs[i];
|
|
619
|
-
|
|
742
|
+
var files = await this._findFiles(dir);
|
|
743
|
+
new_map[dir] = this._buildEntries(files, config_dict);
|
|
620
744
|
}
|
|
621
|
-
this._saveSnapshot(
|
|
745
|
+
this._saveSnapshot(new_map);
|
|
622
746
|
};
|
|
623
747
|
|
|
624
748
|
/**
|
|
@@ -757,7 +881,7 @@ Manager.prototype._runMod = async function (mod, method, ...params) {
|
|
|
757
881
|
/**
|
|
758
882
|
* 初始化管理器
|
|
759
883
|
*/
|
|
760
|
-
Manager.prototype._initManager = function () {};
|
|
884
|
+
Manager.prototype._initManager = function () { };
|
|
761
885
|
|
|
762
886
|
/**
|
|
763
887
|
* 获取公共模块目录
|
|
@@ -786,8 +910,8 @@ Manager.prototype._loadSources = async function () {
|
|
|
786
910
|
if (this.config.use_snapshot) {
|
|
787
911
|
var snapshot = this._loadSnapshot();
|
|
788
912
|
if (snapshot) {
|
|
789
|
-
//
|
|
790
|
-
this._loadFromSnapshot(snapshot.
|
|
913
|
+
// 快照存在,用config快速加载模块
|
|
914
|
+
this._loadFromSnapshot(snapshot.mods_map);
|
|
791
915
|
this.log('info', '已从快照快速加载模块,正在后台同步文件变更...');
|
|
792
916
|
// 异步增量同步,不阻塞启动
|
|
793
917
|
this._syncFromFile(snapshot);
|
|
@@ -803,14 +927,16 @@ Manager.prototype._loadSources = async function () {
|
|
|
803
927
|
await this.call('update', dir, true);
|
|
804
928
|
}
|
|
805
929
|
|
|
806
|
-
//
|
|
930
|
+
// 首次扫描后保存快照(含config)
|
|
807
931
|
if (this.config.use_snapshot) {
|
|
808
|
-
var
|
|
932
|
+
var dirs = [];
|
|
809
933
|
if (base_dir) {
|
|
810
|
-
|
|
934
|
+
dirs.push(base_dir);
|
|
935
|
+
}
|
|
936
|
+
if (dir) {
|
|
937
|
+
dirs.push(dir);
|
|
811
938
|
}
|
|
812
|
-
|
|
813
|
-
this._saveSnapshot(files_map);
|
|
939
|
+
await this._saveSnapshotDirs(dirs);
|
|
814
940
|
}
|
|
815
941
|
};
|
|
816
942
|
|
|
@@ -1148,6 +1274,7 @@ Manager.prototype.createFile = function (config, file) {
|
|
|
1148
1274
|
Manager.prototype.create = function (config, file = '') {
|
|
1149
1275
|
let f = this.createFile(config, file);
|
|
1150
1276
|
let mod = this.registerMod(f, config);
|
|
1277
|
+
this.refreshSnapshot();
|
|
1151
1278
|
return mod;
|
|
1152
1279
|
};
|
|
1153
1280
|
|
|
@@ -1162,6 +1289,7 @@ Manager.prototype.remove = async function (name) {
|
|
|
1162
1289
|
await mod.remove();
|
|
1163
1290
|
}
|
|
1164
1291
|
this.unregisterMod(name);
|
|
1292
|
+
this.refreshSnapshot();
|
|
1165
1293
|
return mod;
|
|
1166
1294
|
};
|
|
1167
1295
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mm_machine",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.5",
|
|
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": {
|