the-invisible-billion-cli 1.0.0 → 1.0.1
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/package.json +1 -1
- package/src/cli/commands/scan.js +1 -1
- package/src/daemon/index.js +38 -14
- package/src/db/index.js +3 -3
package/package.json
CHANGED
package/src/cli/commands/scan.js
CHANGED
|
@@ -32,7 +32,7 @@ async function scanCommand() {
|
|
|
32
32
|
|
|
33
33
|
function isOnline(epochMs) {
|
|
34
34
|
if (!epochMs) return false;
|
|
35
|
-
return (Date.now() - epochMs) <
|
|
35
|
+
return (Date.now() - epochMs) < 45_000; // 45 s — 3 missed heartbeats (heartbeat = 15s)
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
function formatAgo(epochMs) {
|
package/src/daemon/index.js
CHANGED
|
@@ -354,16 +354,19 @@ const stopTCP = startTCP({
|
|
|
354
354
|
|
|
355
355
|
// ── Network change watcher ────────────────────────────────────────────────────
|
|
356
356
|
const stopNetworkWatcher = startNetworkWatcher((newIP, previousIP) => {
|
|
357
|
-
log(`[network] Changed: ${previousIP} → ${newIP}.
|
|
357
|
+
log(`[network] Changed: ${previousIP} → ${newIP}. Clearing stale peer IPs and re-announcing...`);
|
|
358
|
+
|
|
359
|
+
// Critical: clear all peer IPs from the OLD network.
|
|
360
|
+
// Peers from the previous network are unreachable now.
|
|
361
|
+
// They will re-announce via UDP within 15s if they are also on the new network.
|
|
362
|
+
clearAllPeerIPs();
|
|
363
|
+
log('[network] Stale peer IPs cleared — waiting for fresh UDP announcements on new network.');
|
|
364
|
+
|
|
365
|
+
// Re-announce ourselves on the new network immediately
|
|
358
366
|
broadcastNow();
|
|
359
|
-
startupDeliverySweep(); // re-try all pending to known peers on new network
|
|
360
367
|
|
|
361
|
-
//
|
|
362
|
-
|
|
363
|
-
if (peerIPs.length > 0) {
|
|
364
|
-
log(`[epidemic] Network change triggered bundle exchange with ${peerIPs.length} peer(s)`);
|
|
365
|
-
forwardMessages(peerIPs);
|
|
366
|
-
}
|
|
368
|
+
// Retry delivery sweep — any peers that re-appear will be handled by onPeer callback
|
|
369
|
+
startupDeliverySweep();
|
|
367
370
|
});
|
|
368
371
|
|
|
369
372
|
// ── Phase 3: Startup / network-change delivery sweep ─────────────────────────
|
|
@@ -436,16 +439,37 @@ setInterval(() => {
|
|
|
436
439
|
}, RETRY_SWEEP_INTERVAL_MS).unref();
|
|
437
440
|
|
|
438
441
|
// ── Periodic stale peer cleanup ───────────────────────────────────────────────
|
|
439
|
-
// Every
|
|
440
|
-
|
|
441
|
-
|
|
442
|
+
// Every 20 s, remove peers not seen in 45 s (3 missed 15s heartbeats).
|
|
443
|
+
// This ensures scan reflects reality quickly when a peer disconnects without
|
|
444
|
+
// sending a goodbye packet (e.g. closes laptop, loses WiFi).
|
|
445
|
+
const STALE_PEER_INTERVAL_MS = 20_000;
|
|
446
|
+
const STALE_PEER_THRESHOLD_MS = 45_000; // 3 missed heartbeats
|
|
442
447
|
setInterval(() => {
|
|
443
448
|
const removed = removeInactivePeers(STALE_PEER_THRESHOLD_MS);
|
|
444
449
|
if (removed > 0) {
|
|
445
|
-
log(`[cleanup] Removed ${removed} stale peer(s) (not seen in
|
|
450
|
+
log(`[cleanup] Removed ${removed} stale peer(s) (not seen in 45s)`);
|
|
446
451
|
}
|
|
447
452
|
}, STALE_PEER_INTERVAL_MS).unref();
|
|
448
453
|
|
|
454
|
+
// ── Periodic epidemic forwarding sweep ────────────────────────────────────────
|
|
455
|
+
// Every 45 s, push ALL pending messages to ALL currently active peers.
|
|
456
|
+
// This catches the case where a carrier was already on the network when a
|
|
457
|
+
// new message arrived and their onPeer event already fired — they wouldn't
|
|
458
|
+
// get the new message unless we periodically push to them.
|
|
459
|
+
const EPIDEMIC_SWEEP_INTERVAL_MS = 45_000;
|
|
460
|
+
setInterval(() => {
|
|
461
|
+
const pending = getAllPending();
|
|
462
|
+
if (pending.length === 0) return;
|
|
463
|
+
|
|
464
|
+
const peerIPs = getActivePeers().map(p => p.ip).filter(ip => ip);
|
|
465
|
+
if (peerIPs.length === 0) return;
|
|
466
|
+
|
|
467
|
+
log(`[epidemic] Periodic sweep: pushing ${pending.length} pending msg(s) to ${peerIPs.length} active peer(s)`);
|
|
468
|
+
forwardMessages(peerIPs).catch(err => {
|
|
469
|
+
log(`[epidemic] Periodic sweep failed: ${err.message}`);
|
|
470
|
+
});
|
|
471
|
+
}, EPIDEMIC_SWEEP_INTERVAL_MS).unref();
|
|
472
|
+
|
|
449
473
|
// ── IPC Server ────────────────────────────────────────────────────────────────
|
|
450
474
|
if (process.platform !== 'win32' && fs.existsSync(IPC_SOCKET)) {
|
|
451
475
|
fs.unlinkSync(IPC_SOCKET);
|
|
@@ -500,8 +524,8 @@ function handleCommand(cmd, socket) {
|
|
|
500
524
|
break;
|
|
501
525
|
|
|
502
526
|
case 'scan': {
|
|
503
|
-
// Return only peers seen within the last
|
|
504
|
-
const SCAN_FRESHNESS_MS =
|
|
527
|
+
// Return only peers seen within the last 90 s (consistent with cleanup threshold)
|
|
528
|
+
const SCAN_FRESHNESS_MS = 90_000;
|
|
505
529
|
const peers = getAllPeers(SCAN_FRESHNESS_MS);
|
|
506
530
|
sendResponse(socket, { ok: true, peers });
|
|
507
531
|
break;
|
package/src/db/index.js
CHANGED
|
@@ -52,12 +52,12 @@ function openDb() {
|
|
|
52
52
|
try {
|
|
53
53
|
_db.exec(`ALTER TABLE peers ADD COLUMN ip TEXT`);
|
|
54
54
|
} catch (_) {
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
// column already exists — ignore safely
|
|
56
|
+
}
|
|
57
57
|
|
|
58
58
|
return _db;
|
|
59
59
|
}
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
63
|
* Close the database connection.
|