mm_machine 2.8.3 → 2.8.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.
- package/drive.js +25 -0
- package/index.js +151 -30
- 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
|
@@ -489,13 +489,13 @@ Manager.prototype.getSnapshotPath = function () {
|
|
|
489
489
|
|
|
490
490
|
/**
|
|
491
491
|
* 保存快照数据
|
|
492
|
-
* @param {object}
|
|
492
|
+
* @param {object} mods_map 目录到模块条目的映射 { dir: [{ file, config }, ...] }
|
|
493
493
|
*/
|
|
494
|
-
Manager.prototype._saveSnapshot = function (
|
|
494
|
+
Manager.prototype._saveSnapshot = function (mods_map) {
|
|
495
495
|
try {
|
|
496
496
|
var snapshot_path = this.getSnapshotPath();
|
|
497
497
|
var snapshot = {
|
|
498
|
-
|
|
498
|
+
mods_map: mods_map,
|
|
499
499
|
updated_at: Date.now()
|
|
500
500
|
};
|
|
501
501
|
snapshot_path.saveJson(snapshot);
|
|
@@ -504,6 +504,47 @@ Manager.prototype._saveSnapshot = function (files_map) {
|
|
|
504
504
|
}
|
|
505
505
|
};
|
|
506
506
|
|
|
507
|
+
/**
|
|
508
|
+
* 从当前已加载模块刷新快照
|
|
509
|
+
* 确保快照与内存中模块状态一致
|
|
510
|
+
*/
|
|
511
|
+
Manager.prototype.refreshSnapshot = function () {
|
|
512
|
+
if (!this.config.use_snapshot) {
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
var mods_map = {};
|
|
516
|
+
for (var name in this.mods) {
|
|
517
|
+
var mod = this.mods[name];
|
|
518
|
+
var f = mod.config_file;
|
|
519
|
+
if (!f) {
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
var dir = this._findSnapshotDir(f);
|
|
523
|
+
if (!mods_map[dir]) {
|
|
524
|
+
mods_map[dir] = [];
|
|
525
|
+
}
|
|
526
|
+
mods_map[dir].push({ file: f, config: mod.config });
|
|
527
|
+
}
|
|
528
|
+
this._saveSnapshot(mods_map);
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* 推断配置文件所属的快照检索目录
|
|
533
|
+
* @param {string} file 配置文件路径
|
|
534
|
+
* @returns {string} 检索目录
|
|
535
|
+
*/
|
|
536
|
+
Manager.prototype._findSnapshotDir = function (file) {
|
|
537
|
+
var base_dir = this.getBaseDir();
|
|
538
|
+
if (base_dir && file.startsWith(base_dir)) {
|
|
539
|
+
return base_dir;
|
|
540
|
+
}
|
|
541
|
+
var dir = this.getDir();
|
|
542
|
+
if (dir && file.startsWith(dir)) {
|
|
543
|
+
return dir;
|
|
544
|
+
}
|
|
545
|
+
return file.dirname();
|
|
546
|
+
};
|
|
547
|
+
|
|
507
548
|
/**
|
|
508
549
|
* 加载快照数据
|
|
509
550
|
* @returns {object|null} 快照数据,不存在时返回null
|
|
@@ -515,7 +556,7 @@ Manager.prototype._loadSnapshot = function () {
|
|
|
515
556
|
return null;
|
|
516
557
|
}
|
|
517
558
|
var snapshot = snapshot_path.loadJson();
|
|
518
|
-
if (!snapshot || !snapshot.
|
|
559
|
+
if (!snapshot || !snapshot.mods_map) {
|
|
519
560
|
return null;
|
|
520
561
|
}
|
|
521
562
|
return snapshot;
|
|
@@ -526,31 +567,68 @@ Manager.prototype._loadSnapshot = function () {
|
|
|
526
567
|
};
|
|
527
568
|
|
|
528
569
|
/**
|
|
529
|
-
*
|
|
530
|
-
*
|
|
570
|
+
* 从快照快速加载模块,不进行文件系统扫描和磁盘配置读取
|
|
571
|
+
* 使用快照中的config直接创建模块,跳过loadConfig的IO
|
|
572
|
+
* @param {object} mods_map 目录到模块条目的映射 { dir: [{ file, config }, ...] }
|
|
531
573
|
* @param {boolean} clear 是否清除已有模块
|
|
532
574
|
*/
|
|
533
|
-
Manager.prototype._loadFromSnapshot = function (
|
|
575
|
+
Manager.prototype._loadFromSnapshot = function (mods_map, clear = true) {
|
|
534
576
|
if (clear) {
|
|
535
577
|
this.clearMods();
|
|
536
578
|
}
|
|
537
|
-
for (var dir in
|
|
538
|
-
var
|
|
539
|
-
if (
|
|
540
|
-
|
|
579
|
+
for (var dir in mods_map) {
|
|
580
|
+
var entries = mods_map[dir];
|
|
581
|
+
if (!entries || entries.length === 0) {
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
for (var i = 0; i < entries.length; i++) {
|
|
585
|
+
var entry = entries[i];
|
|
586
|
+
var f = entry.file;
|
|
587
|
+
// 跳过已不存在的文件,等待后台同步处理
|
|
588
|
+
if (!f.hasFile || !f.hasFile()) {
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
this._newModFromSnap(f, entry.config);
|
|
541
592
|
}
|
|
542
593
|
}
|
|
543
594
|
this.updateInfo();
|
|
544
595
|
this.is_loaded = true;
|
|
545
596
|
};
|
|
546
597
|
|
|
598
|
+
/**
|
|
599
|
+
* 用快照config创建模块,跳过磁盘读取
|
|
600
|
+
* @param {string} file 配置文件路径
|
|
601
|
+
* @param {object} config 模块配置
|
|
602
|
+
* @returns {object} 模块对象
|
|
603
|
+
*/
|
|
604
|
+
Manager.prototype._newModFromSnap = function (file, config) {
|
|
605
|
+
var mod;
|
|
606
|
+
if (this.config.mod_type === 'script') {
|
|
607
|
+
mod = new Mod(config || {}, this);
|
|
608
|
+
} else {
|
|
609
|
+
mod = new this.Drive(config || {}, this);
|
|
610
|
+
}
|
|
611
|
+
mod.mode = this.config.mode;
|
|
612
|
+
mod.config_file = file;
|
|
613
|
+
if (mod._preset) {
|
|
614
|
+
mod._preset();
|
|
615
|
+
}
|
|
616
|
+
return this.setMod(mod.config.name, mod);
|
|
617
|
+
};
|
|
618
|
+
|
|
547
619
|
/**
|
|
548
620
|
* 后台增量同步:扫描文件系统并与快照进行diff,增减模块
|
|
621
|
+
* 使用锁防止多次重入冲突
|
|
549
622
|
* @param {object} snapshot 快照数据
|
|
550
623
|
*/
|
|
551
624
|
Manager.prototype._syncFromFile = async function (snapshot) {
|
|
625
|
+
// 防重入锁,避免多次同步同时执行
|
|
626
|
+
if (this._syncing) {
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
this._syncing = true;
|
|
552
630
|
try {
|
|
553
|
-
var old_dirs = snapshot.
|
|
631
|
+
var old_dirs = snapshot.mods_map || {};
|
|
554
632
|
var old = this._buildSet(old_dirs);
|
|
555
633
|
|
|
556
634
|
// 扫描目录并注册新模块
|
|
@@ -567,25 +645,28 @@ Manager.prototype._syncFromFile = async function (snapshot) {
|
|
|
567
645
|
}
|
|
568
646
|
|
|
569
647
|
// 移除已删除的模块
|
|
570
|
-
this._removeStale(old);
|
|
648
|
+
await this._removeStale(old);
|
|
571
649
|
this.updateInfo();
|
|
572
650
|
await this._saveSnapshotDirs(Object.keys(old_dirs));
|
|
651
|
+
this.log('info', '快照同步完成');
|
|
573
652
|
} catch (err) {
|
|
574
653
|
this.log('error', '快照增量同步失败', err);
|
|
654
|
+
} finally {
|
|
655
|
+
this._syncing = false;
|
|
575
656
|
}
|
|
576
657
|
};
|
|
577
658
|
|
|
578
659
|
/**
|
|
579
660
|
* 构建文件集合
|
|
580
|
-
* @param {object} dirs
|
|
661
|
+
* @param {object} dirs 目录到模块条目的映射 { dir: [{ file, config }, ...] }
|
|
581
662
|
* @returns {object} 文件集合 { file: true }
|
|
582
663
|
*/
|
|
583
664
|
Manager.prototype._buildSet = function (dirs) {
|
|
584
665
|
var set = {};
|
|
585
666
|
for (var dir in dirs) {
|
|
586
|
-
var
|
|
587
|
-
for (var i = 0; i <
|
|
588
|
-
set[
|
|
667
|
+
var entries = dirs[dir];
|
|
668
|
+
for (var i = 0; i < entries.length; i++) {
|
|
669
|
+
set[entries[i].file] = true;
|
|
589
670
|
}
|
|
590
671
|
}
|
|
591
672
|
return set;
|
|
@@ -595,12 +676,12 @@ Manager.prototype._buildSet = function (dirs) {
|
|
|
595
676
|
* 移除已删除的模块
|
|
596
677
|
* @param {object} old 旧文件集合,标记为false表示仍存在
|
|
597
678
|
*/
|
|
598
|
-
Manager.prototype._removeStale = function (old) {
|
|
679
|
+
Manager.prototype._removeStale = async function (old) {
|
|
599
680
|
for (var file in old) {
|
|
600
681
|
if (old[file] === true) {
|
|
601
682
|
var mod = this.getMod(file);
|
|
602
683
|
if (mod) {
|
|
603
|
-
this.unloadMod(mod.config.name);
|
|
684
|
+
await this.unloadMod(mod.config.name);
|
|
604
685
|
this.delMod(mod.config.name);
|
|
605
686
|
this.log('info', '快照同步: 移除模块 ' + file);
|
|
606
687
|
}
|
|
@@ -609,16 +690,52 @@ Manager.prototype._removeStale = function (old) {
|
|
|
609
690
|
};
|
|
610
691
|
|
|
611
692
|
/**
|
|
612
|
-
*
|
|
693
|
+
* 构建文件到config的映射
|
|
694
|
+
* @returns {object} 文件到config的映射 { file_path: config }
|
|
695
|
+
*/
|
|
696
|
+
Manager.prototype._buildConfigMap = function () {
|
|
697
|
+
var map = {};
|
|
698
|
+
var mods = this.getMods();
|
|
699
|
+
for (var name in mods) {
|
|
700
|
+
var mod = mods[name];
|
|
701
|
+
if (mod.config_file) {
|
|
702
|
+
map[mod.config_file] = mod.config;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
return map;
|
|
706
|
+
};
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* 构建模块条目列表
|
|
710
|
+
* @param {string[]} files 文件路径数组
|
|
711
|
+
* @param {object} config_dict 文件到config的映射
|
|
712
|
+
* @returns {object[]} 模块条目数组 [{ file, config }]
|
|
713
|
+
*/
|
|
714
|
+
Manager.prototype._buildEntries = function (files, config_dict) {
|
|
715
|
+
var entries = [];
|
|
716
|
+
for (var i = 0; i < files.length; i++) {
|
|
717
|
+
var f = files[i];
|
|
718
|
+
var config = config_dict[f];
|
|
719
|
+
if (config) {
|
|
720
|
+
entries.push({ file: f, config: config });
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
return entries;
|
|
724
|
+
};
|
|
725
|
+
|
|
726
|
+
/**
|
|
727
|
+
* 保存快照目录(含config)
|
|
613
728
|
* @param {string[]} dirs 目录列表
|
|
614
729
|
*/
|
|
615
730
|
Manager.prototype._saveSnapshotDirs = async function (dirs) {
|
|
616
|
-
var
|
|
731
|
+
var new_map = {};
|
|
732
|
+
var config_dict = this._buildConfigMap();
|
|
617
733
|
for (var i = 0; i < dirs.length; i++) {
|
|
618
734
|
var dir = dirs[i];
|
|
619
|
-
|
|
735
|
+
var files = await this._findFiles(dir);
|
|
736
|
+
new_map[dir] = this._buildEntries(files, config_dict);
|
|
620
737
|
}
|
|
621
|
-
this._saveSnapshot(
|
|
738
|
+
this._saveSnapshot(new_map);
|
|
622
739
|
};
|
|
623
740
|
|
|
624
741
|
/**
|
|
@@ -786,8 +903,8 @@ Manager.prototype._loadSources = async function () {
|
|
|
786
903
|
if (this.config.use_snapshot) {
|
|
787
904
|
var snapshot = this._loadSnapshot();
|
|
788
905
|
if (snapshot) {
|
|
789
|
-
//
|
|
790
|
-
this._loadFromSnapshot(snapshot.
|
|
906
|
+
// 快照存在,用config快速加载模块
|
|
907
|
+
this._loadFromSnapshot(snapshot.mods_map);
|
|
791
908
|
this.log('info', '已从快照快速加载模块,正在后台同步文件变更...');
|
|
792
909
|
// 异步增量同步,不阻塞启动
|
|
793
910
|
this._syncFromFile(snapshot);
|
|
@@ -803,14 +920,16 @@ Manager.prototype._loadSources = async function () {
|
|
|
803
920
|
await this.call('update', dir, true);
|
|
804
921
|
}
|
|
805
922
|
|
|
806
|
-
//
|
|
923
|
+
// 首次扫描后保存快照(含config)
|
|
807
924
|
if (this.config.use_snapshot) {
|
|
808
|
-
var
|
|
925
|
+
var dirs = [];
|
|
809
926
|
if (base_dir) {
|
|
810
|
-
|
|
927
|
+
dirs.push(base_dir);
|
|
928
|
+
}
|
|
929
|
+
if (dir) {
|
|
930
|
+
dirs.push(dir);
|
|
811
931
|
}
|
|
812
|
-
|
|
813
|
-
this._saveSnapshot(files_map);
|
|
932
|
+
await this._saveSnapshotDirs(dirs);
|
|
814
933
|
}
|
|
815
934
|
};
|
|
816
935
|
|
|
@@ -1148,6 +1267,7 @@ Manager.prototype.createFile = function (config, file) {
|
|
|
1148
1267
|
Manager.prototype.create = function (config, file = '') {
|
|
1149
1268
|
let f = this.createFile(config, file);
|
|
1150
1269
|
let mod = this.registerMod(f, config);
|
|
1270
|
+
this.refreshSnapshot();
|
|
1151
1271
|
return mod;
|
|
1152
1272
|
};
|
|
1153
1273
|
|
|
@@ -1162,6 +1282,7 @@ Manager.prototype.remove = async function (name) {
|
|
|
1162
1282
|
await mod.remove();
|
|
1163
1283
|
}
|
|
1164
1284
|
this.unregisterMod(name);
|
|
1285
|
+
this.refreshSnapshot();
|
|
1165
1286
|
return mod;
|
|
1166
1287
|
};
|
|
1167
1288
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mm_machine",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.4",
|
|
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": {
|