@leofcoin/chain 1.7.103 → 1.7.105
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/exports/browser/chain.js +61 -183
- package/exports/chain.js +61 -183
- package/package.json +1 -1
package/exports/browser/chain.js
CHANGED
|
@@ -5347,13 +5347,13 @@ class ConnectionMonitor {
|
|
|
5347
5347
|
void this.#restoreNetwork();
|
|
5348
5348
|
};
|
|
5349
5349
|
window.addEventListener('online', this.#onOnline);
|
|
5350
|
-
this.#onVisibilityChange = () => {
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
}
|
|
5356
|
-
document.addEventListener('visibilitychange', this.#onVisibilityChange)
|
|
5350
|
+
// this.#onVisibilityChange = () => {
|
|
5351
|
+
// if (document.visibilityState === 'visible') {
|
|
5352
|
+
// console.log('💡 Visibility regained — attempting restore')
|
|
5353
|
+
// void this.#restoreNetwork()
|
|
5354
|
+
// }
|
|
5355
|
+
// }
|
|
5356
|
+
// document.addEventListener('visibilitychange', this.#onVisibilityChange)
|
|
5357
5357
|
}
|
|
5358
5358
|
if (typeof process !== 'undefined' && typeof process.on === 'function') {
|
|
5359
5359
|
this.#onSigcont = () => {
|
|
@@ -5412,20 +5412,6 @@ class ConnectionMonitor {
|
|
|
5412
5412
|
else if (compatiblePeers.length === 0) {
|
|
5413
5413
|
console.warn('⚠️ No compatible peers found');
|
|
5414
5414
|
await this.#attemptReconnection();
|
|
5415
|
-
// Could attempt to find compatible peers or trigger version negotiation
|
|
5416
|
-
}
|
|
5417
|
-
// Log disconnected peers
|
|
5418
|
-
const disconnectedPeers = this.disconnectedPeers;
|
|
5419
|
-
if (disconnectedPeers.length > 0) {
|
|
5420
|
-
console.warn(`⚠️ Disconnected peers: ${disconnectedPeers.map((peer) => peer.peerId).join(', ')}`);
|
|
5421
|
-
// Attempt to reconnect each disconnected peer sequentially to avoid racing signaling/state
|
|
5422
|
-
for (const peer of disconnectedPeers) {
|
|
5423
|
-
// small spacing between attempts to reduce signaling races
|
|
5424
|
-
// eslint-disable-next-line no-await-in-loop
|
|
5425
|
-
await new Promise((r) => setTimeout(r, 150));
|
|
5426
|
-
// eslint-disable-next-line no-await-in-loop
|
|
5427
|
-
await this.#attemptPeerReconnection(peer);
|
|
5428
|
-
}
|
|
5429
5415
|
}
|
|
5430
5416
|
// Publish connection status
|
|
5431
5417
|
globalThis.pubsub?.publish('connection-status', {
|
|
@@ -5434,170 +5420,73 @@ class ConnectionMonitor {
|
|
|
5434
5420
|
healthy: compatiblePeers.length > 0
|
|
5435
5421
|
});
|
|
5436
5422
|
}
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
if (!this.#peerReconnectAttempts[peerId]) {
|
|
5444
|
-
this.#peerReconnectAttempts[peerId] = 0;
|
|
5445
|
-
}
|
|
5446
|
-
if (this.#peerReconnectAttempts[peerId] >= this.#maxReconnectAttempts) {
|
|
5447
|
-
console.error('❌ Max reconnection attempts reached for', peerId);
|
|
5448
|
-
this.#peerReconnectAttempts[peerId] = 0;
|
|
5449
|
-
return;
|
|
5450
|
-
}
|
|
5451
|
-
this.#peerReconnectAttempts[peerId]++;
|
|
5452
|
-
console.log(`🔄 Attempting reconnection ${this.#peerReconnectAttempts[peerId]}/${this.#maxReconnectAttempts} for ${peerId}`);
|
|
5453
|
-
try {
|
|
5454
|
-
const peernet = globalThis.peernet;
|
|
5455
|
-
if (!peernet) {
|
|
5456
|
-
console.warn('⚠️ globalThis.peernet not available');
|
|
5457
|
-
return;
|
|
5423
|
+
// lightweight TCP probe to detect internet connectivity in Node.js
|
|
5424
|
+
async #isOnLine(timeout = 1500) {
|
|
5425
|
+
// If not running in Node, fallback to navigator.onLine if available, otherwise assume online
|
|
5426
|
+
if (typeof process === 'undefined') {
|
|
5427
|
+
if (navigator?.onLine !== undefined) {
|
|
5428
|
+
return navigator.onLine;
|
|
5458
5429
|
}
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
if (
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
try {
|
|
5475
|
-
await this.#cleanupPeerState(peerId, peernet);
|
|
5476
|
-
// small backoff before retry
|
|
5477
|
-
await new Promise((r) => setTimeout(r, 150));
|
|
5478
|
-
await peernet.client.reconnect(peerId, peernet.stars?.[0]);
|
|
5479
|
-
return;
|
|
5480
|
-
}
|
|
5481
|
-
catch (retryErr) {
|
|
5482
|
-
console.warn('⚠️ Retry targeted reconnect failed:', String(retryErr?.message || retryErr));
|
|
5483
|
-
// fall through to non-targeted fallback below
|
|
5484
|
-
}
|
|
5430
|
+
return true;
|
|
5431
|
+
}
|
|
5432
|
+
return new Promise(async (resolve) => {
|
|
5433
|
+
try {
|
|
5434
|
+
// lazy require so bundlers / browser builds don't break
|
|
5435
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
5436
|
+
const net = await import('net');
|
|
5437
|
+
const socket = new net.Socket();
|
|
5438
|
+
let finished = false;
|
|
5439
|
+
const finish = (val) => {
|
|
5440
|
+
if (finished)
|
|
5441
|
+
return;
|
|
5442
|
+
finished = true;
|
|
5443
|
+
try {
|
|
5444
|
+
socket.destroy();
|
|
5485
5445
|
}
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5446
|
+
catch (e) {
|
|
5447
|
+
// ignore
|
|
5448
|
+
}
|
|
5449
|
+
resolve(val);
|
|
5450
|
+
};
|
|
5451
|
+
socket.setTimeout(timeout);
|
|
5452
|
+
socket.once('connect', () => finish(true));
|
|
5453
|
+
socket.once('error', () => finish(false));
|
|
5454
|
+
socket.once('timeout', () => finish(false));
|
|
5455
|
+
// connect to Cloudflare DNS (1.1.1.1) on TCP/53 — fast and reliable
|
|
5456
|
+
socket.connect(53, '1.1.1.1');
|
|
5492
5457
|
}
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
console.error('❌ Reconnection failed:', error?.message || error);
|
|
5496
|
-
// As fallback, try full restart only if even the cleanup+retry failed
|
|
5497
|
-
if (globalThis.peernet) {
|
|
5498
|
-
await this.#performFullRestart(globalThis.peernet);
|
|
5458
|
+
catch (e) {
|
|
5459
|
+
resolve(false);
|
|
5499
5460
|
}
|
|
5500
|
-
}
|
|
5461
|
+
});
|
|
5501
5462
|
}
|
|
5502
|
-
//
|
|
5503
|
-
async #
|
|
5463
|
+
// Called on visibility/online/resume events
|
|
5464
|
+
async #restoreNetwork() {
|
|
5465
|
+
console.log('🔁 Restoring network');
|
|
5504
5466
|
try {
|
|
5505
|
-
const
|
|
5506
|
-
|
|
5507
|
-
|
|
5467
|
+
const online = await this.#isOnLine(1500);
|
|
5468
|
+
if (!online) {
|
|
5469
|
+
console.warn('⚠️ No internet detected, skipping restore');
|
|
5508
5470
|
return;
|
|
5509
|
-
// close underlying RTCPeerConnection if exposed
|
|
5510
|
-
try {
|
|
5511
|
-
if (conn.pc && typeof conn.pc.close === 'function') {
|
|
5512
|
-
conn.pc.close();
|
|
5513
|
-
}
|
|
5514
|
-
}
|
|
5515
|
-
catch (e) {
|
|
5516
|
-
// ignore
|
|
5517
5471
|
}
|
|
5518
|
-
// call any destroy/cleanup API on the connection object
|
|
5519
|
-
try {
|
|
5520
|
-
if (typeof conn.destroy === 'function') {
|
|
5521
|
-
conn.destroy();
|
|
5522
|
-
}
|
|
5523
|
-
else if (typeof conn.close === 'function') {
|
|
5524
|
-
conn.close();
|
|
5525
|
-
}
|
|
5526
|
-
}
|
|
5527
|
-
catch (e) {
|
|
5528
|
-
// ignore
|
|
5529
|
-
}
|
|
5530
|
-
// remove reference so reconnect path will create a fresh one
|
|
5531
|
-
try {
|
|
5532
|
-
delete peernet.connections[peerId];
|
|
5533
|
-
}
|
|
5534
|
-
catch (e) {
|
|
5535
|
-
// ignore
|
|
5536
|
-
}
|
|
5537
|
-
// small pause to let underlying sockets/RTCs settle
|
|
5538
|
-
await new Promise((r) => setTimeout(r, 100));
|
|
5539
5472
|
}
|
|
5540
5473
|
catch (e) {
|
|
5541
|
-
//
|
|
5474
|
+
// If the probe failed for any reason, continue with restore attempt
|
|
5475
|
+
console.warn('⚠️ Online probe failed, proceeding with restore', e?.message || e);
|
|
5542
5476
|
}
|
|
5543
|
-
}
|
|
5544
|
-
// New helper: close stale RTCPeerConnections if present and then restart peernet
|
|
5545
|
-
async #performFullRestart(peernet) {
|
|
5546
5477
|
try {
|
|
5547
|
-
//
|
|
5478
|
+
// prefer safe client reinit if available
|
|
5479
|
+
console.log('🔄 Attempting to reinitialize peernet client');
|
|
5480
|
+
await globalThis.peernet.client.reinit();
|
|
5481
|
+
}
|
|
5482
|
+
catch (e) {
|
|
5483
|
+
console.warn('⚠️ peernet.client.reinit failed, falling back to peernet.start if available', e?.message || e);
|
|
5548
5484
|
try {
|
|
5549
|
-
|
|
5550
|
-
for (const id of Object.keys(conns)) {
|
|
5551
|
-
const p = conns[id];
|
|
5552
|
-
// try to close underlying RTCPeerConnection if exposed
|
|
5553
|
-
if (p && p.pc && typeof p.pc.close === 'function') {
|
|
5554
|
-
try {
|
|
5555
|
-
p.pc.close();
|
|
5556
|
-
}
|
|
5557
|
-
catch (e) {
|
|
5558
|
-
// ignore
|
|
5559
|
-
}
|
|
5560
|
-
}
|
|
5561
|
-
}
|
|
5562
|
-
}
|
|
5563
|
-
catch (e) {
|
|
5564
|
-
// ignore
|
|
5565
|
-
}
|
|
5566
|
-
// If the library supports stop -> start, do that to fully reset signaling state
|
|
5567
|
-
if (typeof peernet.stop === 'function') {
|
|
5568
|
-
try {
|
|
5569
|
-
await peernet.stop();
|
|
5570
|
-
}
|
|
5571
|
-
catch (e) {
|
|
5572
|
-
// ignore stop errors
|
|
5573
|
-
}
|
|
5485
|
+
await globalThis.peernet.start();
|
|
5574
5486
|
}
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
if (typeof peernet.start === 'function') {
|
|
5578
|
-
await peernet.start();
|
|
5487
|
+
catch (err) {
|
|
5488
|
+
console.error('❌ peernet.start also failed during restore', err?.message || err);
|
|
5579
5489
|
}
|
|
5580
|
-
else {
|
|
5581
|
-
console.warn('⚠️ peernet.start not available for full restart');
|
|
5582
|
-
}
|
|
5583
|
-
// reset reconnect attempts so we can try fresh
|
|
5584
|
-
this.#peerReconnectAttempts = {};
|
|
5585
|
-
console.log('✅ Full peernet restart completed');
|
|
5586
|
-
}
|
|
5587
|
-
catch (e) {
|
|
5588
|
-
console.error('❌ Full restart failed:', e?.message || e);
|
|
5589
|
-
}
|
|
5590
|
-
}
|
|
5591
|
-
// Called on visibility/online/resume events
|
|
5592
|
-
async #restoreNetwork() {
|
|
5593
|
-
console.log('🔁 Restoring network after resume/wake');
|
|
5594
|
-
// If there is a peernet instance, try a safe restore
|
|
5595
|
-
if (globalThis.peernet) {
|
|
5596
|
-
await this.#performFullRestart(globalThis.peernet);
|
|
5597
|
-
}
|
|
5598
|
-
else {
|
|
5599
|
-
// If no global peernet, attempt a normal reconnection flow
|
|
5600
|
-
await this.#attemptReconnection();
|
|
5601
5490
|
}
|
|
5602
5491
|
}
|
|
5603
5492
|
async waitForPeers(timeoutMs = 30000) {
|
|
@@ -5617,21 +5506,9 @@ class ConnectionMonitor {
|
|
|
5617
5506
|
checkPeers();
|
|
5618
5507
|
});
|
|
5619
5508
|
}
|
|
5620
|
-
// New: attempt reconnection flow (gentle start + sequential per-peer reconnect)
|
|
5621
5509
|
async #attemptReconnection() {
|
|
5622
|
-
console.warn('⚠️ Attempting to reconnect to peers...');
|
|
5623
5510
|
try {
|
|
5624
|
-
|
|
5625
|
-
const disconnected = this.disconnectedPeers;
|
|
5626
|
-
for (const p of disconnected) {
|
|
5627
|
-
// small spacing between attempts to reduce signaling races
|
|
5628
|
-
// eslint-disable-next-line no-await-in-loop
|
|
5629
|
-
await new Promise((r) => setTimeout(r, 200));
|
|
5630
|
-
// eslint-disable-next-line no-await-in-loop
|
|
5631
|
-
await this.#attemptPeerReconnection(p);
|
|
5632
|
-
}
|
|
5633
|
-
// pause before next health check cycle
|
|
5634
|
-
await new Promise((resolve) => setTimeout(resolve, this.#reconnectDelay));
|
|
5511
|
+
await this.#restoreNetwork();
|
|
5635
5512
|
}
|
|
5636
5513
|
catch (error) {
|
|
5637
5514
|
console.error('❌ Reconnection failed:', error?.message || error);
|
|
@@ -5644,6 +5521,7 @@ class ConnectionMonitor {
|
|
|
5644
5521
|
this.#reconnectDelay = Math.min(this.#reconnectDelay * 1.5, 30000);
|
|
5645
5522
|
console.warn(`⚠️ Increasing reconnection delay to ${this.#reconnectDelay} ms`);
|
|
5646
5523
|
}
|
|
5524
|
+
setTimeout(() => this.#attemptReconnection(), this.#reconnectDelay);
|
|
5647
5525
|
}
|
|
5648
5526
|
}
|
|
5649
5527
|
}
|
package/exports/chain.js
CHANGED
|
@@ -1493,13 +1493,13 @@ class ConnectionMonitor {
|
|
|
1493
1493
|
void this.#restoreNetwork();
|
|
1494
1494
|
};
|
|
1495
1495
|
window.addEventListener('online', this.#onOnline);
|
|
1496
|
-
this.#onVisibilityChange = () => {
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
}
|
|
1502
|
-
document.addEventListener('visibilitychange', this.#onVisibilityChange)
|
|
1496
|
+
// this.#onVisibilityChange = () => {
|
|
1497
|
+
// if (document.visibilityState === 'visible') {
|
|
1498
|
+
// console.log('💡 Visibility regained — attempting restore')
|
|
1499
|
+
// void this.#restoreNetwork()
|
|
1500
|
+
// }
|
|
1501
|
+
// }
|
|
1502
|
+
// document.addEventListener('visibilitychange', this.#onVisibilityChange)
|
|
1503
1503
|
}
|
|
1504
1504
|
if (typeof process !== 'undefined' && typeof process.on === 'function') {
|
|
1505
1505
|
this.#onSigcont = () => {
|
|
@@ -1558,20 +1558,6 @@ class ConnectionMonitor {
|
|
|
1558
1558
|
else if (compatiblePeers.length === 0) {
|
|
1559
1559
|
console.warn('⚠️ No compatible peers found');
|
|
1560
1560
|
await this.#attemptReconnection();
|
|
1561
|
-
// Could attempt to find compatible peers or trigger version negotiation
|
|
1562
|
-
}
|
|
1563
|
-
// Log disconnected peers
|
|
1564
|
-
const disconnectedPeers = this.disconnectedPeers;
|
|
1565
|
-
if (disconnectedPeers.length > 0) {
|
|
1566
|
-
console.warn(`⚠️ Disconnected peers: ${disconnectedPeers.map((peer) => peer.peerId).join(', ')}`);
|
|
1567
|
-
// Attempt to reconnect each disconnected peer sequentially to avoid racing signaling/state
|
|
1568
|
-
for (const peer of disconnectedPeers) {
|
|
1569
|
-
// small spacing between attempts to reduce signaling races
|
|
1570
|
-
// eslint-disable-next-line no-await-in-loop
|
|
1571
|
-
await new Promise((r) => setTimeout(r, 150));
|
|
1572
|
-
// eslint-disable-next-line no-await-in-loop
|
|
1573
|
-
await this.#attemptPeerReconnection(peer);
|
|
1574
|
-
}
|
|
1575
1561
|
}
|
|
1576
1562
|
// Publish connection status
|
|
1577
1563
|
globalThis.pubsub?.publish('connection-status', {
|
|
@@ -1580,170 +1566,73 @@ class ConnectionMonitor {
|
|
|
1580
1566
|
healthy: compatiblePeers.length > 0
|
|
1581
1567
|
});
|
|
1582
1568
|
}
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
if (!this.#peerReconnectAttempts[peerId]) {
|
|
1590
|
-
this.#peerReconnectAttempts[peerId] = 0;
|
|
1591
|
-
}
|
|
1592
|
-
if (this.#peerReconnectAttempts[peerId] >= this.#maxReconnectAttempts) {
|
|
1593
|
-
console.error('❌ Max reconnection attempts reached for', peerId);
|
|
1594
|
-
this.#peerReconnectAttempts[peerId] = 0;
|
|
1595
|
-
return;
|
|
1596
|
-
}
|
|
1597
|
-
this.#peerReconnectAttempts[peerId]++;
|
|
1598
|
-
console.log(`🔄 Attempting reconnection ${this.#peerReconnectAttempts[peerId]}/${this.#maxReconnectAttempts} for ${peerId}`);
|
|
1599
|
-
try {
|
|
1600
|
-
const peernet = globalThis.peernet;
|
|
1601
|
-
if (!peernet) {
|
|
1602
|
-
console.warn('⚠️ globalThis.peernet not available');
|
|
1603
|
-
return;
|
|
1569
|
+
// lightweight TCP probe to detect internet connectivity in Node.js
|
|
1570
|
+
async #isOnLine(timeout = 1500) {
|
|
1571
|
+
// If not running in Node, fallback to navigator.onLine if available, otherwise assume online
|
|
1572
|
+
if (typeof process === 'undefined') {
|
|
1573
|
+
if (navigator?.onLine !== undefined) {
|
|
1574
|
+
return navigator.onLine;
|
|
1604
1575
|
}
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
if (
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
try {
|
|
1621
|
-
await this.#cleanupPeerState(peerId, peernet);
|
|
1622
|
-
// small backoff before retry
|
|
1623
|
-
await new Promise((r) => setTimeout(r, 150));
|
|
1624
|
-
await peernet.client.reconnect(peerId, peernet.stars?.[0]);
|
|
1625
|
-
return;
|
|
1626
|
-
}
|
|
1627
|
-
catch (retryErr) {
|
|
1628
|
-
console.warn('⚠️ Retry targeted reconnect failed:', String(retryErr?.message || retryErr));
|
|
1629
|
-
// fall through to non-targeted fallback below
|
|
1630
|
-
}
|
|
1576
|
+
return true;
|
|
1577
|
+
}
|
|
1578
|
+
return new Promise(async (resolve) => {
|
|
1579
|
+
try {
|
|
1580
|
+
// lazy require so bundlers / browser builds don't break
|
|
1581
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
1582
|
+
const net = await import('net');
|
|
1583
|
+
const socket = new net.Socket();
|
|
1584
|
+
let finished = false;
|
|
1585
|
+
const finish = (val) => {
|
|
1586
|
+
if (finished)
|
|
1587
|
+
return;
|
|
1588
|
+
finished = true;
|
|
1589
|
+
try {
|
|
1590
|
+
socket.destroy();
|
|
1631
1591
|
}
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1592
|
+
catch (e) {
|
|
1593
|
+
// ignore
|
|
1594
|
+
}
|
|
1595
|
+
resolve(val);
|
|
1596
|
+
};
|
|
1597
|
+
socket.setTimeout(timeout);
|
|
1598
|
+
socket.once('connect', () => finish(true));
|
|
1599
|
+
socket.once('error', () => finish(false));
|
|
1600
|
+
socket.once('timeout', () => finish(false));
|
|
1601
|
+
// connect to Cloudflare DNS (1.1.1.1) on TCP/53 — fast and reliable
|
|
1602
|
+
socket.connect(53, '1.1.1.1');
|
|
1638
1603
|
}
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
console.error('❌ Reconnection failed:', error?.message || error);
|
|
1642
|
-
// As fallback, try full restart only if even the cleanup+retry failed
|
|
1643
|
-
if (globalThis.peernet) {
|
|
1644
|
-
await this.#performFullRestart(globalThis.peernet);
|
|
1604
|
+
catch (e) {
|
|
1605
|
+
resolve(false);
|
|
1645
1606
|
}
|
|
1646
|
-
}
|
|
1607
|
+
});
|
|
1647
1608
|
}
|
|
1648
|
-
//
|
|
1649
|
-
async #
|
|
1609
|
+
// Called on visibility/online/resume events
|
|
1610
|
+
async #restoreNetwork() {
|
|
1611
|
+
console.log('🔁 Restoring network');
|
|
1650
1612
|
try {
|
|
1651
|
-
const
|
|
1652
|
-
|
|
1653
|
-
|
|
1613
|
+
const online = await this.#isOnLine(1500);
|
|
1614
|
+
if (!online) {
|
|
1615
|
+
console.warn('⚠️ No internet detected, skipping restore');
|
|
1654
1616
|
return;
|
|
1655
|
-
// close underlying RTCPeerConnection if exposed
|
|
1656
|
-
try {
|
|
1657
|
-
if (conn.pc && typeof conn.pc.close === 'function') {
|
|
1658
|
-
conn.pc.close();
|
|
1659
|
-
}
|
|
1660
1617
|
}
|
|
1661
|
-
catch (e) {
|
|
1662
|
-
// ignore
|
|
1663
|
-
}
|
|
1664
|
-
// call any destroy/cleanup API on the connection object
|
|
1665
|
-
try {
|
|
1666
|
-
if (typeof conn.destroy === 'function') {
|
|
1667
|
-
conn.destroy();
|
|
1668
|
-
}
|
|
1669
|
-
else if (typeof conn.close === 'function') {
|
|
1670
|
-
conn.close();
|
|
1671
|
-
}
|
|
1672
|
-
}
|
|
1673
|
-
catch (e) {
|
|
1674
|
-
// ignore
|
|
1675
|
-
}
|
|
1676
|
-
// remove reference so reconnect path will create a fresh one
|
|
1677
|
-
try {
|
|
1678
|
-
delete peernet.connections[peerId];
|
|
1679
|
-
}
|
|
1680
|
-
catch (e) {
|
|
1681
|
-
// ignore
|
|
1682
|
-
}
|
|
1683
|
-
// small pause to let underlying sockets/RTCs settle
|
|
1684
|
-
await new Promise((r) => setTimeout(r, 100));
|
|
1685
1618
|
}
|
|
1686
1619
|
catch (e) {
|
|
1687
|
-
//
|
|
1620
|
+
// If the probe failed for any reason, continue with restore attempt
|
|
1621
|
+
console.warn('⚠️ Online probe failed, proceeding with restore', e?.message || e);
|
|
1688
1622
|
}
|
|
1689
|
-
}
|
|
1690
|
-
// New helper: close stale RTCPeerConnections if present and then restart peernet
|
|
1691
|
-
async #performFullRestart(peernet) {
|
|
1692
1623
|
try {
|
|
1693
|
-
//
|
|
1624
|
+
// prefer safe client reinit if available
|
|
1625
|
+
console.log('🔄 Attempting to reinitialize peernet client');
|
|
1626
|
+
await globalThis.peernet.client.reinit();
|
|
1627
|
+
}
|
|
1628
|
+
catch (e) {
|
|
1629
|
+
console.warn('⚠️ peernet.client.reinit failed, falling back to peernet.start if available', e?.message || e);
|
|
1694
1630
|
try {
|
|
1695
|
-
|
|
1696
|
-
for (const id of Object.keys(conns)) {
|
|
1697
|
-
const p = conns[id];
|
|
1698
|
-
// try to close underlying RTCPeerConnection if exposed
|
|
1699
|
-
if (p && p.pc && typeof p.pc.close === 'function') {
|
|
1700
|
-
try {
|
|
1701
|
-
p.pc.close();
|
|
1702
|
-
}
|
|
1703
|
-
catch (e) {
|
|
1704
|
-
// ignore
|
|
1705
|
-
}
|
|
1706
|
-
}
|
|
1707
|
-
}
|
|
1708
|
-
}
|
|
1709
|
-
catch (e) {
|
|
1710
|
-
// ignore
|
|
1711
|
-
}
|
|
1712
|
-
// If the library supports stop -> start, do that to fully reset signaling state
|
|
1713
|
-
if (typeof peernet.stop === 'function') {
|
|
1714
|
-
try {
|
|
1715
|
-
await peernet.stop();
|
|
1716
|
-
}
|
|
1717
|
-
catch (e) {
|
|
1718
|
-
// ignore stop errors
|
|
1719
|
-
}
|
|
1631
|
+
await globalThis.peernet.start();
|
|
1720
1632
|
}
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
if (typeof peernet.start === 'function') {
|
|
1724
|
-
await peernet.start();
|
|
1633
|
+
catch (err) {
|
|
1634
|
+
console.error('❌ peernet.start also failed during restore', err?.message || err);
|
|
1725
1635
|
}
|
|
1726
|
-
else {
|
|
1727
|
-
console.warn('⚠️ peernet.start not available for full restart');
|
|
1728
|
-
}
|
|
1729
|
-
// reset reconnect attempts so we can try fresh
|
|
1730
|
-
this.#peerReconnectAttempts = {};
|
|
1731
|
-
console.log('✅ Full peernet restart completed');
|
|
1732
|
-
}
|
|
1733
|
-
catch (e) {
|
|
1734
|
-
console.error('❌ Full restart failed:', e?.message || e);
|
|
1735
|
-
}
|
|
1736
|
-
}
|
|
1737
|
-
// Called on visibility/online/resume events
|
|
1738
|
-
async #restoreNetwork() {
|
|
1739
|
-
console.log('🔁 Restoring network after resume/wake');
|
|
1740
|
-
// If there is a peernet instance, try a safe restore
|
|
1741
|
-
if (globalThis.peernet) {
|
|
1742
|
-
await this.#performFullRestart(globalThis.peernet);
|
|
1743
|
-
}
|
|
1744
|
-
else {
|
|
1745
|
-
// If no global peernet, attempt a normal reconnection flow
|
|
1746
|
-
await this.#attemptReconnection();
|
|
1747
1636
|
}
|
|
1748
1637
|
}
|
|
1749
1638
|
async waitForPeers(timeoutMs = 30000) {
|
|
@@ -1763,21 +1652,9 @@ class ConnectionMonitor {
|
|
|
1763
1652
|
checkPeers();
|
|
1764
1653
|
});
|
|
1765
1654
|
}
|
|
1766
|
-
// New: attempt reconnection flow (gentle start + sequential per-peer reconnect)
|
|
1767
1655
|
async #attemptReconnection() {
|
|
1768
|
-
console.warn('⚠️ Attempting to reconnect to peers...');
|
|
1769
1656
|
try {
|
|
1770
|
-
|
|
1771
|
-
const disconnected = this.disconnectedPeers;
|
|
1772
|
-
for (const p of disconnected) {
|
|
1773
|
-
// small spacing between attempts to reduce signaling races
|
|
1774
|
-
// eslint-disable-next-line no-await-in-loop
|
|
1775
|
-
await new Promise((r) => setTimeout(r, 200));
|
|
1776
|
-
// eslint-disable-next-line no-await-in-loop
|
|
1777
|
-
await this.#attemptPeerReconnection(p);
|
|
1778
|
-
}
|
|
1779
|
-
// pause before next health check cycle
|
|
1780
|
-
await new Promise((resolve) => setTimeout(resolve, this.#reconnectDelay));
|
|
1657
|
+
await this.#restoreNetwork();
|
|
1781
1658
|
}
|
|
1782
1659
|
catch (error) {
|
|
1783
1660
|
console.error('❌ Reconnection failed:', error?.message || error);
|
|
@@ -1790,6 +1667,7 @@ class ConnectionMonitor {
|
|
|
1790
1667
|
this.#reconnectDelay = Math.min(this.#reconnectDelay * 1.5, 30000);
|
|
1791
1668
|
console.warn(`⚠️ Increasing reconnection delay to ${this.#reconnectDelay} ms`);
|
|
1792
1669
|
}
|
|
1670
|
+
setTimeout(() => this.#attemptReconnection(), this.#reconnectDelay);
|
|
1793
1671
|
}
|
|
1794
1672
|
}
|
|
1795
1673
|
}
|