egos-transfer 0.2.9 → 0.2.11
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/dist/peer-transfer.d.ts +9 -0
- package/dist/peer-transfer.js +55 -2
- package/package.json +1 -1
- package/src/peer-transfer.ts +55 -2
package/dist/peer-transfer.d.ts
CHANGED
|
@@ -31,6 +31,12 @@ export declare abstract class PeerTransfer {
|
|
|
31
31
|
private idleTimer;
|
|
32
32
|
/** 心跳超时定时器:30 秒未收到 HEARTBEAT 则重连 */
|
|
33
33
|
private heartbeatTimer;
|
|
34
|
+
/** 进行中的 Peer 创建:并发调用复用同一个 Promise,防止交叉 destroy/新建 */
|
|
35
|
+
private creatingPeer;
|
|
36
|
+
/** 上次成功创建 Peer 的时间戳:节流窗口内直接复用现有实例 */
|
|
37
|
+
private lastPeerCreatedAt;
|
|
38
|
+
/** 创建代际:stop/clearInstance/新一轮创建时递增,使旧的进行中创建作废 */
|
|
39
|
+
private createEpoch;
|
|
34
40
|
constructor(deviceId: string, config: PeerTransferOptions);
|
|
35
41
|
abstract getStore(): any;
|
|
36
42
|
abstract online(deviceId: string): void;
|
|
@@ -43,6 +49,7 @@ export declare abstract class PeerTransfer {
|
|
|
43
49
|
abstract onConnectLimit(): void;
|
|
44
50
|
abstract reloadConfig(config?: Record<string, any>): Promise<void>;
|
|
45
51
|
createPeer(force?: boolean): Promise<Peer>;
|
|
52
|
+
private doCreatePeer;
|
|
46
53
|
private waitForOpen;
|
|
47
54
|
handleSocketMessage(message: IMessage): void;
|
|
48
55
|
connectToPeer(peerId: string): Promise<DataConnection | undefined>;
|
|
@@ -89,6 +96,8 @@ export declare abstract class PeerTransfer {
|
|
|
89
96
|
* 与 destroy stop 后仍可调用 createPeer 恢复工作。
|
|
90
97
|
*/
|
|
91
98
|
stop(): void;
|
|
99
|
+
/** 使进行中的 Peer 创建作废:旧创建在恢复点自行中止,并允许 createPeer 立即重启 */
|
|
100
|
+
private abortCreate;
|
|
92
101
|
private destroyPeer;
|
|
93
102
|
askReload(peerId: string): void;
|
|
94
103
|
}
|
package/dist/peer-transfer.js
CHANGED
|
@@ -27,6 +27,10 @@ const IDLE_RECREATE_TIMEOUT = 30 * 60 * 1000;
|
|
|
27
27
|
/** 30 秒未收到服务端 HEARTBEAT 则重连 */
|
|
28
28
|
const HEARTBEAT_TIMEOUT = 30000;
|
|
29
29
|
exports.PEER_CLOSE_RECONNECT_TIMEOUT = 3000;
|
|
30
|
+
/** Peer 创建节流窗口:窗口内禁止重复重建,防止事件风暴导致连续 create */
|
|
31
|
+
const PEER_RECREATE_THROTTLE = 5000;
|
|
32
|
+
/** 进行中的创建因 stop/clearInstance/新一轮创建而被中止时抛出的错误 */
|
|
33
|
+
const PEER_CREATION_ABORTED = 'peer creation aborted';
|
|
30
34
|
class PeerTransfer {
|
|
31
35
|
constructor(deviceId, config) {
|
|
32
36
|
this.requests = new Map();
|
|
@@ -42,6 +46,12 @@ class PeerTransfer {
|
|
|
42
46
|
this.idleTimer = null;
|
|
43
47
|
/** 心跳超时定时器:30 秒未收到 HEARTBEAT 则重连 */
|
|
44
48
|
this.heartbeatTimer = null;
|
|
49
|
+
/** 进行中的 Peer 创建:并发调用复用同一个 Promise,防止交叉 destroy/新建 */
|
|
50
|
+
this.creatingPeer = null;
|
|
51
|
+
/** 上次成功创建 Peer 的时间戳:节流窗口内直接复用现有实例 */
|
|
52
|
+
this.lastPeerCreatedAt = 0;
|
|
53
|
+
/** 创建代际:stop/clearInstance/新一轮创建时递增,使旧的进行中创建作废 */
|
|
54
|
+
this.createEpoch = 0;
|
|
45
55
|
this.peerConfig = Object.assign(Object.assign({}, config), { key: String(Date.now()) });
|
|
46
56
|
this.peerId = deviceId;
|
|
47
57
|
this.deviceId = deviceId;
|
|
@@ -57,15 +67,50 @@ class PeerTransfer {
|
|
|
57
67
|
return __awaiter(this, void 0, void 0, function* () {
|
|
58
68
|
var _a;
|
|
59
69
|
this._exited = false;
|
|
70
|
+
// 并发去重:同一时刻只允许一次创建,后续调用复用进行中的 Promise
|
|
71
|
+
if (this.creatingPeer) {
|
|
72
|
+
return this.creatingPeer;
|
|
73
|
+
}
|
|
60
74
|
if (((_a = this.peer) === null || _a === void 0 ? void 0 : _a.open) && !force) {
|
|
61
75
|
return this.peer;
|
|
62
76
|
}
|
|
77
|
+
// 节流:距离上次创建尝试不足窗口期时直接返回现有实例,防止失败后热循环重建(force 可穿透)
|
|
78
|
+
if (!force && Date.now() - this.lastPeerCreatedAt < PEER_RECREATE_THROTTLE) {
|
|
79
|
+
return this.peer;
|
|
80
|
+
}
|
|
63
81
|
console.info('create peer', Date.now());
|
|
82
|
+
const createPromise = this.doCreatePeer();
|
|
83
|
+
this.creatingPeer = createPromise;
|
|
84
|
+
try {
|
|
85
|
+
return yield createPromise;
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
// 仅当未被新一轮创建/abort 覆盖时才清理,避免误清新创建的引用
|
|
89
|
+
if (this.creatingPeer === createPromise) {
|
|
90
|
+
this.creatingPeer = null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
doCreatePeer() {
|
|
96
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
97
|
+
const epoch = ++this.createEpoch; // 本轮创建的代际号
|
|
98
|
+
const isStale = () => epoch !== this.createEpoch;
|
|
99
|
+
this.lastPeerCreatedAt = Date.now(); // 记录创建尝试时间,节流窗口从尝试时刻起算
|
|
64
100
|
this.destroyPeer();
|
|
65
101
|
yield this.reloadConfig();
|
|
102
|
+
// reloadConfig 期间可能发生 stop()/destroy(),旧创建作废
|
|
103
|
+
if (isStale()) {
|
|
104
|
+
throw new Error(PEER_CREATION_ABORTED);
|
|
105
|
+
}
|
|
66
106
|
const peer = new peerjs_1.Peer(this.peerId, Object.assign(Object.assign({}, this.peerConfig), { pingInterval: 9000 }));
|
|
67
107
|
this.peer = peer;
|
|
68
108
|
yield this.waitForOpen(peer);
|
|
109
|
+
// waitForOpen 期间可能发生 stop()/destroy(),旧创建作废
|
|
110
|
+
if (isStale()) {
|
|
111
|
+
peer.destroy();
|
|
112
|
+
throw new Error(PEER_CREATION_ABORTED);
|
|
113
|
+
}
|
|
69
114
|
this.destroyed = false;
|
|
70
115
|
peer.on('close', () => {
|
|
71
116
|
// 仅当 Peer 非主动销毁(stop/clearInstance/重建)时才重连
|
|
@@ -467,7 +512,7 @@ class PeerTransfer {
|
|
|
467
512
|
onRequest(conn, message) {
|
|
468
513
|
return __awaiter(this, void 0, void 0, function* () {
|
|
469
514
|
console.info('onRequest===>', message.route);
|
|
470
|
-
this.resetIdleTimer();
|
|
515
|
+
// this.resetIdleTimer();
|
|
471
516
|
try {
|
|
472
517
|
yield this.router.run(conn, message);
|
|
473
518
|
}
|
|
@@ -479,7 +524,7 @@ class PeerTransfer {
|
|
|
479
524
|
onResponse(_conn, message) {
|
|
480
525
|
return __awaiter(this, void 0, void 0, function* () {
|
|
481
526
|
console.info('onResponse<====', message.route);
|
|
482
|
-
this.resetIdleTimer();
|
|
527
|
+
// this.resetIdleTimer();
|
|
483
528
|
// 优先检查 health check ping 回调
|
|
484
529
|
const cb = this.requests.get(message.requestId);
|
|
485
530
|
if (cb) {
|
|
@@ -539,6 +584,7 @@ class PeerTransfer {
|
|
|
539
584
|
}
|
|
540
585
|
clearInstance() {
|
|
541
586
|
this.destroyed = true;
|
|
587
|
+
this.abortCreate();
|
|
542
588
|
this.clearIdleTimer();
|
|
543
589
|
this.clearHeartbeatTimer();
|
|
544
590
|
this.connectionManager.destroy();
|
|
@@ -556,6 +602,7 @@ class PeerTransfer {
|
|
|
556
602
|
*/
|
|
557
603
|
stop() {
|
|
558
604
|
this._exited = true;
|
|
605
|
+
this.abortCreate();
|
|
559
606
|
this.clearIdleTimer();
|
|
560
607
|
this.clearHeartbeatTimer();
|
|
561
608
|
this.connectionManager.stopHealthCheck();
|
|
@@ -565,6 +612,12 @@ class PeerTransfer {
|
|
|
565
612
|
this.destroyPeer();
|
|
566
613
|
this.reconnectAttempt = 0;
|
|
567
614
|
}
|
|
615
|
+
/** 使进行中的 Peer 创建作废:旧创建在恢复点自行中止,并允许 createPeer 立即重启 */
|
|
616
|
+
abortCreate() {
|
|
617
|
+
this.createEpoch++; // 旧创建的 isStale() 变为 true,自行 destroy 并抛错
|
|
618
|
+
this.creatingPeer = null;
|
|
619
|
+
this.lastPeerCreatedAt = 0; // 重置节流,createPeer 可立即再次创建
|
|
620
|
+
}
|
|
568
621
|
destroyPeer() {
|
|
569
622
|
var _a, _b;
|
|
570
623
|
(_a = this.peer) === null || _a === void 0 ? void 0 : _a.destroy();
|
package/package.json
CHANGED
package/src/peer-transfer.ts
CHANGED
|
@@ -41,6 +41,10 @@ const IDLE_RECREATE_TIMEOUT = 30 * 60 * 1000;
|
|
|
41
41
|
const HEARTBEAT_TIMEOUT = 30000;
|
|
42
42
|
|
|
43
43
|
export const PEER_CLOSE_RECONNECT_TIMEOUT = 3000;
|
|
44
|
+
/** Peer 创建节流窗口:窗口内禁止重复重建,防止事件风暴导致连续 create */
|
|
45
|
+
const PEER_RECREATE_THROTTLE = 5000;
|
|
46
|
+
/** 进行中的创建因 stop/clearInstance/新一轮创建而被中止时抛出的错误 */
|
|
47
|
+
const PEER_CREATION_ABORTED = 'peer creation aborted';
|
|
44
48
|
|
|
45
49
|
export abstract class PeerTransfer {
|
|
46
50
|
protected peer: Peer | undefined;
|
|
@@ -62,6 +66,12 @@ export abstract class PeerTransfer {
|
|
|
62
66
|
private idleTimer: ReturnType<typeof setTimeout> | null = null;
|
|
63
67
|
/** 心跳超时定时器:30 秒未收到 HEARTBEAT 则重连 */
|
|
64
68
|
private heartbeatTimer: ReturnType<typeof setTimeout> | null = null;
|
|
69
|
+
/** 进行中的 Peer 创建:并发调用复用同一个 Promise,防止交叉 destroy/新建 */
|
|
70
|
+
private creatingPeer: Promise<Peer> | null = null;
|
|
71
|
+
/** 上次成功创建 Peer 的时间戳:节流窗口内直接复用现有实例 */
|
|
72
|
+
private lastPeerCreatedAt = 0;
|
|
73
|
+
/** 创建代际:stop/clearInstance/新一轮创建时递增,使旧的进行中创建作废 */
|
|
74
|
+
private createEpoch = 0;
|
|
65
75
|
|
|
66
76
|
constructor(deviceId: string, config: PeerTransferOptions) {
|
|
67
77
|
this.peerConfig = { ...config, key: String(Date.now()) };
|
|
@@ -90,17 +100,51 @@ export abstract class PeerTransfer {
|
|
|
90
100
|
|
|
91
101
|
async createPeer(force?: boolean): Promise<Peer> {
|
|
92
102
|
this._exited = false;
|
|
103
|
+
// 并发去重:同一时刻只允许一次创建,后续调用复用进行中的 Promise
|
|
104
|
+
if (this.creatingPeer) {
|
|
105
|
+
return this.creatingPeer;
|
|
106
|
+
}
|
|
93
107
|
if (this.peer?.open && !force) {
|
|
94
108
|
return this.peer;
|
|
95
109
|
}
|
|
110
|
+
// 节流:距离上次创建尝试不足窗口期时直接返回现有实例,防止失败后热循环重建(force 可穿透)
|
|
111
|
+
if (!force && Date.now() - this.lastPeerCreatedAt < PEER_RECREATE_THROTTLE) {
|
|
112
|
+
return this.peer!;
|
|
113
|
+
}
|
|
96
114
|
console.info('create peer', Date.now());
|
|
115
|
+
const createPromise = this.doCreatePeer();
|
|
116
|
+
this.creatingPeer = createPromise;
|
|
117
|
+
try {
|
|
118
|
+
return await createPromise;
|
|
119
|
+
} finally {
|
|
120
|
+
// 仅当未被新一轮创建/abort 覆盖时才清理,避免误清新创建的引用
|
|
121
|
+
if (this.creatingPeer === createPromise) {
|
|
122
|
+
this.creatingPeer = null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private async doCreatePeer(): Promise<Peer> {
|
|
128
|
+
const epoch = ++this.createEpoch; // 本轮创建的代际号
|
|
129
|
+
const isStale = () => epoch !== this.createEpoch;
|
|
130
|
+
this.lastPeerCreatedAt = Date.now(); // 记录创建尝试时间,节流窗口从尝试时刻起算
|
|
97
131
|
this.destroyPeer();
|
|
98
132
|
await this.reloadConfig();
|
|
99
133
|
|
|
134
|
+
// reloadConfig 期间可能发生 stop()/destroy(),旧创建作废
|
|
135
|
+
if (isStale()) {
|
|
136
|
+
throw new Error(PEER_CREATION_ABORTED);
|
|
137
|
+
}
|
|
138
|
+
|
|
100
139
|
const peer = new Peer(this.peerId, { ...this.peerConfig, pingInterval: 9000 });
|
|
101
140
|
this.peer = peer;
|
|
102
141
|
|
|
103
142
|
await this.waitForOpen(peer);
|
|
143
|
+
// waitForOpen 期间可能发生 stop()/destroy(),旧创建作废
|
|
144
|
+
if (isStale()) {
|
|
145
|
+
peer.destroy();
|
|
146
|
+
throw new Error(PEER_CREATION_ABORTED);
|
|
147
|
+
}
|
|
104
148
|
this.destroyed = false;
|
|
105
149
|
peer.on('close', () => {
|
|
106
150
|
// 仅当 Peer 非主动销毁(stop/clearInstance/重建)时才重连
|
|
@@ -562,7 +606,7 @@ export abstract class PeerTransfer {
|
|
|
562
606
|
|
|
563
607
|
async onRequest(conn: DataConnection, message: PeerMessage) {
|
|
564
608
|
console.info('onRequest===>', message.route);
|
|
565
|
-
this.resetIdleTimer();
|
|
609
|
+
// this.resetIdleTimer();
|
|
566
610
|
try {
|
|
567
611
|
await this.router.run(conn, message);
|
|
568
612
|
} catch (err: any) {
|
|
@@ -572,7 +616,7 @@ export abstract class PeerTransfer {
|
|
|
572
616
|
|
|
573
617
|
async onResponse(_conn: DataConnection, message: PeerMessage) {
|
|
574
618
|
console.info('onResponse<====', message.route);
|
|
575
|
-
this.resetIdleTimer();
|
|
619
|
+
// this.resetIdleTimer();
|
|
576
620
|
// 优先检查 health check ping 回调
|
|
577
621
|
const cb = this.requests.get(message.requestId);
|
|
578
622
|
if (cb) {
|
|
@@ -641,6 +685,7 @@ export abstract class PeerTransfer {
|
|
|
641
685
|
|
|
642
686
|
clearInstance() {
|
|
643
687
|
this.destroyed = true;
|
|
688
|
+
this.abortCreate();
|
|
644
689
|
this.clearIdleTimer();
|
|
645
690
|
this.clearHeartbeatTimer();
|
|
646
691
|
|
|
@@ -662,6 +707,7 @@ export abstract class PeerTransfer {
|
|
|
662
707
|
*/
|
|
663
708
|
stop() {
|
|
664
709
|
this._exited = true;
|
|
710
|
+
this.abortCreate();
|
|
665
711
|
this.clearIdleTimer();
|
|
666
712
|
this.clearHeartbeatTimer();
|
|
667
713
|
this.connectionManager.stopHealthCheck();
|
|
@@ -672,6 +718,13 @@ export abstract class PeerTransfer {
|
|
|
672
718
|
this.reconnectAttempt = 0;
|
|
673
719
|
}
|
|
674
720
|
|
|
721
|
+
/** 使进行中的 Peer 创建作废:旧创建在恢复点自行中止,并允许 createPeer 立即重启 */
|
|
722
|
+
private abortCreate() {
|
|
723
|
+
this.createEpoch++; // 旧创建的 isStale() 变为 true,自行 destroy 并抛错
|
|
724
|
+
this.creatingPeer = null;
|
|
725
|
+
this.lastPeerCreatedAt = 0; // 重置节流,createPeer 可立即再次创建
|
|
726
|
+
}
|
|
727
|
+
|
|
675
728
|
private destroyPeer() {
|
|
676
729
|
this.peer?.destroy();
|
|
677
730
|
this.peer?.removeAllListeners();
|