@decentnetwork/peer 0.1.143 → 0.1.145
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.js +76 -5
- package/dist/types/peer.d.ts +4 -0
- package/package.json +1 -1
package/dist/peer.js
CHANGED
|
@@ -373,6 +373,10 @@ export class Peer {
|
|
|
373
373
|
#knownNodes;
|
|
374
374
|
#announceDataKey;
|
|
375
375
|
#lastSelfAnnounceMs = 0;
|
|
376
|
+
// Env vars OR an explicit option. A browser has no process.env, so peer
|
|
377
|
+
// debugging there was simply unreachable — which is why the browser client
|
|
378
|
+
// has been a black box every time it misbehaved. The option is the only way
|
|
379
|
+
// in from a page.
|
|
376
380
|
#debug = process.env.DECENT_DEBUG === "1" || process.env.DECENT_DEBUG_VERBOSE === "1";
|
|
377
381
|
#debugVerbose = process.env.DECENT_DEBUG_VERBOSE === "1";
|
|
378
382
|
#packetTrace = process.env.DECENT_PACKET_TRACE === "1";
|
|
@@ -538,6 +542,15 @@ export class Peer {
|
|
|
538
542
|
...opts,
|
|
539
543
|
compatibilityMode: opts.compatibilityMode ?? "legacy"
|
|
540
544
|
};
|
|
545
|
+
// A browser has no process.env, so the env-var switches above can never
|
|
546
|
+
// be set there and peer debugging was unreachable from a page. That is
|
|
547
|
+
// why every browser misbehaviour has had to be diagnosed by inference.
|
|
548
|
+
if (opts.debug)
|
|
549
|
+
this.#debug = true;
|
|
550
|
+
if (opts.debugVerbose) {
|
|
551
|
+
this.#debug = true;
|
|
552
|
+
this.#debugVerbose = true;
|
|
553
|
+
}
|
|
541
554
|
this.#knownNodes = [...opts.bootstrapNodes];
|
|
542
555
|
this.#friendStoreFile = opts.friendStoreFile ?? `${opts.keyFile}.friends.json`;
|
|
543
556
|
// Enable resumable (断点续传) receives when the app gives us a directory to
|
|
@@ -6860,6 +6873,41 @@ export class Peer {
|
|
|
6860
6873
|
async #sendThroughOnionPath(payloadForNodeD, nodeD, pathOffset = 0, forcedPath) {
|
|
6861
6874
|
const path = forcedPath === "direct" ? undefined : forcedPath ?? this.#selectOnionPath(nodeD, pathOffset);
|
|
6862
6875
|
if (!path) {
|
|
6876
|
+
// No 3-hop UDP path. "Direct" then meant a plain UDP send — which on a
|
|
6877
|
+
// host with no UDP (a browser, where dgram is a socket that drops) goes
|
|
6878
|
+
// straight into the void, silently, forever. Every announce and every
|
|
6879
|
+
// friend-request lookup died here.
|
|
6880
|
+
//
|
|
6881
|
+
// A RELAYED onion request needs only two hops: the relay is node A. So
|
|
6882
|
+
// try that before giving up, and only fall through to the UDP send when
|
|
6883
|
+
// there are no relays or not even two usable hops.
|
|
6884
|
+
if (this.#tcpRelays && this.#tcpRelays.connectedCount() > 0) {
|
|
6885
|
+
const hops = this.#selectTcpOnionHops(nodeD, pathOffset);
|
|
6886
|
+
if (hops) {
|
|
6887
|
+
try {
|
|
6888
|
+
const tcpPacket = createOnionRequest0Tcp({
|
|
6889
|
+
nodeBHost: hops.nodeB.host,
|
|
6890
|
+
nodeBPort: hops.nodeB.port,
|
|
6891
|
+
nodeBPublicKey: hops.nodeB.publicKey,
|
|
6892
|
+
nodeCHost: hops.nodeC.host,
|
|
6893
|
+
nodeCPort: hops.nodeC.port,
|
|
6894
|
+
nodeCPublicKey: hops.nodeC.publicKey,
|
|
6895
|
+
nodeDHost: nodeD.host,
|
|
6896
|
+
nodeDPort: nodeD.port,
|
|
6897
|
+
payloadForNodeD
|
|
6898
|
+
});
|
|
6899
|
+
const sent = this.#tcpRelays.sendOnionRequest(tcpPacket);
|
|
6900
|
+
if (sent > 0) {
|
|
6901
|
+
this.#diagTcpOnionSent += 1;
|
|
6902
|
+
this.#debugLog(`no 3-hop path for ${nodeD.host}:${nodeD.port} — relayed 2-hop onion via ${sent} relay(s) (B=${hops.nodeB.host} C=${hops.nodeC.host})`);
|
|
6903
|
+
return "direct";
|
|
6904
|
+
}
|
|
6905
|
+
}
|
|
6906
|
+
catch {
|
|
6907
|
+
/* malformed hop key — fall through to the UDP attempt */
|
|
6908
|
+
}
|
|
6909
|
+
}
|
|
6910
|
+
}
|
|
6863
6911
|
this.#debugLog(`no onion path for ${nodeD.host}:${nodeD.port}, sending direct`);
|
|
6864
6912
|
await this.#sendPacket(payloadForNodeD, nodeD);
|
|
6865
6913
|
return "direct";
|
|
@@ -6910,7 +6958,10 @@ export class Peer {
|
|
|
6910
6958
|
}
|
|
6911
6959
|
return path;
|
|
6912
6960
|
}
|
|
6913
|
-
|
|
6961
|
+
/** Ranked hop candidates for a path to nodeD. Shared by the 3-hop UDP
|
|
6962
|
+
* selector and the 2-hop TCP one — a relay stands in for node A, so a
|
|
6963
|
+
* relayed path needs one fewer usable node than a direct one. */
|
|
6964
|
+
#onionCandidatePool(nodeD) {
|
|
6914
6965
|
const nodeDId = `${nodeD.host}:${nodeD.port}`;
|
|
6915
6966
|
const candidates = [];
|
|
6916
6967
|
const bootstrapIds = new Set(this.#opts.bootstrapNodes.map((node) => `${node.host}:${node.port}`));
|
|
@@ -6959,13 +7010,33 @@ export class Peer {
|
|
|
6959
7010
|
// Ignore bad keys.
|
|
6960
7011
|
}
|
|
6961
7012
|
}
|
|
6962
|
-
if (candidates.length < 3) {
|
|
6963
|
-
return undefined;
|
|
6964
|
-
}
|
|
6965
7013
|
candidates.sort((a, b) => b.score - a.score);
|
|
6966
7014
|
const preferredRelays = candidates.filter((item) => isLikelyStableRelayPort(item.node.port));
|
|
6967
7015
|
const healthy = preferredRelays.filter((item) => item.score > -2);
|
|
6968
|
-
|
|
7016
|
+
return healthy.length >= 3 ? healthy : preferredRelays.length >= 3 ? preferredRelays : candidates;
|
|
7017
|
+
}
|
|
7018
|
+
/** Two hops (B and C) for a relayed onion request. The relay is node A, so
|
|
7019
|
+
* this succeeds on node sets too thin for a direct 3-hop path — which is
|
|
7020
|
+
* the browser's normal state, and where every request used to fall through
|
|
7021
|
+
* to a UDP send that goes nowhere. */
|
|
7022
|
+
#selectTcpOnionHops(nodeD, pathOffset = 0) {
|
|
7023
|
+
const pool = this.#onionCandidatePool(nodeD);
|
|
7024
|
+
if (pool.length < 2)
|
|
7025
|
+
return undefined;
|
|
7026
|
+
const i1 = pathOffset % pool.length;
|
|
7027
|
+
const i2 = (pathOffset + 1) % pool.length;
|
|
7028
|
+
if (i1 === i2)
|
|
7029
|
+
return undefined;
|
|
7030
|
+
const hop = (x) => ({
|
|
7031
|
+
node: x.node, host: x.node.host, port: x.node.port, publicKey: x.publicKey
|
|
7032
|
+
});
|
|
7033
|
+
return { nodeB: hop(pool[i1]), nodeC: hop(pool[i2]) };
|
|
7034
|
+
}
|
|
7035
|
+
#selectOnionPath(nodeD, pathOffset = 0) {
|
|
7036
|
+
const pool = this.#onionCandidatePool(nodeD);
|
|
7037
|
+
if (pool.length < 3) {
|
|
7038
|
+
return undefined;
|
|
7039
|
+
}
|
|
6969
7040
|
const count = pool.length;
|
|
6970
7041
|
const i0 = pathOffset % count;
|
|
6971
7042
|
const i1 = (pathOffset + 1) % count;
|
package/dist/types/peer.d.ts
CHANGED
|
@@ -100,6 +100,10 @@ export type PeerOptions = {
|
|
|
100
100
|
* of it never runs: self-announce (so nobody can find this peer) and the
|
|
101
101
|
* express pull loop (so offline messages are never collected). */
|
|
102
102
|
tcpOnlyBootstrap?: boolean;
|
|
103
|
+
/** Turn on peer debug logging without env vars — the only route in from a
|
|
104
|
+
* browser, where process.env does not exist. */
|
|
105
|
+
debug?: boolean;
|
|
106
|
+
debugVerbose?: boolean;
|
|
103
107
|
compatibilityMode?: CompatibilityMode;
|
|
104
108
|
debugLabel?: string;
|
|
105
109
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decentnetwork/peer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.145",
|
|
4
4
|
"description": "Pure TypeScript port of Elastos Carrier (toxcore-derived) P2P messaging. DHT, onion routing, TCP relay, FlatBuffers app payloads, Express offline relay. Wire-compatible with iOS Beagle and the Carrier C SDK.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|