@leofcoin/peernet 1.1.97 → 1.1.98
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.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { L as LittlePubSub } from './peernet-
|
|
1
|
+
import { L as LittlePubSub } from './peernet-DzeROp0A.js';
|
|
2
2
|
import './identity-Cn0iQbY3.js';
|
|
3
3
|
import './value-C3vAp-wb.js';
|
|
4
4
|
|
|
@@ -428,7 +428,11 @@ class Client {
|
|
|
428
428
|
#peerId;
|
|
429
429
|
#connections = {};
|
|
430
430
|
#stars = {};
|
|
431
|
+
#starListeners = {};
|
|
432
|
+
#handlersSetup = false;
|
|
433
|
+
#reinitLock = null;
|
|
431
434
|
#connectEvent = 'peer:connected';
|
|
435
|
+
#retryOptions = { retries: 5, factor: 2, minTimeout: 1000, maxTimeout: 30000 };
|
|
432
436
|
id;
|
|
433
437
|
networkVersion;
|
|
434
438
|
starsConfig;
|
|
@@ -467,21 +471,80 @@ class Client {
|
|
|
467
471
|
this.version = version;
|
|
468
472
|
this.#connectEvent = connectEvent;
|
|
469
473
|
this.starsConfig = stars;
|
|
474
|
+
if (options?.retry)
|
|
475
|
+
this.#retryOptions = { ...this.#retryOptions, ...options.retry };
|
|
470
476
|
this._init();
|
|
471
477
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
478
|
+
/**
|
|
479
|
+
* Safely reinitialize the client (used after system resume/sleep).
|
|
480
|
+
* It closes existing connections and reconnects to configured stars.
|
|
481
|
+
*/
|
|
482
|
+
async reinit() {
|
|
483
|
+
// avoid concurrent reinit runs
|
|
484
|
+
if (this.#reinitLock)
|
|
485
|
+
return this.#reinitLock;
|
|
486
|
+
this.#reinitLock = (async () => {
|
|
487
|
+
debug('reinit: start');
|
|
488
|
+
try {
|
|
489
|
+
await this.close();
|
|
490
|
+
// clear internal maps so setupStar starts fresh
|
|
491
|
+
this.#stars = {};
|
|
492
|
+
this.#connections = {};
|
|
493
|
+
for (const star of this.starsConfig) {
|
|
494
|
+
try {
|
|
495
|
+
await this.setupStar(star);
|
|
496
|
+
}
|
|
497
|
+
catch (e) {
|
|
498
|
+
// If last star fails and none connected, surface error
|
|
499
|
+
if (this.starsConfig.indexOf(star) === this.starsConfig.length - 1 &&
|
|
500
|
+
Object.keys(this.#stars).length === 0)
|
|
501
|
+
throw new Error(`No star available to connect`);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
finally {
|
|
506
|
+
debug('reinit: done');
|
|
507
|
+
this.#reinitLock = null;
|
|
508
|
+
}
|
|
509
|
+
})();
|
|
510
|
+
return this.#reinitLock;
|
|
511
|
+
}
|
|
512
|
+
async setupStar(star) {
|
|
513
|
+
const { retries, factor, minTimeout, maxTimeout } = this.#retryOptions;
|
|
514
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
515
|
+
let attempt = 0;
|
|
516
|
+
let lastErr;
|
|
517
|
+
while (attempt <= retries) {
|
|
477
518
|
try {
|
|
478
519
|
const client = new SocketRequestClient(star, this.networkVersion);
|
|
479
520
|
this.#stars[star] = await client.init();
|
|
480
|
-
this.setupStarListeners(this.#stars[star]);
|
|
521
|
+
this.setupStarListeners(this.#stars[star], star);
|
|
481
522
|
this.#stars[star].send({
|
|
482
523
|
url: 'join',
|
|
483
524
|
params: { version: this.version, peerId: this.peerId }
|
|
484
525
|
});
|
|
526
|
+
return this.#stars[star];
|
|
527
|
+
}
|
|
528
|
+
catch (e) {
|
|
529
|
+
lastErr = e;
|
|
530
|
+
attempt += 1;
|
|
531
|
+
if (attempt > retries)
|
|
532
|
+
break;
|
|
533
|
+
const delay = Math.min(maxTimeout, Math.round(minTimeout * Math.pow(factor, attempt - 1)));
|
|
534
|
+
debug(`setupStar ${star} failed, retrying in ${delay}ms (attempt ${attempt})`);
|
|
535
|
+
// eslint-disable-next-line no-await-in-loop
|
|
536
|
+
await sleep(delay);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
throw lastErr;
|
|
540
|
+
}
|
|
541
|
+
async _init() {
|
|
542
|
+
// reconnectJob()
|
|
543
|
+
if (!globalThis.RTCPeerConnection)
|
|
544
|
+
globalThis.wrtc = (await import('./browser-Cjcx-T47.js').then(function (n) { return n.b; })).default;
|
|
545
|
+
for (const star of this.starsConfig) {
|
|
546
|
+
try {
|
|
547
|
+
await this.setupStar(star);
|
|
485
548
|
}
|
|
486
549
|
catch (e) {
|
|
487
550
|
if (this.starsConfig.indexOf(star) === this.starsConfig.length - 1 &&
|
|
@@ -499,13 +562,68 @@ class Client {
|
|
|
499
562
|
else {
|
|
500
563
|
globalThis.addEventListener('beforeunload', this.close.bind(this));
|
|
501
564
|
}
|
|
565
|
+
// Setup resume/sleep detection so we can reinit connections after wake
|
|
566
|
+
this._setupResumeHandler();
|
|
567
|
+
}
|
|
568
|
+
setupStarListeners(starConnection, starId) {
|
|
569
|
+
// create stable references to handlers so we can unsubscribe later
|
|
570
|
+
const onPeerJoined = (id) => this.#peerJoined(id, starConnection);
|
|
571
|
+
const onPeerLeft = (id) => this.#peerLeft(id, starConnection);
|
|
572
|
+
const onStarJoined = this.#starJoined;
|
|
573
|
+
const onStarLeft = this.#starLeft;
|
|
574
|
+
const onSignal = (message) => this.#inComingSignal(message, starConnection);
|
|
575
|
+
starConnection.pubsub.subscribe('peer:joined', onPeerJoined);
|
|
576
|
+
starConnection.pubsub.subscribe('peer:left', onPeerLeft);
|
|
577
|
+
starConnection.pubsub.subscribe('star:joined', onStarJoined);
|
|
578
|
+
starConnection.pubsub.subscribe('star:left', onStarLeft);
|
|
579
|
+
starConnection.pubsub.subscribe('signal', onSignal);
|
|
580
|
+
this.#starListeners[starId] = [
|
|
581
|
+
{ topic: 'peer:joined', handler: onPeerJoined },
|
|
582
|
+
{ topic: 'peer:left', handler: onPeerLeft },
|
|
583
|
+
{ topic: 'star:joined', handler: onStarJoined },
|
|
584
|
+
{ topic: 'star:left', handler: onStarLeft },
|
|
585
|
+
{ topic: 'signal', handler: onSignal }
|
|
586
|
+
];
|
|
502
587
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
588
|
+
_setupResumeHandler() {
|
|
589
|
+
if (this.#handlersSetup)
|
|
590
|
+
return;
|
|
591
|
+
this.#handlersSetup = true;
|
|
592
|
+
const THRESHOLD = 10 * 1000; // 10s gap indicates sleep/wake
|
|
593
|
+
let last = Date.now();
|
|
594
|
+
const check = () => {
|
|
595
|
+
const now = Date.now();
|
|
596
|
+
const delta = now - last;
|
|
597
|
+
last = now;
|
|
598
|
+
if (delta > THRESHOLD) {
|
|
599
|
+
debug(`resume detected (gap ${delta}ms)`);
|
|
600
|
+
this.reinit().catch((e) => debug('reinit error', e));
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
// Start interval checker
|
|
604
|
+
const iv = setInterval(check, 2000);
|
|
605
|
+
// Browser specific events
|
|
606
|
+
if (typeof document !== 'undefined' && document.addEventListener) {
|
|
607
|
+
document.addEventListener('visibilitychange', () => {
|
|
608
|
+
if (document.visibilityState === 'visible') {
|
|
609
|
+
// small delay to let timers update
|
|
610
|
+
setTimeout(() => check(), 50);
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
window.addEventListener('online', () => setTimeout(() => check(), 50));
|
|
614
|
+
}
|
|
615
|
+
// Node: listen for SIGCONT (process continued) as well
|
|
616
|
+
if (globalThis.process?.on) {
|
|
617
|
+
try {
|
|
618
|
+
process.on('SIGCONT', () => setTimeout(() => check(), 50));
|
|
619
|
+
}
|
|
620
|
+
catch (e) {
|
|
621
|
+
// ignore
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
// keep reference so it can be cleared on close
|
|
625
|
+
// @ts-ignore
|
|
626
|
+
this._resumeInterval = iv;
|
|
509
627
|
}
|
|
510
628
|
#starJoined = (id) => {
|
|
511
629
|
if (this.#stars[id]) {
|
|
@@ -519,20 +637,16 @@ class Client {
|
|
|
519
637
|
this.#stars[id].close(0);
|
|
520
638
|
delete this.#stars[id];
|
|
521
639
|
}
|
|
640
|
+
// if we lost all stars, try to reconnect to configured stars with backoff
|
|
522
641
|
if (Object.keys(this.#stars).length === 0) {
|
|
523
642
|
for (const star of this.starsConfig) {
|
|
524
643
|
try {
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
this.#stars[star] = socketClient;
|
|
529
|
-
this.#stars[star].send({
|
|
530
|
-
url: 'join',
|
|
531
|
-
params: { peerId: this.peerId, version: this.version }
|
|
532
|
-
});
|
|
533
|
-
this.setupStarListeners(socketClient);
|
|
644
|
+
await this.setupStar(star);
|
|
645
|
+
// stop at first success
|
|
646
|
+
return;
|
|
534
647
|
}
|
|
535
648
|
catch (e) {
|
|
649
|
+
debug(`reconnect star ${star} failed: ${e.message || e}`);
|
|
536
650
|
if (this.starsConfig.indexOf(star) === this.starsConfig.length - 1)
|
|
537
651
|
throw new Error(`No star available to connect`);
|
|
538
652
|
}
|
|
@@ -611,7 +725,7 @@ class Client {
|
|
|
611
725
|
// Destroy the existing peer connection
|
|
612
726
|
// peer.destroy()
|
|
613
727
|
// delete this.#connections[from]
|
|
614
|
-
// // Create a new peer connection with the correct configuration
|
|
728
|
+
// // // Create a new peer connection with the correct configuration
|
|
615
729
|
// this.#createRTCPeerConnection(from, star, version, false)
|
|
616
730
|
// peer = this.#connections[from]
|
|
617
731
|
}
|
|
@@ -685,15 +799,53 @@ class Client {
|
|
|
685
799
|
peer.destroy();
|
|
686
800
|
};
|
|
687
801
|
async close() {
|
|
802
|
+
// clear resume interval if set
|
|
803
|
+
// @ts-ignore
|
|
804
|
+
if (this._resumeInterval) {
|
|
805
|
+
// @ts-ignore
|
|
806
|
+
clearInterval(this._resumeInterval);
|
|
807
|
+
// @ts-ignore
|
|
808
|
+
this._resumeInterval = null;
|
|
809
|
+
}
|
|
688
810
|
for (const star in this.#stars) {
|
|
689
|
-
if (this.#stars[star].connectionState() === 'open')
|
|
811
|
+
if (this.#stars[star].connectionState() === 'open') {
|
|
690
812
|
await this.#stars[star].send({ url: 'leave', params: this.peerId });
|
|
813
|
+
// unsubscribe handlers we registered earlier
|
|
814
|
+
const listeners = this.#starListeners[star];
|
|
815
|
+
if (listeners && listeners.length) {
|
|
816
|
+
for (const { topic, handler } of listeners) {
|
|
817
|
+
try {
|
|
818
|
+
this.#stars[star].pubsub.unsubscribe(topic, handler);
|
|
819
|
+
}
|
|
820
|
+
catch (e) {
|
|
821
|
+
// ignore
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
691
826
|
}
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
827
|
+
// Ensure we wait for all peer and star close/destroy operations.
|
|
828
|
+
// Previous code passed an array of arrays to Promise.allSettled which
|
|
829
|
+
// resolves immediately; flatten into a single array of promises (or
|
|
830
|
+
// values) so we actually wait for async close operations.
|
|
831
|
+
const peerClosers = Object.values(this.#connections).map((connection) => {
|
|
832
|
+
try {
|
|
833
|
+
// destroy() may be sync or return a promise
|
|
834
|
+
return connection.destroy();
|
|
835
|
+
}
|
|
836
|
+
catch (e) {
|
|
837
|
+
return undefined;
|
|
838
|
+
}
|
|
839
|
+
});
|
|
840
|
+
const starClosers = Object.values(this.#stars).map((connection) => {
|
|
841
|
+
try {
|
|
842
|
+
return connection.close(0);
|
|
843
|
+
}
|
|
844
|
+
catch (e) {
|
|
845
|
+
return undefined;
|
|
846
|
+
}
|
|
847
|
+
});
|
|
848
|
+
return Promise.allSettled([...peerClosers, ...starClosers]);
|
|
697
849
|
}
|
|
698
850
|
}
|
|
699
851
|
|
|
@@ -8367,7 +8367,7 @@ class Peernet {
|
|
|
8367
8367
|
this.root = options.root;
|
|
8368
8368
|
const { RequestMessage, ResponseMessage, PeerMessage, PeerMessageResponse, PeernetMessage, DHTMessage, DHTMessageResponse, DataMessage, DataMessageResponse, PsMessage, ChatMessage, PeernetFile
|
|
8369
8369
|
// FolderMessageResponse
|
|
8370
|
-
} = await import(/* webpackChunkName: "messages" */ './messages-
|
|
8370
|
+
} = await import(/* webpackChunkName: "messages" */ './messages-CFqwXbrQ.js');
|
|
8371
8371
|
/**
|
|
8372
8372
|
* proto Object containing protos
|
|
8373
8373
|
* @type {Object}
|
|
@@ -8461,7 +8461,7 @@ class Peernet {
|
|
|
8461
8461
|
if (this.#starting || this.#started)
|
|
8462
8462
|
return;
|
|
8463
8463
|
this.#starting = true;
|
|
8464
|
-
const importee = await import('./client-
|
|
8464
|
+
const importee = await import('./client-UwSHOtRi.js');
|
|
8465
8465
|
/**
|
|
8466
8466
|
* @access public
|
|
8467
8467
|
* @type {PeernetClient}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leofcoin/peernet",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.98",
|
|
4
4
|
"description": "",
|
|
5
5
|
"browser": "./exports/browser/peernet.js",
|
|
6
6
|
"exports": {
|
|
@@ -37,13 +37,13 @@
|
|
|
37
37
|
"@leofcoin/identity-utils": "^1.0.2",
|
|
38
38
|
"@leofcoin/multi-wallet": "^3.1.8",
|
|
39
39
|
"@leofcoin/storage": "^3.5.38",
|
|
40
|
-
"@netpeer/swarm": "^0.8.
|
|
40
|
+
"@netpeer/swarm": "^0.8.24",
|
|
41
41
|
"@vandeurenglenn/base32": "^1.2.4",
|
|
42
42
|
"@vandeurenglenn/base58": "^1.1.9",
|
|
43
43
|
"@vandeurenglenn/debug": "^1.2.6",
|
|
44
44
|
"@vandeurenglenn/is-hex": "^1.1.1",
|
|
45
45
|
"@vandeurenglenn/little-pubsub": "^1.5.1",
|
|
46
|
-
"inquirer": "^12.9.
|
|
46
|
+
"inquirer": "^12.9.2",
|
|
47
47
|
"multi-signature": "^1.3.1",
|
|
48
48
|
"qr-scanner": "^1.4.2",
|
|
49
49
|
"qrcode": "^1.5.4",
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
58
58
|
"@rollup/plugin-typescript": "^12.1.4",
|
|
59
59
|
"@rollup/plugin-wasm": "^6.2.2",
|
|
60
|
-
"@types/bs58check": "^
|
|
61
|
-
"@types/node": "^24.
|
|
60
|
+
"@types/bs58check": "^3.0.1",
|
|
61
|
+
"@types/node": "^24.3.0",
|
|
62
62
|
"@types/qrcode": "^1.5.5",
|
|
63
63
|
"@types/secp256k1": "^4.0.6",
|
|
64
64
|
"@types/varint": "^6.0.3",
|