mm_machine 2.8.2 → 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 +153 -31
- 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
|
@@ -483,18 +483,19 @@ Manager.prototype._findFiles = async function (dir) {
|
|
|
483
483
|
*/
|
|
484
484
|
Manager.prototype.getSnapshotPath = function () {
|
|
485
485
|
var snapshot_file = this.config.snapshot_file || './snapshot.json';
|
|
486
|
-
|
|
486
|
+
let dir = this.getBaseDir();
|
|
487
|
+
return snapshot_file.fullname(dir);
|
|
487
488
|
};
|
|
488
489
|
|
|
489
490
|
/**
|
|
490
491
|
* 保存快照数据
|
|
491
|
-
* @param {object}
|
|
492
|
+
* @param {object} mods_map 目录到模块条目的映射 { dir: [{ file, config }, ...] }
|
|
492
493
|
*/
|
|
493
|
-
Manager.prototype._saveSnapshot = function (
|
|
494
|
+
Manager.prototype._saveSnapshot = function (mods_map) {
|
|
494
495
|
try {
|
|
495
496
|
var snapshot_path = this.getSnapshotPath();
|
|
496
497
|
var snapshot = {
|
|
497
|
-
|
|
498
|
+
mods_map: mods_map,
|
|
498
499
|
updated_at: Date.now()
|
|
499
500
|
};
|
|
500
501
|
snapshot_path.saveJson(snapshot);
|
|
@@ -503,6 +504,47 @@ Manager.prototype._saveSnapshot = function (files_map) {
|
|
|
503
504
|
}
|
|
504
505
|
};
|
|
505
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
|
+
|
|
506
548
|
/**
|
|
507
549
|
* 加载快照数据
|
|
508
550
|
* @returns {object|null} 快照数据,不存在时返回null
|
|
@@ -514,7 +556,7 @@ Manager.prototype._loadSnapshot = function () {
|
|
|
514
556
|
return null;
|
|
515
557
|
}
|
|
516
558
|
var snapshot = snapshot_path.loadJson();
|
|
517
|
-
if (!snapshot || !snapshot.
|
|
559
|
+
if (!snapshot || !snapshot.mods_map) {
|
|
518
560
|
return null;
|
|
519
561
|
}
|
|
520
562
|
return snapshot;
|
|
@@ -525,31 +567,68 @@ Manager.prototype._loadSnapshot = function () {
|
|
|
525
567
|
};
|
|
526
568
|
|
|
527
569
|
/**
|
|
528
|
-
*
|
|
529
|
-
*
|
|
570
|
+
* 从快照快速加载模块,不进行文件系统扫描和磁盘配置读取
|
|
571
|
+
* 使用快照中的config直接创建模块,跳过loadConfig的IO
|
|
572
|
+
* @param {object} mods_map 目录到模块条目的映射 { dir: [{ file, config }, ...] }
|
|
530
573
|
* @param {boolean} clear 是否清除已有模块
|
|
531
574
|
*/
|
|
532
|
-
Manager.prototype._loadFromSnapshot = function (
|
|
575
|
+
Manager.prototype._loadFromSnapshot = function (mods_map, clear = true) {
|
|
533
576
|
if (clear) {
|
|
534
577
|
this.clearMods();
|
|
535
578
|
}
|
|
536
|
-
for (var dir in
|
|
537
|
-
var
|
|
538
|
-
if (
|
|
539
|
-
|
|
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);
|
|
540
592
|
}
|
|
541
593
|
}
|
|
542
594
|
this.updateInfo();
|
|
543
595
|
this.is_loaded = true;
|
|
544
596
|
};
|
|
545
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
|
+
|
|
546
619
|
/**
|
|
547
620
|
* 后台增量同步:扫描文件系统并与快照进行diff,增减模块
|
|
621
|
+
* 使用锁防止多次重入冲突
|
|
548
622
|
* @param {object} snapshot 快照数据
|
|
549
623
|
*/
|
|
550
624
|
Manager.prototype._syncFromFile = async function (snapshot) {
|
|
625
|
+
// 防重入锁,避免多次同步同时执行
|
|
626
|
+
if (this._syncing) {
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
this._syncing = true;
|
|
551
630
|
try {
|
|
552
|
-
var old_dirs = snapshot.
|
|
631
|
+
var old_dirs = snapshot.mods_map || {};
|
|
553
632
|
var old = this._buildSet(old_dirs);
|
|
554
633
|
|
|
555
634
|
// 扫描目录并注册新模块
|
|
@@ -566,25 +645,28 @@ Manager.prototype._syncFromFile = async function (snapshot) {
|
|
|
566
645
|
}
|
|
567
646
|
|
|
568
647
|
// 移除已删除的模块
|
|
569
|
-
this._removeStale(old);
|
|
648
|
+
await this._removeStale(old);
|
|
570
649
|
this.updateInfo();
|
|
571
650
|
await this._saveSnapshotDirs(Object.keys(old_dirs));
|
|
651
|
+
this.log('info', '快照同步完成');
|
|
572
652
|
} catch (err) {
|
|
573
653
|
this.log('error', '快照增量同步失败', err);
|
|
654
|
+
} finally {
|
|
655
|
+
this._syncing = false;
|
|
574
656
|
}
|
|
575
657
|
};
|
|
576
658
|
|
|
577
659
|
/**
|
|
578
660
|
* 构建文件集合
|
|
579
|
-
* @param {object} dirs
|
|
661
|
+
* @param {object} dirs 目录到模块条目的映射 { dir: [{ file, config }, ...] }
|
|
580
662
|
* @returns {object} 文件集合 { file: true }
|
|
581
663
|
*/
|
|
582
664
|
Manager.prototype._buildSet = function (dirs) {
|
|
583
665
|
var set = {};
|
|
584
666
|
for (var dir in dirs) {
|
|
585
|
-
var
|
|
586
|
-
for (var i = 0; i <
|
|
587
|
-
set[
|
|
667
|
+
var entries = dirs[dir];
|
|
668
|
+
for (var i = 0; i < entries.length; i++) {
|
|
669
|
+
set[entries[i].file] = true;
|
|
588
670
|
}
|
|
589
671
|
}
|
|
590
672
|
return set;
|
|
@@ -594,12 +676,12 @@ Manager.prototype._buildSet = function (dirs) {
|
|
|
594
676
|
* 移除已删除的模块
|
|
595
677
|
* @param {object} old 旧文件集合,标记为false表示仍存在
|
|
596
678
|
*/
|
|
597
|
-
Manager.prototype._removeStale = function (old) {
|
|
679
|
+
Manager.prototype._removeStale = async function (old) {
|
|
598
680
|
for (var file in old) {
|
|
599
681
|
if (old[file] === true) {
|
|
600
682
|
var mod = this.getMod(file);
|
|
601
683
|
if (mod) {
|
|
602
|
-
this.unloadMod(mod.config.name);
|
|
684
|
+
await this.unloadMod(mod.config.name);
|
|
603
685
|
this.delMod(mod.config.name);
|
|
604
686
|
this.log('info', '快照同步: 移除模块 ' + file);
|
|
605
687
|
}
|
|
@@ -608,16 +690,52 @@ Manager.prototype._removeStale = function (old) {
|
|
|
608
690
|
};
|
|
609
691
|
|
|
610
692
|
/**
|
|
611
|
-
*
|
|
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)
|
|
612
728
|
* @param {string[]} dirs 目录列表
|
|
613
729
|
*/
|
|
614
730
|
Manager.prototype._saveSnapshotDirs = async function (dirs) {
|
|
615
|
-
var
|
|
731
|
+
var new_map = {};
|
|
732
|
+
var config_dict = this._buildConfigMap();
|
|
616
733
|
for (var i = 0; i < dirs.length; i++) {
|
|
617
734
|
var dir = dirs[i];
|
|
618
|
-
|
|
735
|
+
var files = await this._findFiles(dir);
|
|
736
|
+
new_map[dir] = this._buildEntries(files, config_dict);
|
|
619
737
|
}
|
|
620
|
-
this._saveSnapshot(
|
|
738
|
+
this._saveSnapshot(new_map);
|
|
621
739
|
};
|
|
622
740
|
|
|
623
741
|
/**
|
|
@@ -785,8 +903,8 @@ Manager.prototype._loadSources = async function () {
|
|
|
785
903
|
if (this.config.use_snapshot) {
|
|
786
904
|
var snapshot = this._loadSnapshot();
|
|
787
905
|
if (snapshot) {
|
|
788
|
-
//
|
|
789
|
-
this._loadFromSnapshot(snapshot.
|
|
906
|
+
// 快照存在,用config快速加载模块
|
|
907
|
+
this._loadFromSnapshot(snapshot.mods_map);
|
|
790
908
|
this.log('info', '已从快照快速加载模块,正在后台同步文件变更...');
|
|
791
909
|
// 异步增量同步,不阻塞启动
|
|
792
910
|
this._syncFromFile(snapshot);
|
|
@@ -802,14 +920,16 @@ Manager.prototype._loadSources = async function () {
|
|
|
802
920
|
await this.call('update', dir, true);
|
|
803
921
|
}
|
|
804
922
|
|
|
805
|
-
//
|
|
923
|
+
// 首次扫描后保存快照(含config)
|
|
806
924
|
if (this.config.use_snapshot) {
|
|
807
|
-
var
|
|
925
|
+
var dirs = [];
|
|
808
926
|
if (base_dir) {
|
|
809
|
-
|
|
927
|
+
dirs.push(base_dir);
|
|
928
|
+
}
|
|
929
|
+
if (dir) {
|
|
930
|
+
dirs.push(dir);
|
|
810
931
|
}
|
|
811
|
-
|
|
812
|
-
this._saveSnapshot(files_map);
|
|
932
|
+
await this._saveSnapshotDirs(dirs);
|
|
813
933
|
}
|
|
814
934
|
};
|
|
815
935
|
|
|
@@ -1147,6 +1267,7 @@ Manager.prototype.createFile = function (config, file) {
|
|
|
1147
1267
|
Manager.prototype.create = function (config, file = '') {
|
|
1148
1268
|
let f = this.createFile(config, file);
|
|
1149
1269
|
let mod = this.registerMod(f, config);
|
|
1270
|
+
this.refreshSnapshot();
|
|
1150
1271
|
return mod;
|
|
1151
1272
|
};
|
|
1152
1273
|
|
|
@@ -1161,6 +1282,7 @@ Manager.prototype.remove = async function (name) {
|
|
|
1161
1282
|
await mod.remove();
|
|
1162
1283
|
}
|
|
1163
1284
|
this.unregisterMod(name);
|
|
1285
|
+
this.refreshSnapshot();
|
|
1164
1286
|
return mod;
|
|
1165
1287
|
};
|
|
1166
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": {
|