bun-torrent 0.0.3-beta → 0.0.4-beta
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/README.md +22 -3
- package/dist/client.d.ts +17 -0
- package/dist/client.js +26 -8
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/torrent/download/PeerScorer.d.ts +15 -0
- package/dist/torrent/download/PeerScorer.js +24 -0
- package/dist/torrent/download/PeerScorer.js.map +1 -0
- package/dist/torrent/download/index.d.ts +3 -1
- package/dist/torrent/download/index.js +1 -0
- package/dist/torrent/download/index.js.map +1 -1
- package/dist/torrent/download/manager.d.ts +19 -17
- package/dist/torrent/download/manager.js +125 -38
- package/dist/torrent/download/manager.js.map +1 -1
- package/dist/torrent/index.d.ts +1 -1
- package/dist/torrent/session/index.d.ts +5 -2
- package/dist/torrent/session/index.js +17 -5
- package/dist/torrent/session/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -66,8 +66,13 @@ import { Client } from 'bun-torrent';
|
|
|
66
66
|
|
|
67
67
|
const client = new Client({
|
|
68
68
|
outputDirectory: './downloads',
|
|
69
|
+
targetConnections: 20,
|
|
70
|
+
maxConnecting: 30,
|
|
69
71
|
maxInFlightRequestsPerPeer: 20,
|
|
72
|
+
peerConnectTimeoutMs: 5_000,
|
|
73
|
+
trackerTimeoutMs: 5_000,
|
|
70
74
|
requestTimeoutMs: 15_000,
|
|
75
|
+
seed: false,
|
|
71
76
|
progressEvents: 'piece',
|
|
72
77
|
speedSampleIntervalMs: 500,
|
|
73
78
|
});
|
|
@@ -77,8 +82,14 @@ Client options:
|
|
|
77
82
|
|
|
78
83
|
- `outputDirectory`: directory where downloaded files are written. Defaults to `process.cwd()`.
|
|
79
84
|
- `files`: optional default file selection for downloads.
|
|
85
|
+
- `targetConnections`: preferred number of connected peers. Defaults to `20`.
|
|
86
|
+
- `minConnections`: minimum connectable peer count before downloading starts. Defaults to `0`.
|
|
87
|
+
- `maxConnecting`: maximum simultaneous peer connection attempts. Defaults to `30`.
|
|
88
|
+
- `peerConnectTimeoutMs`: timeout for connecting to one peer. Defaults to `5000`.
|
|
89
|
+
- `trackerTimeoutMs`: timeout for tracker announces. Defaults to `5000`.
|
|
80
90
|
- `maxInFlightRequestsPerPeer`: maximum active block requests per peer. Defaults to `20`.
|
|
81
91
|
- `requestTimeoutMs`: timeout for an individual block request. Defaults to `15000`.
|
|
92
|
+
- `seed`: reserved for future seeding support. Currently only `false` is supported.
|
|
82
93
|
- `progressEvents`: `'piece'` emits progress when a piece completes, `'block'` emits for every received block. Defaults to `'piece'`.
|
|
83
94
|
- `speedSampleIntervalMs`: minimum interval used to refresh speed calculations. Defaults to `500`.
|
|
84
95
|
|
|
@@ -109,8 +120,11 @@ const torrent = await client.download(
|
|
|
109
120
|
},
|
|
110
121
|
{
|
|
111
122
|
outputDirectory: './downloads',
|
|
123
|
+
targetConnections: 50,
|
|
124
|
+
maxConnecting: 100,
|
|
112
125
|
minConnections: 5,
|
|
113
126
|
announcePort: 6881,
|
|
127
|
+
seed: false,
|
|
114
128
|
progressEvents: 'block',
|
|
115
129
|
onChangeState: (state) => {
|
|
116
130
|
console.log('client state:', state);
|
|
@@ -123,10 +137,15 @@ Download options:
|
|
|
123
137
|
|
|
124
138
|
- `outputDirectory`: override the output directory for this download.
|
|
125
139
|
- `files`: download only selected files.
|
|
140
|
+
- `targetConnections`: override the preferred peer connection count.
|
|
126
141
|
- `minConnections`: minimum connectable peer count requested before downloading starts.
|
|
142
|
+
- `maxConnecting`: override simultaneous peer connection attempts.
|
|
143
|
+
- `peerConnectTimeoutMs`: override peer connection timeout.
|
|
144
|
+
- `trackerTimeoutMs`: override tracker announce timeout.
|
|
127
145
|
- `announcePort`: port sent to trackers in announce requests.
|
|
128
146
|
- `maxInFlightRequestsPerPeer`: override request concurrency per peer.
|
|
129
147
|
- `requestTimeoutMs`: override block request timeout.
|
|
148
|
+
- `seed`: reserved for future seeding support. Currently only `false` is supported.
|
|
130
149
|
- `progressEvents`: `'piece'` or `'block'`.
|
|
131
150
|
- `speedSampleIntervalMs`: override speed sample interval.
|
|
132
151
|
- `onChangeState`: receives client setup states: `parsing`, `tracking`, `connecting`, `downloading`.
|
|
@@ -185,8 +204,8 @@ torrent.on('progress', (progress) => {
|
|
|
185
204
|
console.log(progress.percent, progress.speed);
|
|
186
205
|
});
|
|
187
206
|
|
|
188
|
-
torrent.on('peer', (
|
|
189
|
-
console.log('peer connected',
|
|
207
|
+
torrent.on('peer', (stats) => {
|
|
208
|
+
console.log('peer connected', stats.connections, '/', stats.targetConnections);
|
|
190
209
|
});
|
|
191
210
|
|
|
192
211
|
torrent.on('done', () => {
|
|
@@ -209,7 +228,7 @@ The current torrent state is also available through `torrent.state`. Possible st
|
|
|
209
228
|
- `failed`
|
|
210
229
|
- `closed`
|
|
211
230
|
|
|
212
|
-
Call `torrent.close()` to stop
|
|
231
|
+
When a download completes, `torrent.done` resolves, the state becomes `completed`, and internal peer connections are closed automatically because seeding is not implemented yet. Call `torrent.close()` to stop an active download early or to mark a completed torrent as explicitly closed.
|
|
213
232
|
|
|
214
233
|
## Progress Shape
|
|
215
234
|
|
package/dist/client.d.ts
CHANGED
|
@@ -11,16 +11,28 @@ export declare enum DownloadState {
|
|
|
11
11
|
export type ClientConfig = {
|
|
12
12
|
files?: TorrentFileSelection;
|
|
13
13
|
maxInFlightRequestsPerPeer?: number;
|
|
14
|
+
maxConnecting?: number;
|
|
15
|
+
minConnections?: number;
|
|
14
16
|
outputDirectory?: string;
|
|
17
|
+
peerConnectTimeoutMs?: number;
|
|
15
18
|
progressEvents?: DownloadProgressEventMode;
|
|
16
19
|
requestTimeoutMs?: number;
|
|
20
|
+
seed?: false;
|
|
17
21
|
speedSampleIntervalMs?: number;
|
|
22
|
+
targetConnections?: number;
|
|
23
|
+
trackerTimeoutMs?: number;
|
|
18
24
|
};
|
|
19
25
|
export declare const DEFAULT_CLIENT_CONFIG: {
|
|
20
26
|
readonly maxInFlightRequestsPerPeer: 20;
|
|
27
|
+
readonly maxConnecting: 30;
|
|
28
|
+
readonly minConnections: 0;
|
|
29
|
+
readonly peerConnectTimeoutMs: 5000;
|
|
21
30
|
readonly progressEvents: "piece";
|
|
22
31
|
readonly requestTimeoutMs: 15000;
|
|
32
|
+
readonly seed: false;
|
|
23
33
|
readonly speedSampleIntervalMs: 500;
|
|
34
|
+
readonly targetConnections: 20;
|
|
35
|
+
readonly trackerTimeoutMs: 5000;
|
|
24
36
|
};
|
|
25
37
|
export declare class Client {
|
|
26
38
|
private readonly config;
|
|
@@ -38,12 +50,17 @@ export type DownloadOptions = {
|
|
|
38
50
|
announcePort?: number;
|
|
39
51
|
files?: TorrentFileSelection;
|
|
40
52
|
maxInFlightRequestsPerPeer?: number;
|
|
53
|
+
maxConnecting?: number;
|
|
41
54
|
minConnections?: number;
|
|
42
55
|
onChangeState?: (state: DownloadState) => unknown;
|
|
43
56
|
outputDirectory?: string;
|
|
57
|
+
peerConnectTimeoutMs?: number;
|
|
44
58
|
progressEvents?: DownloadProgressEventMode;
|
|
45
59
|
requestTimeoutMs?: number;
|
|
60
|
+
seed?: false;
|
|
46
61
|
speedSampleIntervalMs?: number;
|
|
62
|
+
targetConnections?: number;
|
|
63
|
+
trackerTimeoutMs?: number;
|
|
47
64
|
};
|
|
48
65
|
export type TorrentFileInput = string | Uint8Array | ArrayBuffer;
|
|
49
66
|
export declare const readTorrentFile: (input: TorrentFileInput) => Promise<Uint8Array>;
|
package/dist/client.js
CHANGED
|
@@ -15,9 +15,15 @@ export var DownloadState;
|
|
|
15
15
|
})(DownloadState || (DownloadState = {}));
|
|
16
16
|
export const DEFAULT_CLIENT_CONFIG = {
|
|
17
17
|
maxInFlightRequestsPerPeer: 20,
|
|
18
|
+
maxConnecting: 30,
|
|
19
|
+
minConnections: 0,
|
|
20
|
+
peerConnectTimeoutMs: 5_000,
|
|
18
21
|
progressEvents: 'piece',
|
|
19
22
|
requestTimeoutMs: 15_000,
|
|
23
|
+
seed: false,
|
|
20
24
|
speedSampleIntervalMs: 500,
|
|
25
|
+
targetConnections: 20,
|
|
26
|
+
trackerTimeoutMs: 5_000,
|
|
21
27
|
};
|
|
22
28
|
export class Client {
|
|
23
29
|
config;
|
|
@@ -32,16 +38,16 @@ export class Client {
|
|
|
32
38
|
const downloadConfig = resolveDownloadConfig(this.config, options);
|
|
33
39
|
assertValidFileSelection(meta, downloadConfig.files);
|
|
34
40
|
options.onChangeState?.(DownloadState.TRACKING);
|
|
35
|
-
const peers = await this.trackPeers(meta, options);
|
|
41
|
+
const peers = await this.trackPeers(meta, options, downloadConfig);
|
|
36
42
|
options.onChangeState?.(DownloadState.CONNECTING);
|
|
37
43
|
const pool = await openPeerPool(peers, {
|
|
38
44
|
infoHash: meta.infoHash,
|
|
39
45
|
peerId: this.peerId,
|
|
40
|
-
targetConnections:
|
|
46
|
+
targetConnections: downloadConfig.targetConnections,
|
|
41
47
|
totalPieces: meta.pieces.length,
|
|
42
|
-
minConnections:
|
|
43
|
-
maxConnecting:
|
|
44
|
-
timeoutMs:
|
|
48
|
+
minConnections: downloadConfig.minConnections,
|
|
49
|
+
maxConnecting: downloadConfig.maxConnecting,
|
|
50
|
+
timeoutMs: downloadConfig.peerConnectTimeoutMs,
|
|
45
51
|
});
|
|
46
52
|
options.onChangeState?.(DownloadState.DOWNLOADING);
|
|
47
53
|
return new Torrent(meta, pool, new DownloadManager({
|
|
@@ -53,19 +59,19 @@ export class Client {
|
|
|
53
59
|
progressEvents: downloadConfig.progressEvents,
|
|
54
60
|
requestTimeoutMs: downloadConfig.requestTimeoutMs,
|
|
55
61
|
speedSampleIntervalMs: downloadConfig.speedSampleIntervalMs,
|
|
56
|
-
}), normalizeTorrentFileSelection(downloadConfig.files));
|
|
62
|
+
}), normalizeTorrentFileSelection(downloadConfig.files), downloadConfig.seed);
|
|
57
63
|
}
|
|
58
64
|
async inspect(input) {
|
|
59
65
|
const bytes = await readTorrentFile(input.torrentFile);
|
|
60
66
|
return parseTorrent(bytes);
|
|
61
67
|
}
|
|
62
|
-
async trackPeers(meta, options) {
|
|
68
|
+
async trackPeers(meta, options, config) {
|
|
63
69
|
try {
|
|
64
70
|
return await trackPeers({
|
|
65
71
|
meta,
|
|
66
72
|
peerId: this.peerId,
|
|
67
73
|
announcePort: options.announcePort,
|
|
68
|
-
timeoutMs:
|
|
74
|
+
timeoutMs: config.trackerTimeoutMs,
|
|
69
75
|
});
|
|
70
76
|
}
|
|
71
77
|
catch (error) {
|
|
@@ -84,14 +90,26 @@ const resolveDownloadConfig = (config, options) => ({
|
|
|
84
90
|
maxInFlightRequestsPerPeer: options.maxInFlightRequestsPerPeer ??
|
|
85
91
|
config.maxInFlightRequestsPerPeer ??
|
|
86
92
|
DEFAULT_CLIENT_CONFIG.maxInFlightRequestsPerPeer,
|
|
93
|
+
maxConnecting: options.maxConnecting ?? config.maxConnecting ?? DEFAULT_CLIENT_CONFIG.maxConnecting,
|
|
94
|
+
minConnections: options.minConnections ?? config.minConnections ?? DEFAULT_CLIENT_CONFIG.minConnections,
|
|
87
95
|
outputDirectory: options.outputDirectory ?? config.outputDirectory ?? process.cwd(),
|
|
96
|
+
peerConnectTimeoutMs: options.peerConnectTimeoutMs ??
|
|
97
|
+
config.peerConnectTimeoutMs ??
|
|
98
|
+
DEFAULT_CLIENT_CONFIG.peerConnectTimeoutMs,
|
|
88
99
|
progressEvents: options.progressEvents ?? config.progressEvents ?? DEFAULT_CLIENT_CONFIG.progressEvents,
|
|
89
100
|
requestTimeoutMs: options.requestTimeoutMs ??
|
|
90
101
|
config.requestTimeoutMs ??
|
|
91
102
|
DEFAULT_CLIENT_CONFIG.requestTimeoutMs,
|
|
103
|
+
seed: options.seed ?? config.seed ?? DEFAULT_CLIENT_CONFIG.seed,
|
|
92
104
|
speedSampleIntervalMs: options.speedSampleIntervalMs ??
|
|
93
105
|
config.speedSampleIntervalMs ??
|
|
94
106
|
DEFAULT_CLIENT_CONFIG.speedSampleIntervalMs,
|
|
107
|
+
targetConnections: options.targetConnections ??
|
|
108
|
+
config.targetConnections ??
|
|
109
|
+
DEFAULT_CLIENT_CONFIG.targetConnections,
|
|
110
|
+
trackerTimeoutMs: options.trackerTimeoutMs ??
|
|
111
|
+
config.trackerTimeoutMs ??
|
|
112
|
+
DEFAULT_CLIENT_CONFIG.trackerTimeoutMs,
|
|
95
113
|
});
|
|
96
114
|
const assertValidFileSelection = (metadata, files) => {
|
|
97
115
|
const unknownFiles = getUnknownSelectedFiles(metadata, files);
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAkC,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAElD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAEvE,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AAElG,MAAM,CAAN,IAAY,aAKX;AALD,WAAY,aAAa;IACrB,oCAAmB,CAAA;IACnB,sCAAqB,CAAA;IACrB,0CAAyB,CAAA;IACzB,4CAA2B,CAAA;AAC/B,CAAC,EALW,aAAa,KAAb,aAAa,QAKxB;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAkC,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAElD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAEvE,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AAElG,MAAM,CAAN,IAAY,aAKX;AALD,WAAY,aAAa;IACrB,oCAAmB,CAAA;IACnB,sCAAqB,CAAA;IACrB,0CAAyB,CAAA;IACzB,4CAA2B,CAAA;AAC/B,CAAC,EALW,aAAa,KAAb,aAAa,QAKxB;AAiBD,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACjC,0BAA0B,EAAE,EAAE;IAC9B,aAAa,EAAE,EAAE;IACjB,cAAc,EAAE,CAAC;IACjB,oBAAoB,EAAE,KAAK;IAC3B,cAAc,EAAE,OAAO;IACvB,gBAAgB,EAAE,MAAM;IACxB,IAAI,EAAE,KAAK;IACX,qBAAqB,EAAE,GAAG;IAC1B,iBAAiB,EAAE,EAAE;IACrB,gBAAgB,EAAE,KAAK;CAe1B,CAAC;AAEF,MAAM,OAAO,MAAM;IAGc;IAFZ,MAAM,CAAa;IAEpC,YAA6B,SAAuB,EAAE;QAAzB,WAAM,GAAN,MAAM,CAAmB;QAClD,IAAI,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;IACjC,CAAC;IAEM,KAAK,CAAC,QAAQ,CACjB,KAEC,EACD,UAA2B,EAAE;QAE7B,OAAO,CAAC,aAAa,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,cAAc,GAAG,qBAAqB,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACnE,wBAAwB,CAAC,IAAI,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;QAErD,OAAO,CAAC,aAAa,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;QAEnE,OAAO,CAAC,aAAa,EAAE,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE;YACnC,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,iBAAiB,EAAE,cAAc,CAAC,iBAAiB;YACnD,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;YAC/B,cAAc,EAAE,cAAc,CAAC,cAAc;YAC7C,aAAa,EAAE,cAAc,CAAC,aAAa;YAC3C,SAAS,EAAE,cAAc,CAAC,oBAAoB;SACjD,CAAC,CAAC;QAEH,OAAO,CAAC,aAAa,EAAE,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;QACnD,OAAO,IAAI,OAAO,CACd,IAAI,EACJ,IAAI,EACJ,IAAI,eAAe,CAAC;YAChB,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,cAAc,CAAC,KAAK;YAC3B,eAAe,EAAE,cAAc,CAAC,eAAe;YAC/C,QAAQ,EAAE,IAAI;YACd,0BAA0B,EAAE,cAAc,CAAC,0BAA0B;YACrE,cAAc,EAAE,cAAc,CAAC,cAAc;YAC7C,gBAAgB,EAAE,cAAc,CAAC,gBAAgB;YACjD,qBAAqB,EAAE,cAAc,CAAC,qBAAqB;SAC9D,CAAC,EACF,6BAA6B,CAAC,cAAc,CAAC,KAAK,CAAC,EACnD,cAAc,CAAC,IAAI,CACtB,CAAC;IACN,CAAC;IAEM,KAAK,CAAC,OAAO,CAAC,KAEpB;QACG,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACvD,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAEO,KAAK,CAAC,UAAU,CACpB,IAAqB,EACrB,OAAwB,EACxB,MAA8B;QAE9B,IAAI,CAAC;YACD,OAAO,MAAM,UAAU,CAAC;gBACpB,IAAI;gBACJ,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,YAAY,EAAE,OAAO,CAAC,YAAY;gBAClC,SAAS,EAAE,MAAM,CAAC,gBAAgB;aACrC,CAAC,CAAC;QACP,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,sBAAsB,CAAC,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;YAC7C,MAAM,KAAK,CAAC;QAChB,CAAC;IACL,CAAC;CACJ;AAuBD,MAAM,sBAAsB,GAAG,CAAC,KAAc,EAAyB,EAAE,CACrE,KAAK,YAAY,YAAY;IAC7B,CAAC,KAAK,CAAC,IAAI,KAAK,gBAAgB,CAAC,eAAe;QAC5C,KAAK,CAAC,IAAI,KAAK,gBAAgB,CAAC,QAAQ;QACxC,KAAK,CAAC,IAAI,KAAK,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;AAE/D,MAAM,qBAAqB,GAAG,CAC1B,MAAoB,EACpB,OAAwB,EACF,EAAE,CAAC,CAAC;IAC1B,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,IAAI,IAAI;IAC5C,0BAA0B,EACtB,OAAO,CAAC,0BAA0B;QAClC,MAAM,CAAC,0BAA0B;QACjC,qBAAqB,CAAC,0BAA0B;IACpD,aAAa,EACT,OAAO,CAAC,aAAa,IAAI,MAAM,CAAC,aAAa,IAAI,qBAAqB,CAAC,aAAa;IACxF,cAAc,EACV,OAAO,CAAC,cAAc,IAAI,MAAM,CAAC,cAAc,IAAI,qBAAqB,CAAC,cAAc;IAC3F,eAAe,EAAE,OAAO,CAAC,eAAe,IAAI,MAAM,CAAC,eAAe,IAAI,OAAO,CAAC,GAAG,EAAE;IACnF,oBAAoB,EAChB,OAAO,CAAC,oBAAoB;QAC5B,MAAM,CAAC,oBAAoB;QAC3B,qBAAqB,CAAC,oBAAoB;IAC9C,cAAc,EACV,OAAO,CAAC,cAAc,IAAI,MAAM,CAAC,cAAc,IAAI,qBAAqB,CAAC,cAAc;IAC3F,gBAAgB,EACZ,OAAO,CAAC,gBAAgB;QACxB,MAAM,CAAC,gBAAgB;QACvB,qBAAqB,CAAC,gBAAgB;IAC1C,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,IAAI,qBAAqB,CAAC,IAAI;IAC/D,qBAAqB,EACjB,OAAO,CAAC,qBAAqB;QAC7B,MAAM,CAAC,qBAAqB;QAC5B,qBAAqB,CAAC,qBAAqB;IAC/C,iBAAiB,EACb,OAAO,CAAC,iBAAiB;QACzB,MAAM,CAAC,iBAAiB;QACxB,qBAAqB,CAAC,iBAAiB;IAC3C,gBAAgB,EACZ,OAAO,CAAC,gBAAgB;QACxB,MAAM,CAAC,gBAAgB;QACvB,qBAAqB,CAAC,gBAAgB;CAC7C,CAAC,CAAC;AAEH,MAAM,wBAAwB,GAAG,CAC7B,QAAyB,EACzB,KAAuC,EACnC,EAAE;IACN,MAAM,YAAY,GAAG,uBAAuB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC9D,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAEtC,MAAM,IAAI,WAAW,CACjB,eAAe,CAAC,sBAAsB,EACtC,mCAAmC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC/D,CAAC;AACN,CAAC,CAAC;AAIF,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAAE,KAAuB,EAAuB,EAAE;IAClF,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;IACpE,IAAI,KAAK,YAAY,UAAU;QAAE,OAAO,KAAK,CAAC;IAC9C,IAAI,KAAK,YAAY,WAAW;QAAE,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;IAE/D,MAAM,IAAI,WAAW,CACjB,eAAe,CAAC,8BAA8B,EAC9C,gCAAgC,CACnC,CAAC;AACN,CAAC,CAAC;AAEF,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
* Copyright (c) 2026 Nikola Nedeljkovic
|
|
3
3
|
* SPDX-License-Identifier: MIT
|
|
4
4
|
*/
|
|
5
|
-
export
|
|
5
|
+
export { Client, DEFAULT_CLIENT_CONFIG, DownloadState, TorrentClient } from './client';
|
|
6
6
|
export { ClientError, ClientErrorCode } from './client.error';
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
7
|
+
export type { ClientConfig, DownloadOptions, TorrentFileInput } from './client';
|
|
8
|
+
export { Torrent, TorrentState, TorrentParseError, TorrentParseErrorCode, TorrentStorageError, TorrentStorageErrorCode, PiecePlannerError, PiecePlannerErrorCode, } from './torrent/index';
|
|
9
|
+
export { PeerPoolError, PeerPoolErrorCode, PeerSessionError, PeerSessionErrorCode } from './peer';
|
|
9
10
|
export { TrackerError, TrackerErrorCode } from './tracker';
|
|
10
|
-
export type {
|
|
11
|
+
export type { DownloadProgress, DownloadProgressEventMode, TorrentFileSelection, TorrentFiles, TorrentMetadata, TorrentStats, TorrentStateChange, } from './torrent/index';
|
|
12
|
+
export type { TorrentFile } from './torrent/types';
|
|
11
13
|
export { BunTorrentError } from './utils/errors';
|
|
12
|
-
export type { BBytes, BDict, BInteger, BList, BValue, BencodeInput, TorrentFiles, TorrentStats, TorrentStateChange, } from './torrent/index';
|
package/dist/index.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Copyright (c) 2026 Nikola Nedeljkovic
|
|
3
3
|
* SPDX-License-Identifier: MIT
|
|
4
4
|
*/
|
|
5
|
-
export
|
|
5
|
+
export { Client, DEFAULT_CLIENT_CONFIG, DownloadState, TorrentClient } from './client';
|
|
6
6
|
export { ClientError, ClientErrorCode } from './client.error';
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
7
|
+
export { Torrent, TorrentState, TorrentParseError, TorrentParseErrorCode, TorrentStorageError, TorrentStorageErrorCode, PiecePlannerError, PiecePlannerErrorCode, } from './torrent/index';
|
|
8
|
+
export { PeerPoolError, PeerPoolErrorCode, PeerSessionError, PeerSessionErrorCode } from './peer';
|
|
9
9
|
export { TrackerError, TrackerErrorCode } from './tracker';
|
|
10
10
|
export { BunTorrentError } from './utils/errors';
|
|
11
11
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,qBAAqB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAG9D,OAAO,EACH,OAAO,EACP,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,GACxB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAClG,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAa3D,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type PeerDownloadStats = {
|
|
2
|
+
receivedBytes: number;
|
|
3
|
+
receivedBlocks: number;
|
|
4
|
+
timedOutRequests: number;
|
|
5
|
+
sentRequests: number;
|
|
6
|
+
completedPieces: number;
|
|
7
|
+
invalidPieces: number;
|
|
8
|
+
lastBlockAt: number | null;
|
|
9
|
+
totalRequestTimeMs: number;
|
|
10
|
+
completedRequests: number;
|
|
11
|
+
};
|
|
12
|
+
export declare class PeerScorer {
|
|
13
|
+
getScore(stats: PeerDownloadStats): number;
|
|
14
|
+
getRequestLimit(stats: PeerDownloadStats, defaultLimit: number): number;
|
|
15
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export class PeerScorer {
|
|
2
|
+
getScore(stats) {
|
|
3
|
+
const averageRequestTime = stats.completedRequests === 0
|
|
4
|
+
? Number.POSITIVE_INFINITY
|
|
5
|
+
: stats.totalRequestTimeMs / stats.completedRequests;
|
|
6
|
+
const timeoutPenalty = stats.timedOutRequests * 1000;
|
|
7
|
+
const invalidPenalty = stats.invalidPieces * 2000;
|
|
8
|
+
const speedBonus = stats.receivedBytes / Math.max(1, averageRequestTime);
|
|
9
|
+
return speedBonus + stats.completedPieces * 100 - timeoutPenalty - invalidPenalty;
|
|
10
|
+
}
|
|
11
|
+
getRequestLimit(stats, defaultLimit) {
|
|
12
|
+
if (stats.timedOutRequests >= 3 && stats.completedRequests === 0)
|
|
13
|
+
return 1;
|
|
14
|
+
if (stats.completedRequests < 3)
|
|
15
|
+
return defaultLimit;
|
|
16
|
+
const timeoutRate = stats.timedOutRequests / Math.max(1, stats.sentRequests);
|
|
17
|
+
if (timeoutRate > 0.5)
|
|
18
|
+
return Math.max(1, Math.floor(defaultLimit / 4));
|
|
19
|
+
if (timeoutRate > 0.25)
|
|
20
|
+
return Math.max(1, Math.floor(defaultLimit / 2));
|
|
21
|
+
return defaultLimit;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=PeerScorer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PeerScorer.js","sourceRoot":"","sources":["../../../src/torrent/download/PeerScorer.ts"],"names":[],"mappings":"AAYA,MAAM,OAAO,UAAU;IACZ,QAAQ,CAAC,KAAwB;QACpC,MAAM,kBAAkB,GACpB,KAAK,CAAC,iBAAiB,KAAK,CAAC;YACzB,CAAC,CAAC,MAAM,CAAC,iBAAiB;YAC1B,CAAC,CAAC,KAAK,CAAC,kBAAkB,GAAG,KAAK,CAAC,iBAAiB,CAAC;QAE7D,MAAM,cAAc,GAAG,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC;QACrD,MAAM,cAAc,GAAG,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC;QAClD,MAAM,UAAU,GAAG,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC;QAEzE,OAAO,UAAU,GAAG,KAAK,CAAC,eAAe,GAAG,GAAG,GAAG,cAAc,GAAG,cAAc,CAAC;IACtF,CAAC;IAEM,eAAe,CAAC,KAAwB,EAAE,YAAoB;QACjE,IAAI,KAAK,CAAC,gBAAgB,IAAI,CAAC,IAAI,KAAK,CAAC,iBAAiB,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QAC3E,IAAI,KAAK,CAAC,iBAAiB,GAAG,CAAC;YAAE,OAAO,YAAY,CAAC;QAErD,MAAM,WAAW,GAAG,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;QAE7E,IAAI,WAAW,GAAG,GAAG;YAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC;QACxE,IAAI,WAAW,GAAG,IAAI;YAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC;QAEzE,OAAO,YAAY,CAAC;IACxB,CAAC;CACJ"}
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
export { DownloadManager } from './manager';
|
|
2
|
-
export type { DownloadManagerOptions,
|
|
2
|
+
export type { DownloadManagerOptions, DownloadProgress, DownloadProgressEventMode, DownloadProgressListener, } from './manager';
|
|
3
|
+
export { PeerScorer } from './PeerScorer';
|
|
4
|
+
export type { PeerDownloadStats } from './PeerScorer';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/torrent/download/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/torrent/download/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAO5C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -1,23 +1,14 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
1
|
+
import type { PeerPool } from '../../peer/pool';
|
|
2
|
+
import type { PeerSession } from '../../peer/session';
|
|
3
|
+
import type { PiecePlanner } from '../pieces';
|
|
3
4
|
import type { TorrentMetadata } from '../types';
|
|
4
5
|
import { writeValidatedPiece } from '../storage';
|
|
5
6
|
import type { TorrentFileSelection } from '../file-selection';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
readonly peerAvailability: PieceAvailability;
|
|
9
|
-
onClose(callback: () => void): () => void;
|
|
10
|
-
onMessage(callback: (message: PeerMessage) => void): () => void;
|
|
11
|
-
sendMessage(message: PeerMessage): void;
|
|
12
|
-
};
|
|
13
|
-
export type DownloadPeerPool<TPeer extends DownloadPeerSession = DownloadPeerSession> = {
|
|
14
|
-
readonly done?: Promise<readonly TPeer[]>;
|
|
15
|
-
onSession(callback: (session: TPeer) => void): () => void;
|
|
16
|
-
};
|
|
17
|
-
export type DownloadManagerOptions<TPeer extends DownloadPeerSession = DownloadPeerSession> = {
|
|
7
|
+
import { type PeerDownloadStats } from './PeerScorer';
|
|
8
|
+
export type DownloadManagerOptions = {
|
|
18
9
|
metadata: TorrentMetadata;
|
|
19
10
|
outputDirectory: string;
|
|
20
|
-
peerPool:
|
|
11
|
+
peerPool: PeerPool;
|
|
21
12
|
files?: TorrentFileSelection;
|
|
22
13
|
maxInFlightRequestsPerPeer?: number;
|
|
23
14
|
progressEvents?: DownloadProgressEventMode;
|
|
@@ -38,7 +29,7 @@ export type DownloadProgress = {
|
|
|
38
29
|
speed: string;
|
|
39
30
|
};
|
|
40
31
|
export type DownloadProgressListener = (progress: DownloadProgress) => void;
|
|
41
|
-
export declare class DownloadManager
|
|
32
|
+
export declare class DownloadManager {
|
|
42
33
|
private readonly options;
|
|
43
34
|
readonly done: Promise<void>;
|
|
44
35
|
private readonly planner;
|
|
@@ -55,10 +46,13 @@ export declare class DownloadManager<TPeer extends DownloadPeerSession = Downloa
|
|
|
55
46
|
private closed;
|
|
56
47
|
private resolveDone;
|
|
57
48
|
private rejectDone;
|
|
58
|
-
|
|
49
|
+
private readonly peerScorer;
|
|
50
|
+
constructor(options: DownloadManagerOptions);
|
|
59
51
|
get progress(): DownloadProgress;
|
|
52
|
+
private getProgressTotals;
|
|
60
53
|
start(): void;
|
|
61
54
|
onProgress(listener: DownloadProgressListener): () => void;
|
|
55
|
+
getPeerStats(peer: PeerSession): PeerDownloadStats | undefined;
|
|
62
56
|
close(): void;
|
|
63
57
|
private attachPeer;
|
|
64
58
|
private detachPeer;
|
|
@@ -69,8 +63,16 @@ export declare class DownloadManager<TPeer extends DownloadPeerSession = Downloa
|
|
|
69
63
|
private pumpPeer;
|
|
70
64
|
private handleRequestTimeout;
|
|
71
65
|
private sendInterestedIfUseful;
|
|
66
|
+
private hasUsefulRequest;
|
|
67
|
+
private getPeerRequestLimit;
|
|
68
|
+
private sendRequest;
|
|
69
|
+
private rollbackFailedSend;
|
|
70
|
+
private takePendingPieceRequest;
|
|
71
|
+
private takePendingRequest;
|
|
72
72
|
private resetPieceForRetry;
|
|
73
|
+
private dropPendingRequestsForPiece;
|
|
73
74
|
private pumpPeers;
|
|
75
|
+
private recordReceivedBlock;
|
|
74
76
|
private clearPendingTimeouts;
|
|
75
77
|
private emitProgress;
|
|
76
78
|
private updateSpeed;
|
|
@@ -2,6 +2,7 @@ import { createPiecePlanner } from '../pieces';
|
|
|
2
2
|
import { writeValidatedPiece } from '../storage';
|
|
3
3
|
import { formatBytes } from '../../utils/formats';
|
|
4
4
|
import { getSelectedPieceIndexes } from '../file-selection';
|
|
5
|
+
import { PeerScorer } from './PeerScorer';
|
|
5
6
|
const DEFAULT_MAX_IN_FLIGHT_REQUESTS_PER_PEER = 20;
|
|
6
7
|
const DEFAULT_PROGRESS_EVENTS = 'piece';
|
|
7
8
|
const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
|
|
@@ -23,6 +24,7 @@ export class DownloadManager {
|
|
|
23
24
|
closed = false;
|
|
24
25
|
resolveDone;
|
|
25
26
|
rejectDone;
|
|
27
|
+
peerScorer = new PeerScorer();
|
|
26
28
|
constructor(options) {
|
|
27
29
|
this.options = options;
|
|
28
30
|
this.planner =
|
|
@@ -43,6 +45,15 @@ export class DownloadManager {
|
|
|
43
45
|
});
|
|
44
46
|
}
|
|
45
47
|
get progress() {
|
|
48
|
+
const totals = this.getProgressTotals();
|
|
49
|
+
return {
|
|
50
|
+
...totals,
|
|
51
|
+
percent: totals.totalBytes === 0 ? 1 : totals.downloadedBytes / totals.totalBytes,
|
|
52
|
+
speedBytesPerSecond: this.currentSpeedBytesPerSecond,
|
|
53
|
+
speed: `${formatBytes(this.currentSpeedBytesPerSecond)}ps`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
getProgressTotals() {
|
|
46
57
|
let receivedBytes = 0;
|
|
47
58
|
let downloadedBytes = 0;
|
|
48
59
|
let totalBytes = 0;
|
|
@@ -59,14 +70,12 @@ export class DownloadManager {
|
|
|
59
70
|
downloadedBytes,
|
|
60
71
|
totalPieces: this.planner.totalPieces,
|
|
61
72
|
completedPieces: this.planner.completedPieces,
|
|
62
|
-
percent: totalBytes === 0 ? 1 : downloadedBytes / totalBytes,
|
|
63
|
-
speedBytesPerSecond: this.currentSpeedBytesPerSecond,
|
|
64
|
-
speed: `${formatBytes(this.currentSpeedBytesPerSecond)}ps`,
|
|
65
73
|
};
|
|
66
74
|
}
|
|
67
75
|
start() {
|
|
68
76
|
if (this.closed || this.offSession)
|
|
69
77
|
return;
|
|
78
|
+
// The peer pool may already have connected sessions, so onSession is both a replay and a subscription.
|
|
70
79
|
this.offSession = this.options.peerPool.onSession((session) => this.attachPeer(session));
|
|
71
80
|
void this.options.peerPool.done?.then((sessions) => {
|
|
72
81
|
if (sessions.length === 0)
|
|
@@ -80,6 +89,12 @@ export class DownloadManager {
|
|
|
80
89
|
this.progressListeners.delete(listener);
|
|
81
90
|
};
|
|
82
91
|
}
|
|
92
|
+
getPeerStats(peer) {
|
|
93
|
+
const stats = this.peerStates.get(peer)?.stats;
|
|
94
|
+
if (!stats)
|
|
95
|
+
return undefined;
|
|
96
|
+
return { ...stats };
|
|
97
|
+
}
|
|
83
98
|
close() {
|
|
84
99
|
if (this.closed)
|
|
85
100
|
return;
|
|
@@ -99,6 +114,7 @@ export class DownloadManager {
|
|
|
99
114
|
peer,
|
|
100
115
|
pending: [],
|
|
101
116
|
interestedSent: false,
|
|
117
|
+
stats: createInitialPeerStats(),
|
|
102
118
|
offClose: peer.onClose(() => this.handlePeerClosed(peer)),
|
|
103
119
|
offMessage: peer.onMessage((message) => this.handlePeerMessage(peer, message)),
|
|
104
120
|
};
|
|
@@ -108,6 +124,7 @@ export class DownloadManager {
|
|
|
108
124
|
detachPeer(state) {
|
|
109
125
|
state.offClose();
|
|
110
126
|
state.offMessage();
|
|
127
|
+
// Any in-flight blocks owned by this peer must become available for another peer.
|
|
111
128
|
this.clearPendingTimeouts(state.pending);
|
|
112
129
|
this.planner.resetPeerRequests(state.pending.map((pending) => pending.request));
|
|
113
130
|
state.pending = [];
|
|
@@ -123,6 +140,7 @@ export class DownloadManager {
|
|
|
123
140
|
const state = this.peerStates.get(peer);
|
|
124
141
|
if (!state || this.closed)
|
|
125
142
|
return;
|
|
143
|
+
// Availability/choke changes are scheduling signals even when no block data arrived.
|
|
126
144
|
if (message.type === 'unchoke' || message.type === 'have' || message.type === 'bitfield') {
|
|
127
145
|
this.pumpPeer(state);
|
|
128
146
|
return;
|
|
@@ -132,17 +150,13 @@ export class DownloadManager {
|
|
|
132
150
|
}
|
|
133
151
|
}
|
|
134
152
|
async handlePiece(state, message) {
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
request.length === message.block.byteLength);
|
|
138
|
-
if (pendingIndex === -1)
|
|
153
|
+
const pending = this.takePendingPieceRequest(state, message);
|
|
154
|
+
if (!pending)
|
|
139
155
|
return;
|
|
140
|
-
|
|
141
|
-
if (pending)
|
|
142
|
-
clearTimeout(pending.timeout);
|
|
156
|
+
this.recordReceivedBlock(state, pending, message);
|
|
143
157
|
const completion = this.planner.receiveBlock(message);
|
|
144
158
|
if (completion) {
|
|
145
|
-
await this.handleCompletion(completion);
|
|
159
|
+
await this.handleCompletion(state, completion);
|
|
146
160
|
this.emitProgress();
|
|
147
161
|
}
|
|
148
162
|
else if (this.progressEvents === 'block') {
|
|
@@ -151,78 +165,140 @@ export class DownloadManager {
|
|
|
151
165
|
this.pumpPeer(state);
|
|
152
166
|
this.resolveIfComplete();
|
|
153
167
|
}
|
|
154
|
-
async handleCompletion(completion) {
|
|
168
|
+
async handleCompletion(state, completion) {
|
|
155
169
|
const result = await this.writeValidated(this.options.metadata, completion, {
|
|
156
170
|
outputDirectory: this.options.outputDirectory,
|
|
157
171
|
files: this.options.files,
|
|
158
172
|
});
|
|
159
173
|
if (!result.valid) {
|
|
174
|
+
state.stats.invalidPieces += 1;
|
|
160
175
|
this.resetPieceForRetry(completion.pieceIndex);
|
|
176
|
+
return;
|
|
161
177
|
}
|
|
178
|
+
state.stats.completedPieces += 1;
|
|
162
179
|
}
|
|
163
180
|
pumpPeer(state) {
|
|
164
|
-
if (this.planner.complete)
|
|
181
|
+
if (this.closed || this.planner.complete)
|
|
165
182
|
return;
|
|
166
183
|
this.sendInterestedIfUseful(state);
|
|
167
184
|
if (state.peer.choked)
|
|
168
185
|
return;
|
|
169
|
-
|
|
186
|
+
// The scorer can throttle unreliable peers without disconnecting them.
|
|
187
|
+
const requestLimit = this.getPeerRequestLimit(state);
|
|
188
|
+
while (state.pending.length < requestLimit) {
|
|
170
189
|
const request = this.planner.nextRequest(state.peer.peerAvailability);
|
|
171
190
|
if (!request)
|
|
172
191
|
break;
|
|
173
|
-
this.
|
|
174
|
-
|
|
175
|
-
unrefTimer(timeout);
|
|
176
|
-
state.pending.push({
|
|
177
|
-
request,
|
|
178
|
-
timeout,
|
|
179
|
-
});
|
|
180
|
-
state.peer.sendMessage(request);
|
|
192
|
+
if (!this.sendRequest(state, request))
|
|
193
|
+
break;
|
|
181
194
|
}
|
|
182
195
|
}
|
|
183
196
|
handleRequestTimeout(state, request) {
|
|
184
197
|
if (this.closed || this.planner.complete)
|
|
185
198
|
return;
|
|
186
|
-
const
|
|
187
|
-
if (
|
|
199
|
+
const pending = this.takePendingRequest(state, request);
|
|
200
|
+
if (!pending)
|
|
188
201
|
return;
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
clearTimeout(pending.timeout);
|
|
202
|
+
// Prefer retrying timed-out work on other peers before giving the same peer another slot.
|
|
203
|
+
state.stats.timedOutRequests += 1;
|
|
192
204
|
this.planner.resetPending(request);
|
|
193
205
|
this.pumpPeers(state);
|
|
194
206
|
}
|
|
195
207
|
sendInterestedIfUseful(state) {
|
|
196
208
|
if (state.interestedSent)
|
|
197
209
|
return;
|
|
198
|
-
if (!this.
|
|
210
|
+
if (!this.hasUsefulRequest(state))
|
|
199
211
|
return;
|
|
200
212
|
state.peer.sendMessage({ type: 'interested' });
|
|
201
213
|
state.interestedSent = true;
|
|
202
214
|
}
|
|
215
|
+
hasUsefulRequest(state) {
|
|
216
|
+
return this.planner.nextRequest(state.peer.peerAvailability) !== null;
|
|
217
|
+
}
|
|
218
|
+
getPeerRequestLimit(state) {
|
|
219
|
+
return this.peerScorer.getRequestLimit(state.stats, this.maxInFlightRequestsPerPeer);
|
|
220
|
+
}
|
|
221
|
+
sendRequest(state, request) {
|
|
222
|
+
this.planner.markPending(request);
|
|
223
|
+
// Keep the timer tied to this exact request so late blocks can cancel it deterministically.
|
|
224
|
+
const timeout = setTimeout(() => this.handleRequestTimeout(state, request), this.requestTimeoutMs);
|
|
225
|
+
unrefTimer(timeout);
|
|
226
|
+
state.pending.push({
|
|
227
|
+
request,
|
|
228
|
+
timeout,
|
|
229
|
+
requestedAt: Date.now(),
|
|
230
|
+
});
|
|
231
|
+
state.stats.sentRequests += 1;
|
|
232
|
+
try {
|
|
233
|
+
state.peer.sendMessage(request);
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
this.rollbackFailedSend(state, request);
|
|
238
|
+
this.handlePeerClosed(state.peer);
|
|
239
|
+
this.pumpPeers();
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
rollbackFailedSend(state, request) {
|
|
244
|
+
const pending = this.takePendingRequest(state, request);
|
|
245
|
+
if (!pending)
|
|
246
|
+
return;
|
|
247
|
+
this.planner.resetPending(request);
|
|
248
|
+
}
|
|
249
|
+
takePendingPieceRequest(state, message) {
|
|
250
|
+
return this.takePendingRequest(state, {
|
|
251
|
+
type: 'request',
|
|
252
|
+
pieceIndex: message.pieceIndex,
|
|
253
|
+
offset: message.offset,
|
|
254
|
+
length: message.block.byteLength,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
takePendingRequest(state, request) {
|
|
258
|
+
const pendingIndex = state.pending.findIndex((pending) => isSameRequest(pending.request, request));
|
|
259
|
+
if (pendingIndex === -1)
|
|
260
|
+
return null;
|
|
261
|
+
const [pending] = state.pending.splice(pendingIndex, 1);
|
|
262
|
+
if (!pending)
|
|
263
|
+
return null;
|
|
264
|
+
clearTimeout(pending.timeout);
|
|
265
|
+
return pending;
|
|
266
|
+
}
|
|
203
267
|
resetPieceForRetry(pieceIndex) {
|
|
204
268
|
this.planner.resetPiece(pieceIndex);
|
|
269
|
+
// A bad piece invalidates every pending block for that piece, across all peers.
|
|
205
270
|
for (const state of this.peerStates.values()) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
271
|
+
this.dropPendingRequestsForPiece(state, pieceIndex);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
dropPendingRequestsForPiece(state, pieceIndex) {
|
|
275
|
+
const kept = [];
|
|
276
|
+
for (const pending of state.pending) {
|
|
277
|
+
if (pending.request.pieceIndex === pieceIndex) {
|
|
278
|
+
clearTimeout(pending.timeout);
|
|
279
|
+
continue;
|
|
214
280
|
}
|
|
215
|
-
|
|
281
|
+
kept.push(pending);
|
|
216
282
|
}
|
|
283
|
+
state.pending = kept;
|
|
217
284
|
}
|
|
218
285
|
pumpPeers(last) {
|
|
219
|
-
|
|
286
|
+
const states = [...this.peerStates.values()].sort((a, b) => this.peerScorer.getScore(b.stats) - this.peerScorer.getScore(a.stats));
|
|
287
|
+
for (const state of states) {
|
|
220
288
|
if (state !== last)
|
|
221
289
|
this.pumpPeer(state);
|
|
222
290
|
}
|
|
223
291
|
if (last)
|
|
224
292
|
this.pumpPeer(last);
|
|
225
293
|
}
|
|
294
|
+
recordReceivedBlock(state, pending, message) {
|
|
295
|
+
const now = Date.now();
|
|
296
|
+
state.stats.receivedBytes += message.block.byteLength;
|
|
297
|
+
state.stats.receivedBlocks += 1;
|
|
298
|
+
state.stats.completedRequests += 1;
|
|
299
|
+
state.stats.totalRequestTimeMs += Math.max(0, now - pending.requestedAt);
|
|
300
|
+
state.stats.lastBlockAt = now;
|
|
301
|
+
}
|
|
226
302
|
clearPendingTimeouts(pending) {
|
|
227
303
|
for (const request of pending)
|
|
228
304
|
clearTimeout(request.timeout);
|
|
@@ -262,6 +338,17 @@ export class DownloadManager {
|
|
|
262
338
|
}
|
|
263
339
|
}
|
|
264
340
|
const isSameRequest = (a, b) => a.pieceIndex === b.pieceIndex && a.offset === b.offset && a.length === b.length;
|
|
341
|
+
const createInitialPeerStats = () => ({
|
|
342
|
+
receivedBytes: 0,
|
|
343
|
+
receivedBlocks: 0,
|
|
344
|
+
timedOutRequests: 0,
|
|
345
|
+
sentRequests: 0,
|
|
346
|
+
completedPieces: 0,
|
|
347
|
+
invalidPieces: 0,
|
|
348
|
+
lastBlockAt: null,
|
|
349
|
+
totalRequestTimeMs: 0,
|
|
350
|
+
completedRequests: 0,
|
|
351
|
+
});
|
|
265
352
|
const unrefTimer = (timer) => {
|
|
266
353
|
if (typeof timer === 'object' && timer && 'unref' in timer) {
|
|
267
354
|
timer.unref();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../src/torrent/download/manager.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../src/torrent/download/manager.ts"],"names":[],"mappings":"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"}
|
package/dist/torrent/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export { BencodeDecodeError, BencodeDecodeErrorCode, BencodeEncodeError, Bencode
|
|
|
10
10
|
export { TorrentParseError, TorrentParseErrorCode } from './parser/parser.error';
|
|
11
11
|
export type { BBytes, BDict, BInteger, BList, BValue, BencodeInput } from './bencode';
|
|
12
12
|
export type { PieceAvailability, PieceBlock, PieceBlockRequest, PieceCompletion, PiecePlanner, PiecePlannerOptions, PieceProgress, PieceStatus, PieceValidationResult, } from './pieces';
|
|
13
|
-
export type { DownloadManagerOptions,
|
|
13
|
+
export type { DownloadManagerOptions, DownloadProgress, DownloadProgressEventMode, DownloadProgressListener, PeerDownloadStats, } from './download';
|
|
14
14
|
export type { TorrentFileSelection } from './file-selection';
|
|
15
15
|
export type { FileWrite, WritePieceOptions } from './storage';
|
|
16
16
|
export type { TorrentFiles, TorrentStateChange, TorrentStats } from './session/index';
|
|
@@ -22,7 +22,7 @@ export type TorrentEventMap = {
|
|
|
22
22
|
close: [];
|
|
23
23
|
done: [];
|
|
24
24
|
error: [error: unknown];
|
|
25
|
-
peer: [
|
|
25
|
+
peer: [stats: TorrentStats];
|
|
26
26
|
progress: [progress: DownloadProgress];
|
|
27
27
|
state: [change: TorrentStateChange];
|
|
28
28
|
};
|
|
@@ -55,11 +55,13 @@ export declare class Torrent {
|
|
|
55
55
|
private readonly peerPool;
|
|
56
56
|
private readonly downloadManager?;
|
|
57
57
|
private readonly selectedFiles?;
|
|
58
|
+
private readonly seed;
|
|
58
59
|
readonly done: Promise<void>;
|
|
59
60
|
private readonly listeners;
|
|
60
61
|
private currentState;
|
|
61
62
|
private lastError;
|
|
62
|
-
|
|
63
|
+
private resourcesClosed;
|
|
64
|
+
constructor(metadata: TorrentMetadata, peerPool: TorrentPeerPool, downloadManager?: TorrentDownloadManager | undefined, selectedFiles?: (Set<string> | null) | undefined, seed?: false);
|
|
63
65
|
get state(): TorrentState;
|
|
64
66
|
get error(): unknown;
|
|
65
67
|
get stats(): TorrentStats;
|
|
@@ -67,6 +69,7 @@ export declare class Torrent {
|
|
|
67
69
|
get files(): TorrentFiles;
|
|
68
70
|
on<TEvent extends TorrentEventName>(event: TEvent, listener: TorrentEventListener<TEvent>): () => void;
|
|
69
71
|
close(): void;
|
|
72
|
+
private closeResources;
|
|
70
73
|
private setState;
|
|
71
74
|
private emit;
|
|
72
75
|
private getListeners;
|
|
@@ -10,15 +10,18 @@ export class Torrent {
|
|
|
10
10
|
peerPool;
|
|
11
11
|
downloadManager;
|
|
12
12
|
selectedFiles;
|
|
13
|
+
seed;
|
|
13
14
|
done;
|
|
14
15
|
listeners = new Map();
|
|
15
16
|
currentState = TorrentState.DOWNLOADING;
|
|
16
17
|
lastError;
|
|
17
|
-
|
|
18
|
+
resourcesClosed = false;
|
|
19
|
+
constructor(metadata, peerPool, downloadManager, selectedFiles, seed = false) {
|
|
18
20
|
this.metadata = metadata;
|
|
19
21
|
this.peerPool = peerPool;
|
|
20
22
|
this.downloadManager = downloadManager;
|
|
21
23
|
this.selectedFiles = selectedFiles;
|
|
24
|
+
this.seed = seed;
|
|
22
25
|
this.downloadManager?.onProgress((progress) => this.emit('progress', progress));
|
|
23
26
|
this.downloadManager?.start();
|
|
24
27
|
this.done = downloadManager?.done ?? peerPool.done.then(() => undefined);
|
|
@@ -27,12 +30,15 @@ export class Torrent {
|
|
|
27
30
|
return;
|
|
28
31
|
this.setState(TorrentState.COMPLETED);
|
|
29
32
|
this.emit('done');
|
|
33
|
+
if (!this.seed)
|
|
34
|
+
this.closeResources();
|
|
30
35
|
}, (error) => {
|
|
31
36
|
if (this.currentState === TorrentState.CLOSED)
|
|
32
37
|
return;
|
|
33
38
|
this.lastError = error;
|
|
34
39
|
this.setState(TorrentState.FAILED);
|
|
35
40
|
this.emit('error', error);
|
|
41
|
+
this.closeResources();
|
|
36
42
|
});
|
|
37
43
|
}
|
|
38
44
|
get state() {
|
|
@@ -72,8 +78,8 @@ export class Torrent {
|
|
|
72
78
|
}
|
|
73
79
|
on(event, listener) {
|
|
74
80
|
if (event === 'peer') {
|
|
75
|
-
return this.peerPool.onSession((
|
|
76
|
-
listener(
|
|
81
|
+
return this.peerPool.onSession(() => {
|
|
82
|
+
listener(this.stats);
|
|
77
83
|
});
|
|
78
84
|
}
|
|
79
85
|
const listeners = this.getListeners(event);
|
|
@@ -85,11 +91,17 @@ export class Torrent {
|
|
|
85
91
|
close() {
|
|
86
92
|
if (this.currentState === TorrentState.CLOSED)
|
|
87
93
|
return;
|
|
88
|
-
this.
|
|
89
|
-
this.peerPool.close();
|
|
94
|
+
this.closeResources();
|
|
90
95
|
this.setState(TorrentState.CLOSED);
|
|
91
96
|
this.emit('close');
|
|
92
97
|
}
|
|
98
|
+
closeResources() {
|
|
99
|
+
if (this.resourcesClosed)
|
|
100
|
+
return;
|
|
101
|
+
this.resourcesClosed = true;
|
|
102
|
+
this.downloadManager?.close();
|
|
103
|
+
this.peerPool.close();
|
|
104
|
+
}
|
|
93
105
|
setState(state) {
|
|
94
106
|
if (this.currentState === state)
|
|
95
107
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/torrent/session/index.ts"],"names":[],"mappings":"AAYA,MAAM,CAAN,IAAY,YAKX;AALD,WAAY,YAAY;IACpB,2CAA2B,CAAA;IAC3B,uCAAuB,CAAA;IACvB,iCAAiB,CAAA;IACjB,iCAAiB,CAAA;AACrB,CAAC,EALW,YAAY,KAAZ,YAAY,QAKvB;AA+CD,MAAM,OAAO,OAAO;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/torrent/session/index.ts"],"names":[],"mappings":"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"}
|