@decentnetwork/peer 0.1.100 → 0.1.103
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/compat/filetransfer.js +26 -5
- package/dist/peer.js +1 -1
- package/dist/types/peer.d.ts +6 -0
- package/package.json +1 -1
|
@@ -96,6 +96,14 @@ const PACE_CYCLE_GAINS = [1.25, 0.8, 1, 1, 1, 1, 1, 1]; // steady PROBE_BW cycle
|
|
|
96
96
|
const PACE_BW_WINDOW = 10; // rounds of delivered-rate history for the max-filter
|
|
97
97
|
const PACE_SAMPLE_MS = 200; // aggregate ACKs so one scheduler-jittered packet is not a "round"
|
|
98
98
|
const PACE_INIT_BPS = 120_000; // initial pace rate (~120 KB/s) before any bandwidth estimate
|
|
99
|
+
// A subnet-validated endpoint is not an unknown Internet/relay path. Starting
|
|
100
|
+
// it at 120 KB/s made a Windows ACK-scheduling wobble terminate STARTUP before
|
|
101
|
+
// the controller had ever offered meaningful LAN load; transfers then stayed
|
|
102
|
+
// around 200-500 KB/s despite a multi-MB/s physical path. 2 MB/s is a starting
|
|
103
|
+
// probe, not a cap: the normal feedback loop can grow above it or immediately
|
|
104
|
+
// drain below it on real loss/queueing. The 20 ms pacer limits the initial burst
|
|
105
|
+
// to ~40 KB, so this does not recreate the old 1 MB window blast.
|
|
106
|
+
const LAN_PACE_INIT_BPS = 2_000_000;
|
|
99
107
|
const PACE_BURST_MS = 20; // token-bucket burst allowance (keeps sends smooth, not bunched)
|
|
100
108
|
// A LAN receiver can coalesce a backlog of ACKs after its event loop wakes. The
|
|
101
109
|
// resulting delivery sample is ACK rate, not link capacity: in practice a
|
|
@@ -111,7 +119,11 @@ const LAN_STARTUP_QUEUE_MS = 500; // unmistakable raw queue spike; smaller app-l
|
|
|
111
119
|
const LAN_STARTUP_HARD_QUEUE_MS = 2000; // one multi-second queue sample is unsafe
|
|
112
120
|
const LAN_STARTUP_QUEUE_ROUNDS = 2; // tolerate one scheduler/session-handover outlier on LAN
|
|
113
121
|
const LAN_STARTUP_KEEPUP = 0.70; // delivered goodput below 70% of pace means the receiver is no longer keeping up
|
|
114
|
-
|
|
122
|
+
// Five 200 ms samples was still only about one Windows ACK scheduling cycle in
|
|
123
|
+
// practice: a clean LAN (0% loss) exited STARTUP after ~3 MB and threw away a
|
|
124
|
+
// healthy 2.3 MB/s probe. Require a few seconds of sustained under-delivery;
|
|
125
|
+
// the independent queue/loss brakes still react immediately to a real overload.
|
|
126
|
+
const LAN_STARTUP_SLOW_ROUNDS = 15;
|
|
115
127
|
// FILE ACKs are coalesced and handled by the remote JS event loop. On Windows
|
|
116
128
|
// the effective ACK clock is commonly 20–120 ms even when an occasional probe
|
|
117
129
|
// reports a 7 ms network RTT. Sizing cwnd from that lucky minimum made a
|
|
@@ -119,6 +131,7 @@ const LAN_STARTUP_SLOW_ROUNDS = 5; // require sustained saturation across Window
|
|
|
119
131
|
// and falsely ended startup. Pacing remains the primary throttle, so this floor
|
|
120
132
|
// only prevents the safety window from starving a validated LAN flow.
|
|
121
133
|
const LAN_BDP_RTT_FLOOR_MS = 50;
|
|
134
|
+
const LAN_CWND_INIT_CHUNKS = Math.ceil((LAN_PACE_INIT_BPS * (LAN_BDP_RTT_FLOOR_MS / 1000) * 2) / MAX_FILE_DATA_SIZE);
|
|
122
135
|
const WATCHDOG_MS = 150; // stall poll cadence / base no-progress patience
|
|
123
136
|
const WATCHDOG_MAX_MS = 8000; // cap the RTT-adaptive stall patience (must exceed a slow path's RTT so acks aren't mistaken for a stall)
|
|
124
137
|
const FAST_RT_MIN_MS = 40; // min gap between fast-retransmits of the same hole (≈1 RTT)
|
|
@@ -245,16 +258,19 @@ export class FileTransferManager {
|
|
|
245
258
|
? new Uint8Array(createHash("sha256").update(data).digest()).slice(0, FILE_ID_LENGTH)
|
|
246
259
|
: randomBytes(FILE_ID_LENGTH);
|
|
247
260
|
const req = encodeFileSendRequest(fileNumber, opts.kind ?? FILEKIND.DATA, BigInt(data.length), fileId, opts.name);
|
|
261
|
+
const lanPath = this.isLanPath(friendId);
|
|
248
262
|
const st = {
|
|
249
263
|
fileNumber, fileId, name: opts.name, data, size: data.length,
|
|
250
264
|
acked: 0, nextSend: 0, pumping: false, started: false, req, startMs: nowMs(),
|
|
251
265
|
lastProgressAcked: 0, lastAckAdvanceMs: nowMs(), lastResendMs: 0,
|
|
252
|
-
cwnd:
|
|
266
|
+
cwnd: lanPath ? LAN_CWND_INIT_CHUNKS : CWND_INIT_CHUNKS,
|
|
267
|
+
stalls: 0, parityHighBlock: -1, lastLossMs: 0, lossEwma: 0,
|
|
253
268
|
minRttMs: Infinity, srttMs: 0, probeOffset: -1, probeSentMs: 0,
|
|
254
|
-
paceRateBps:
|
|
269
|
+
paceRateBps: lanPath ? LAN_PACE_INIT_BPS : PACE_INIT_BPS,
|
|
270
|
+
paceTokens: 0, lastPaceMs: nowMs(),
|
|
255
271
|
btlBwBps: 0, bwSamples: [], fullBwRounds: 0, startupQueueRounds: 0, bbrPhase: 0, roundCount: 0,
|
|
256
272
|
rateMarkMs: nowMs(), rateMarkAcked: 0, lowRttCount: 0, lowRttMinMs: Infinity, lastCcLogMs: 0,
|
|
257
|
-
lanPath
|
|
273
|
+
lanPath,
|
|
258
274
|
};
|
|
259
275
|
this.#map(this.#sending, friendId).set(fileNumber, st);
|
|
260
276
|
void this.send(friendId, PACKET_ID_FILE_SENDREQUEST, req).catch(() => undefined);
|
|
@@ -786,10 +802,15 @@ export class FileTransferManager {
|
|
|
786
802
|
const lossMult = lanNow ? 1 : 1 / (1 - Math.min(0.5, st.lossEwma));
|
|
787
803
|
if (lanNow && !st.lanPath) {
|
|
788
804
|
// A transfer can begin on relay and then promote to a validated
|
|
789
|
-
// physical-LAN endpoint.
|
|
805
|
+
// physical-LAN endpoint. Relay samples must not pin the new LAN
|
|
806
|
+
// path near 120 KB/s: discard them and begin a safe LAN probe.
|
|
790
807
|
st.bbrPhase = 0;
|
|
791
808
|
st.fullBwRounds = 0;
|
|
792
809
|
st.startupQueueRounds = 0;
|
|
810
|
+
st.bwSamples = [];
|
|
811
|
+
st.btlBwBps = 0;
|
|
812
|
+
st.paceRateBps = Math.max(st.paceRateBps, LAN_PACE_INIT_BPS);
|
|
813
|
+
st.cwnd = Math.max(st.cwnd, LAN_CWND_INIT_CHUNKS);
|
|
793
814
|
}
|
|
794
815
|
st.lanPath = lanNow;
|
|
795
816
|
if (!lanNow) {
|
package/dist/peer.js
CHANGED
|
@@ -430,7 +430,7 @@ export class Peer {
|
|
|
430
430
|
});
|
|
431
431
|
}
|
|
432
432
|
this.#udp.on("datagram", this.#onDatagram);
|
|
433
|
-
await this.#udp.start();
|
|
433
|
+
await this.#udp.start({ port: this.#opts.udpPort });
|
|
434
434
|
// Spin up the TCP relay pool. We pass the same bootstrap node list
|
|
435
435
|
// we already have — every Carrier bootstrap is also a TCP relay
|
|
436
436
|
// server on the same pubkey. The pool opens up to 3 connections in
|
package/dist/types/peer.d.ts
CHANGED
|
@@ -25,6 +25,12 @@ export type NetworkNode = {
|
|
|
25
25
|
};
|
|
26
26
|
export type PeerOptions = {
|
|
27
27
|
keyFile: string;
|
|
28
|
+
/**
|
|
29
|
+
* Stable UDP listen port. Long-lived service peers (Dora registries,
|
|
30
|
+
* relays/exits) should set this so friends' cached DHT endpoints remain
|
|
31
|
+
* usable across process restarts. Omit or set 0 for an ephemeral port.
|
|
32
|
+
*/
|
|
33
|
+
udpPort?: number;
|
|
28
34
|
friendStoreFile?: string;
|
|
29
35
|
bootstrapNodes: NetworkNode[];
|
|
30
36
|
expressNodes?: NetworkNode[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decentnetwork/peer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.103",
|
|
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",
|