bun-torrent 0.0.5-beta → 0.0.7

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.
Files changed (156) hide show
  1. package/README.md +80 -6
  2. package/dist/app.d.ts +2 -0
  3. package/dist/app.js +136 -0
  4. package/dist/app.js.map +1 -0
  5. package/dist/client.d.ts +30 -6
  6. package/dist/client.error.d.ts +1 -0
  7. package/dist/client.error.js +1 -0
  8. package/dist/client.error.js.map +1 -1
  9. package/dist/client.js +66 -6
  10. package/dist/client.js.map +1 -1
  11. package/dist/configs/defaults.d.ts +20 -0
  12. package/dist/configs/defaults.js +15 -0
  13. package/dist/configs/defaults.js.map +1 -1
  14. package/dist/dht/DhtClient.d.ts +52 -0
  15. package/dist/dht/DhtClient.js +279 -0
  16. package/dist/dht/DhtClient.js.map +1 -0
  17. package/dist/dht/KBucket.d.ts +12 -0
  18. package/dist/dht/KBucket.js +43 -0
  19. package/dist/dht/KBucket.js.map +1 -0
  20. package/dist/dht/RoutingTable.d.ts +19 -0
  21. package/dist/dht/RoutingTable.js +75 -0
  22. package/dist/dht/RoutingTable.js.map +1 -0
  23. package/dist/dht/errors.d.ts +19 -0
  24. package/dist/dht/errors.js +24 -0
  25. package/dist/dht/errors.js.map +1 -0
  26. package/dist/dht/index.d.ts +8 -0
  27. package/dist/dht/index.js +5 -0
  28. package/dist/dht/index.js.map +1 -0
  29. package/dist/dht/krpc/TransactionId.d.ts +12 -0
  30. package/dist/dht/krpc/TransactionId.js +23 -0
  31. package/dist/dht/krpc/TransactionId.js.map +1 -0
  32. package/dist/dht/krpc/index.d.ts +5 -0
  33. package/dist/dht/krpc/index.js +4 -0
  34. package/dist/dht/krpc/index.js.map +1 -0
  35. package/dist/dht/krpc/messages.d.ts +3 -0
  36. package/dist/dht/krpc/messages.js +163 -0
  37. package/dist/dht/krpc/messages.js.map +1 -0
  38. package/dist/dht/krpc/types.d.ts +54 -0
  39. package/dist/dht/krpc/types.js +14 -0
  40. package/dist/dht/krpc/types.js.map +1 -0
  41. package/dist/dht/routing-table.d.ts +2 -0
  42. package/dist/dht/routing-table.js +2 -0
  43. package/dist/dht/routing-table.js.map +1 -0
  44. package/dist/dht/utils/compact.d.ts +17 -0
  45. package/dist/dht/utils/compact.js +81 -0
  46. package/dist/dht/utils/compact.js.map +1 -0
  47. package/dist/dht/utils/distance.d.ts +5 -0
  48. package/dist/dht/utils/distance.js +25 -0
  49. package/dist/dht/utils/distance.js.map +1 -0
  50. package/dist/index.d.ts +1 -0
  51. package/dist/index.js +1 -0
  52. package/dist/index.js.map +1 -1
  53. package/dist/magnet/base32/errors.d.ts +8 -0
  54. package/dist/magnet/base32/errors.js +13 -0
  55. package/dist/magnet/base32/errors.js.map +1 -0
  56. package/dist/magnet/base32/index.d.ts +3 -0
  57. package/dist/magnet/base32/index.js +24 -0
  58. package/dist/magnet/base32/index.js.map +1 -0
  59. package/dist/magnet/index.d.ts +2 -0
  60. package/dist/magnet/index.js +3 -0
  61. package/dist/magnet/index.js.map +1 -0
  62. package/dist/magnet/parser/errors.d.ts +13 -0
  63. package/dist/magnet/parser/errors.js +19 -0
  64. package/dist/magnet/parser/errors.js.map +1 -0
  65. package/dist/magnet/parser/index.d.ts +16 -0
  66. package/dist/magnet/parser/index.js +105 -0
  67. package/dist/magnet/parser/index.js.map +1 -0
  68. package/dist/magnet/parser/meta.d.ts +2 -0
  69. package/dist/magnet/parser/meta.js +68 -0
  70. package/dist/magnet/parser/meta.js.map +1 -0
  71. package/dist/magnet/parser/types.d.ts +5 -0
  72. package/dist/magnet/parser/types.js +2 -0
  73. package/dist/magnet/parser/types.js.map +1 -0
  74. package/dist/peer/PeerPieceAvailability.d.ts +50 -0
  75. package/dist/peer/PeerPieceAvailability.js +71 -0
  76. package/dist/peer/PeerPieceAvailability.js.map +1 -0
  77. package/dist/peer/availability.d.ts +2 -50
  78. package/dist/peer/availability.js +1 -70
  79. package/dist/peer/availability.js.map +1 -1
  80. package/dist/peer/extended/connection.d.ts +32 -0
  81. package/dist/peer/extended/connection.js +159 -0
  82. package/dist/peer/extended/connection.js.map +1 -0
  83. package/dist/peer/extended/errors.d.ts +15 -0
  84. package/dist/peer/extended/errors.js +20 -0
  85. package/dist/peer/extended/errors.js.map +1 -0
  86. package/dist/peer/extended/index.d.ts +5 -0
  87. package/dist/peer/extended/index.js +4 -0
  88. package/dist/peer/extended/index.js.map +1 -0
  89. package/dist/peer/extended/metadata/MetadataAssembler.d.ts +12 -0
  90. package/dist/peer/extended/metadata/MetadataAssembler.js +44 -0
  91. package/dist/peer/extended/metadata/MetadataAssembler.js.map +1 -0
  92. package/dist/peer/extended/metadata/assembler.d.ts +1 -0
  93. package/dist/peer/extended/metadata/assembler.js +2 -0
  94. package/dist/peer/extended/metadata/assembler.js.map +1 -0
  95. package/dist/peer/extended/metadata/index.d.ts +9 -0
  96. package/dist/peer/extended/metadata/index.js +86 -0
  97. package/dist/peer/extended/metadata/index.js.map +1 -0
  98. package/dist/peer/extended/metadata/messages.d.ts +6 -0
  99. package/dist/peer/extended/metadata/messages.js +20 -0
  100. package/dist/peer/extended/metadata/messages.js.map +1 -0
  101. package/dist/peer/extended/protocol.d.ts +8 -0
  102. package/dist/peer/extended/protocol.js +31 -0
  103. package/dist/peer/extended/protocol.js.map +1 -0
  104. package/dist/peer/index.d.ts +2 -2
  105. package/dist/peer/index.js +1 -1
  106. package/dist/peer/index.js.map +1 -1
  107. package/dist/peer/messages/index.js +5 -0
  108. package/dist/peer/messages/index.js.map +1 -1
  109. package/dist/peer/messages/types.d.ts +8 -2
  110. package/dist/peer/messages/types.js +1 -0
  111. package/dist/peer/messages/types.js.map +1 -1
  112. package/dist/peer/pool/PeerPool.d.ts +65 -0
  113. package/dist/peer/pool/PeerPool.js +206 -0
  114. package/dist/peer/pool/PeerPool.js.map +1 -0
  115. package/dist/peer/pool/index.d.ts +2 -65
  116. package/dist/peer/pool/index.js +1 -205
  117. package/dist/peer/pool/index.js.map +1 -1
  118. package/dist/peer/session/PeerSession.d.ts +35 -0
  119. package/dist/peer/session/PeerSession.js +200 -0
  120. package/dist/peer/session/PeerSession.js.map +1 -0
  121. package/dist/peer/session/index.d.ts +2 -35
  122. package/dist/peer/session/index.js +1 -199
  123. package/dist/peer/session/index.js.map +1 -1
  124. package/dist/torrent/bencode/decoder.d.ts +4 -0
  125. package/dist/torrent/bencode/decoder.js +9 -0
  126. package/dist/torrent/bencode/decoder.js.map +1 -1
  127. package/dist/torrent/download/DownloadManager.d.ts +85 -0
  128. package/dist/torrent/download/DownloadManager.js +383 -0
  129. package/dist/torrent/download/DownloadManager.js.map +1 -0
  130. package/dist/torrent/download/index.d.ts +2 -2
  131. package/dist/torrent/download/index.js +1 -1
  132. package/dist/torrent/download/index.js.map +1 -1
  133. package/dist/torrent/download/manager.d.ts +2 -85
  134. package/dist/torrent/download/manager.js +1 -382
  135. package/dist/torrent/download/manager.js.map +1 -1
  136. package/dist/torrent/session/Torrent.d.ts +77 -0
  137. package/dist/torrent/session/Torrent.js +126 -0
  138. package/dist/torrent/session/Torrent.js.map +1 -0
  139. package/dist/torrent/session/index.d.ts +2 -77
  140. package/dist/torrent/session/index.js +1 -125
  141. package/dist/torrent/session/index.js.map +1 -1
  142. package/dist/tracker/http.d.ts +1 -1
  143. package/dist/tracker/http.js.map +1 -1
  144. package/dist/tracker/index.d.ts +1 -1
  145. package/dist/tracker/index.js +1 -1
  146. package/dist/tracker/index.js.map +1 -1
  147. package/dist/tracker/types.d.ts +1 -1
  148. package/dist/tracker/udp.d.ts +1 -1
  149. package/dist/tracker/udp.js +24 -25
  150. package/dist/tracker/udp.js.map +1 -1
  151. package/dist/utils/UdpSocket.d.ts +12 -0
  152. package/dist/utils/UdpSocket.js +31 -0
  153. package/dist/utils/UdpSocket.js.map +1 -0
  154. package/examples/download-torrent.ts +32 -0
  155. package/examples/magnet-dht.ts +32 -0
  156. package/package.json +5 -1
package/README.md CHANGED
@@ -2,12 +2,10 @@
2
2
 
3
3
  A minimal Bun-native BitTorrent download-only client written in TypeScript.
4
4
 
5
- `bun-torrent` can parse `.torrent` files, announce to HTTP and UDP trackers, connect to peers, download pieces, validate piece hashes, and write the downloaded files to disk. The public API is intentionally small: create a `Client`, inspect a torrent when you need metadata, then call `download()`.
5
+ `bun-torrent` can parse `.torrent` files and magnet links, announce to HTTP and UDP trackers, discover peers through the BitTorrent DHT, connect to peers, download pieces, validate piece hashes, and write the downloaded files to disk. The public API is intentionally small: create a `Client`, inspect a torrent when you need metadata, then call `download()`.
6
6
 
7
7
  It has no runtime dependencies.
8
8
 
9
- > This package is currently beta software. The API can still change before a stable release.
10
-
11
9
  ## Requirements
12
10
 
13
11
  - Bun `>= 1.3.0`
@@ -15,13 +13,13 @@ It has no runtime dependencies.
15
13
  ## Installation
16
14
 
17
15
  ```bash
18
- bun add bun-torrent@beta
16
+ bun add bun-torrent
19
17
  ```
20
18
 
21
19
  or:
22
20
 
23
21
  ```bash
24
- npm install bun-torrent@beta
22
+ npm install bun-torrent
25
23
  ```
26
24
 
27
25
  ## Basic Usage
@@ -59,6 +57,17 @@ await torrent.done;
59
57
 
60
58
  `download()` returns a `Torrent` instance and starts the download immediately.
61
59
 
60
+ ## Runnable Example Files
61
+
62
+ Runnable example files are available in `examples/`:
63
+
64
+ ```bash
65
+ bun examples/download-torrent.ts ./example.torrent ./downloads
66
+ bun examples/magnet-dht.ts "magnet:?xt=urn:btih:..." ./downloads
67
+ ```
68
+
69
+ The magnet example works with tracker-backed and trackerless magnets. It uses the default in-memory DHT node and closes the client before exiting.
70
+
62
71
  ## Client Setup
63
72
 
64
73
  ```ts
@@ -80,6 +89,7 @@ const client = new Client({
80
89
 
81
90
  Client options:
82
91
 
92
+ - `dht`: optional DHT peer discovery implementation, or `false` to disable DHT. By default, the client creates an in-memory DHT node.
83
93
  - `outputDirectory`: directory where downloaded files are written. Defaults to `process.cwd()`.
84
94
  - `files`: optional default file selection for downloads.
85
95
  - `targetConnections`: preferred number of connected peers. Defaults to `20`.
@@ -111,6 +121,70 @@ console.log(metadata.files);
111
121
 
112
122
  Torrent file input can be a file path, `Uint8Array`, or `ArrayBuffer`.
113
123
 
124
+ Call `client.close()` when the client should stop accepting work and close active torrents and its DHT socket.
125
+
126
+ ## Magnet Links
127
+
128
+ Magnet links are supported with or without trackers. If `tr` parameters are present, the client asks those trackers first. If no tracker returns peers, or the magnet is trackerless, the client falls back to DHT peer discovery. Metadata is fetched from peers with the `ut_metadata` extension before the normal download flow starts.
129
+
130
+ ```ts
131
+ const magnet =
132
+ 'magnet:?xt=urn:btih:0123456789abcdef0123456789abcdef01234567' +
133
+ '&dn=file.bin' +
134
+ '&tr=udp%3A%2F%2Ftracker.example.com%3A6969%2Fannounce';
135
+
136
+ const metadata = await client.inspect({ magnet });
137
+
138
+ console.log(metadata.name);
139
+ console.log(metadata.files);
140
+
141
+ const torrent = await client.download(
142
+ { magnet },
143
+ {
144
+ outputDirectory: './downloads',
145
+ },
146
+ );
147
+
148
+ await torrent.done;
149
+ ```
150
+
151
+ Trackerless magnets use the same API. Keep the same `Client` instance if you inspect first and download later, because the default DHT node keeps discovered peers in memory for the current process.
152
+
153
+ ```ts
154
+ import { Client } from 'bun-torrent';
155
+
156
+ const client = new Client({
157
+ outputDirectory: './downloads',
158
+ });
159
+
160
+ const magnet = 'magnet:?xt=urn:btih:0123456789abcdef0123456789abcdef01234567';
161
+
162
+ try {
163
+ const metadata = await client.inspect({ magnet });
164
+
165
+ console.log(metadata.name);
166
+ console.log(metadata.files);
167
+
168
+ const torrent = await client.download({ meta: metadata });
169
+
170
+ torrent.on('progress', (progress) => {
171
+ console.log(`${(progress.percent * 100).toFixed(2)}%`, progress.speed);
172
+ });
173
+
174
+ await torrent.done;
175
+ } finally {
176
+ client.close();
177
+ }
178
+ ```
179
+
180
+ Supported magnet fields:
181
+
182
+ - `xt=urn:btih:<infoHash>`: required. Hex-encoded 40-character info hashes and base32 32-character info hashes are supported.
183
+ - `dn`: optional display name.
184
+ - `tr`: optional tracker URL. Multiple `tr` parameters are supported, but trackerless magnets can resolve through DHT.
185
+
186
+ The default DHT node is in-memory. It keeps a routing table and a short-lived peer cache for the current process, so a magnet `inspect()` can populate peers that a later `download({ meta })` call can reuse on the same `Client` instance. The DHT state is not persisted to disk.
187
+
114
188
  ## Download Options
115
189
 
116
190
  ```ts
@@ -150,7 +224,7 @@ Download options:
150
224
  - `speedSampleIntervalMs`: override speed sample interval.
151
225
  - `onChangeState`: receives client setup states: `parsing`, `tracking`, `connecting`, `downloading`.
152
226
 
153
- Tracker announce failures are treated as non-fatal. If no tracker responds, the client can still continue with an empty peer list instead of throwing during tracking.
227
+ Tracker announce failures are treated as non-fatal. If trackers are missing or do not return peers, the client falls back to DHT when it is enabled. With DHT disabled, the client can still continue with an empty peer list instead of throwing during tracking when `minConnections` is `0`.
154
228
 
155
229
  ## Selecting Files
156
230
 
package/dist/app.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ export {};
package/dist/app.js ADDED
@@ -0,0 +1,136 @@
1
+ #!/usr/bin/env bun
2
+ import { bytesToHex } from './utils/buffers';
3
+ import { formatBytes } from './utils/formats';
4
+ import { Client } from './client';
5
+ const summarizeTorrent = (metadata) => ({
6
+ announce: metadata.announce,
7
+ announceList: metadata.announceList,
8
+ infoHash: bytesToHex(metadata.infoHash),
9
+ name: metadata.name,
10
+ pieceLength: metadata.pieceLength,
11
+ piecesTotal: metadata.pieces.length,
12
+ length: metadata.length,
13
+ files: metadata.files.map((file) => ({
14
+ path: file.path.join('/'),
15
+ length: file.length,
16
+ offset: file.offset,
17
+ })),
18
+ filesTotal: metadata.files.length,
19
+ });
20
+ const usage = () => {
21
+ console.error('Usage:');
22
+ console.error(' bunx bun-torrent inspect <file.torrent>');
23
+ console.error(' bunx bun-torrent inspect <magnet-uri>');
24
+ console.error(' bunx bun-torrent inspect < file.torrent');
25
+ console.error(' bunx bun-torrent download <file.torrent|magnet-uri> [output-directory]');
26
+ };
27
+ const inspect = async (input) => {
28
+ const client = new Client();
29
+ try {
30
+ const metadata = input ? await inspectArgument(client, input) : await inspectStdin(client);
31
+ console.log(JSON.stringify(summarizeTorrent(metadata), null, 2));
32
+ }
33
+ finally {
34
+ client.close();
35
+ }
36
+ };
37
+ const resolveInput = (input) => {
38
+ if (input.startsWith('magnet:')) {
39
+ return { magnet: input };
40
+ }
41
+ return { torrentFile: input };
42
+ };
43
+ const inspectArgument = async (client, input) => {
44
+ return await client.inspect(resolveInput(input));
45
+ };
46
+ const inspectStdin = async (client) => {
47
+ const input = new Uint8Array(await Bun.stdin.arrayBuffer());
48
+ if (input.byteLength === 0) {
49
+ throw new Error('Expected torrent file bytes on stdin');
50
+ }
51
+ return await client.inspect({ torrentFile: input });
52
+ };
53
+ const download = async (input, outputDirectory = './downloads') => {
54
+ if (!input) {
55
+ throw new Error('Expected file.torrent or magnet URI');
56
+ }
57
+ const client = new Client({ outputDirectory });
58
+ let state = 'starting';
59
+ let progress = null;
60
+ let stats = null;
61
+ const render = () => renderProgressLine(state, progress, stats);
62
+ try {
63
+ render();
64
+ const torrent = await client.download(resolveInput(input), {
65
+ progressEvents: 'block',
66
+ onChangeState: (nextState) => {
67
+ state = nextState;
68
+ render();
69
+ },
70
+ });
71
+ progress = torrent.progress;
72
+ stats = torrent.stats;
73
+ render();
74
+ torrent.on('progress', (nextProgress) => {
75
+ progress = nextProgress;
76
+ render();
77
+ });
78
+ torrent.on('peer', (nextStats) => {
79
+ stats = nextStats;
80
+ render();
81
+ });
82
+ await torrent.done;
83
+ state = 'completed';
84
+ progress = torrent.progress;
85
+ stats = torrent.stats;
86
+ render();
87
+ process.stdout.write('\nDownload complete\n');
88
+ }
89
+ finally {
90
+ client.close();
91
+ }
92
+ };
93
+ const renderProgressLine = (state, progress, stats) => {
94
+ const bar = progress ? progressBar(progress.percent) : progressBar(0);
95
+ const percent = progress ? `${(progress.percent * 100).toFixed(2).padStart(6)}%` : ' 0.00%';
96
+ const downloaded = progress ? formatBytes(progress.downloadedBytes) : '0.0 B';
97
+ const total = progress ? formatBytes(progress.totalBytes) : '?';
98
+ const speed = progress?.speed ?? '0.0 Bps';
99
+ const pieces = progress
100
+ ? `pieces=${progress.completedPieces}/${progress.totalPieces}`
101
+ : 'pieces=?/?';
102
+ const peers = stats ? `peers=${stats.connections}/${stats.peers}` : 'peers=0/0';
103
+ const line = `${state.padEnd(11)} ${bar} ${percent} ${downloaded}/${total} ${speed} ${pieces} ${peers}`;
104
+ process.stdout.write(`\r${line}\x1b[K`);
105
+ };
106
+ const progressBar = (percent) => {
107
+ const width = 28;
108
+ const normalized = Math.min(1, Math.max(0, percent));
109
+ const filled = Math.round(normalized * width);
110
+ return `[${'#'.repeat(filled)}${'-'.repeat(width - filled)}]`;
111
+ };
112
+ if (import.meta.main) {
113
+ const command = Bun.argv[2];
114
+ const input = Bun.argv[3];
115
+ const outputDirectory = Bun.argv[4];
116
+ try {
117
+ switch (command) {
118
+ case 'inspect':
119
+ await inspect(input);
120
+ break;
121
+ case 'download':
122
+ await download(input, outputDirectory);
123
+ break;
124
+ default:
125
+ usage();
126
+ process.exitCode = 1;
127
+ }
128
+ }
129
+ catch (error) {
130
+ if (command === 'download')
131
+ process.stdout.write('\n');
132
+ console.error(error instanceof Error ? error.message : String(error));
133
+ process.exitCode = 1;
134
+ }
135
+ }
136
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
package/dist/client.d.ts CHANGED
@@ -2,13 +2,19 @@ import { type DownloadProgressEventMode } from './torrent/download';
2
2
  import { Torrent } from './torrent/session/index';
3
3
  import type { TorrentMetadata } from './torrent/types';
4
4
  import type { TorrentFileSelection } from './torrent/file-selection';
5
+ import type { PeerInfo } from './tracker/types';
5
6
  export declare enum DownloadState {
6
7
  PARSING = "parsing",
7
8
  TRACKING = "tracking",
8
9
  CONNECTING = "connecting",
9
10
  DOWNLOADING = "downloading"
10
11
  }
12
+ export type ClientDht = {
13
+ lookupPeers(infoHash: Uint8Array): Promise<PeerInfo[]>;
14
+ close?(): void;
15
+ };
11
16
  export type ClientConfig = {
17
+ dht?: ClientDht | false;
12
18
  files?: TorrentFileSelection;
13
19
  maxInFlightRequestsPerPeer?: number;
14
20
  maxConnecting?: number;
@@ -22,17 +28,35 @@ export type ClientConfig = {
22
28
  targetConnections?: number;
23
29
  trackerTimeoutMs?: number;
24
30
  };
31
+ type InspectInput = {
32
+ torrentFile: string | Uint8Array | ArrayBuffer;
33
+ magnet?: undefined | null;
34
+ meta?: null;
35
+ } | {
36
+ magnet: string;
37
+ torrentFile?: undefined | null;
38
+ meta?: null;
39
+ };
40
+ type DownloadInput = {
41
+ meta: TorrentMetadata;
42
+ } | InspectInput;
25
43
  export declare class Client {
26
44
  private readonly config;
27
45
  private readonly peerId;
46
+ private readonly dhtNodeId;
47
+ private readonly dht?;
48
+ private readonly torrents;
49
+ private closed;
28
50
  constructor(config?: ClientConfig);
29
- download(input: {
30
- torrentFile: string | Uint8Array | ArrayBuffer;
31
- }, options?: DownloadOptions): Promise<Torrent>;
32
- inspect(input: {
33
- torrentFile: string | Uint8Array | ArrayBuffer;
51
+ download(input: DownloadInput, options?: DownloadOptions): Promise<Torrent>;
52
+ inspect(input: InspectInput, options?: {
53
+ timeout?: number;
34
54
  }): Promise<TorrentMetadata>;
55
+ close(): void;
56
+ private discoverPeers;
35
57
  private trackPeers;
58
+ private trackTorrent;
59
+ private assertOpen;
36
60
  }
37
61
  export type DownloadOptions = {
38
62
  announcePort?: number;
@@ -51,5 +75,5 @@ export type DownloadOptions = {
51
75
  trackerTimeoutMs?: number;
52
76
  };
53
77
  export type TorrentFileInput = string | Uint8Array | ArrayBuffer;
54
- export declare const readTorrentFile: (input: TorrentFileInput) => Promise<Uint8Array>;
78
+ export declare const readTorrentFile: (input: unknown) => Promise<Uint8Array>;
55
79
  export { Client as TorrentClient };
@@ -1,5 +1,6 @@
1
1
  import { BunTorrentError } from './utils/errors';
2
2
  export declare enum ClientErrorCode {
3
+ CLOSED = "CLIENT_CLOSED",
3
4
  INVALID_FILE_SELECTION = "CLIENT_INVALID_FILE_SELECTION",
4
5
  UNSUPPORTED_TORRENT_FILE_INPUT = "CLIENT_UNSUPPORTED_TORRENT_FILE_INPUT"
5
6
  }
@@ -1,6 +1,7 @@
1
1
  import { BunTorrentError } from './utils/errors';
2
2
  export var ClientErrorCode;
3
3
  (function (ClientErrorCode) {
4
+ ClientErrorCode["CLOSED"] = "CLIENT_CLOSED";
4
5
  ClientErrorCode["INVALID_FILE_SELECTION"] = "CLIENT_INVALID_FILE_SELECTION";
5
6
  ClientErrorCode["UNSUPPORTED_TORRENT_FILE_INPUT"] = "CLIENT_UNSUPPORTED_TORRENT_FILE_INPUT";
6
7
  })(ClientErrorCode || (ClientErrorCode = {}));
@@ -1 +1 @@
1
- {"version":3,"file":"client.error.js","sourceRoot":"","sources":["../src/client.error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,MAAM,CAAN,IAAY,eAGX;AAHD,WAAY,eAAe;IACvB,2EAAwD,CAAA;IACxD,2FAAwE,CAAA;AAC5E,CAAC,EAHW,eAAe,KAAf,eAAe,QAG1B;AAED,MAAM,OAAO,WAAY,SAAQ,eAAe;IAC5C,YAAY,IAAqB,EAAE,OAAe;QAC9C,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACzB,CAAC;CACJ"}
1
+ {"version":3,"file":"client.error.js","sourceRoot":"","sources":["../src/client.error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,MAAM,CAAN,IAAY,eAIX;AAJD,WAAY,eAAe;IACvB,2CAAwB,CAAA;IACxB,2EAAwD,CAAA;IACxD,2FAAwE,CAAA;AAC5E,CAAC,EAJW,eAAe,KAAf,eAAe,QAI1B;AAED,MAAM,OAAO,WAAY,SAAQ,eAAe;IAC5C,YAAY,IAAqB,EAAE,OAAe;QAC9C,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACzB,CAAC;CACJ"}
package/dist/client.js CHANGED
@@ -7,6 +7,10 @@ import { ClientError, ClientErrorCode } from './client.error';
7
7
  import { trackPeers, TrackerError, TrackerErrorCode } from './tracker';
8
8
  import { getUnknownSelectedFiles, normalizeTorrentFileSelection } from './torrent/file-selection';
9
9
  import { defaults } from './configs/defaults';
10
+ import { BunTorrentError } from './utils/errors';
11
+ import { parseMagnet } from './magnet';
12
+ import { DhtClient } from './dht';
13
+ import { createDhtNodeId } from './dht/utils/distance';
10
14
  export var DownloadState;
11
15
  (function (DownloadState) {
12
16
  DownloadState["PARSING"] = "parsing";
@@ -17,17 +21,27 @@ export var DownloadState;
17
21
  export class Client {
18
22
  config;
19
23
  peerId;
24
+ dhtNodeId;
25
+ dht;
26
+ torrents = new Set();
27
+ closed = false;
20
28
  constructor(config = {}) {
21
29
  this.config = config;
22
30
  this.peerId = createPeerId();
31
+ this.dhtNodeId = createDhtNodeId();
32
+ this.dht =
33
+ config.dht === false
34
+ ? undefined
35
+ : (config.dht ?? new DhtClient({ nodeId: this.dhtNodeId }));
23
36
  }
24
37
  async download(input, options = {}) {
38
+ this.assertOpen();
25
39
  options.onChangeState?.(DownloadState.PARSING);
26
- const meta = await this.inspect(input);
40
+ const meta = input.meta ?? (await this.inspect(input, { timeout: options.trackerTimeoutMs }));
27
41
  const downloadConfig = resolveDownloadConfig(this.config, options);
28
42
  assertValidFileSelection(meta, downloadConfig.files);
29
43
  options.onChangeState?.(DownloadState.TRACKING);
30
- const peers = await this.trackPeers(meta, options, downloadConfig);
44
+ const peers = await this.discoverPeers(meta, options, downloadConfig);
31
45
  options.onChangeState?.(DownloadState.CONNECTING);
32
46
  const pool = await openPeerPool(peers, {
33
47
  infoHash: meta.infoHash,
@@ -39,7 +53,7 @@ export class Client {
39
53
  timeoutMs: downloadConfig.peerConnectTimeoutMs,
40
54
  });
41
55
  options.onChangeState?.(DownloadState.DOWNLOADING);
42
- return new Torrent(meta, pool, new DownloadManager({
56
+ const torrent = new Torrent(meta, pool, new DownloadManager({
43
57
  metadata: meta,
44
58
  files: downloadConfig.files,
45
59
  outputDirectory: downloadConfig.outputDirectory,
@@ -49,10 +63,45 @@ export class Client {
49
63
  requestTimeoutMs: downloadConfig.requestTimeoutMs,
50
64
  speedSampleIntervalMs: downloadConfig.speedSampleIntervalMs,
51
65
  }), normalizeTorrentFileSelection(downloadConfig.files), downloadConfig.seed);
66
+ this.trackTorrent(torrent);
67
+ return torrent;
52
68
  }
53
- async inspect(input) {
54
- const bytes = await readTorrentFile(input.torrentFile);
55
- return parseTorrent(bytes);
69
+ async inspect(input, options) {
70
+ this.assertOpen();
71
+ if ('torrentFile' in input && input.torrentFile !== undefined) {
72
+ const bytes = await readTorrentFile(input.torrentFile);
73
+ return parseTorrent(bytes);
74
+ }
75
+ if ('magnet' in input && input.magnet !== undefined && input.magnet !== null) {
76
+ return parseMagnet(input.magnet, this.peerId, { ...options, dht: this.dht });
77
+ }
78
+ throw new BunTorrentError('No input provided', 'NO_INPUT');
79
+ }
80
+ close() {
81
+ if (this.closed)
82
+ return;
83
+ this.closed = true;
84
+ for (const torrent of this.torrents)
85
+ torrent.close();
86
+ this.torrents.clear();
87
+ this.dht?.close?.();
88
+ }
89
+ async discoverPeers(meta, options, config) {
90
+ const peers = new Map();
91
+ for (const peer of await this.trackPeers(meta, options, config)) {
92
+ peers.set(peerKey(peer), peer);
93
+ }
94
+ if (peers.size > 0 || !this.dht)
95
+ return [...peers.values()];
96
+ try {
97
+ for (const peer of await this.dht.lookupPeers(meta.infoHash)) {
98
+ peers.set(peerKey(peer), peer);
99
+ }
100
+ }
101
+ catch {
102
+ return [...peers.values()];
103
+ }
104
+ return [...peers.values()];
56
105
  }
57
106
  async trackPeers(meta, options, config) {
58
107
  try {
@@ -69,11 +118,22 @@ export class Client {
69
118
  throw error;
70
119
  }
71
120
  }
121
+ trackTorrent(torrent) {
122
+ this.torrents.add(torrent);
123
+ torrent.on('close', () => this.torrents.delete(torrent));
124
+ void torrent.done.then(() => this.torrents.delete(torrent), () => this.torrents.delete(torrent));
125
+ }
126
+ assertOpen() {
127
+ if (!this.closed)
128
+ return;
129
+ throw new ClientError(ClientErrorCode.CLOSED, 'Torrent client is closed');
130
+ }
72
131
  }
73
132
  const isNonFatalTrackerError = (error) => error instanceof TrackerError &&
74
133
  (error.code === TrackerErrorCode.ANNOUNCE_FAILED ||
75
134
  error.code === TrackerErrorCode.NO_PEERS ||
76
135
  error.code === TrackerErrorCode.NO_SUPPORTED_TRACKERS);
136
+ const peerKey = (peer) => `${peer.ip}:${peer.port}`;
77
137
  const resolveDownloadConfig = (config, options) => ({
78
138
  files: options.files ?? config.files ?? null,
79
139
  maxInFlightRequestsPerPeer: options.maxInFlightRequestsPerPeer ??
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -22,4 +22,24 @@ export declare const defaults: {
22
22
  readonly announcePort: 6881;
23
23
  readonly timeoutMs: 5000;
24
24
  };
25
+ readonly dht: {
26
+ readonly bootstrapNodes: readonly [{
27
+ readonly host: "router.bittorrent.com";
28
+ readonly port: 6881;
29
+ }, {
30
+ readonly host: "router.utorrent.com";
31
+ readonly port: 6881;
32
+ }, {
33
+ readonly host: "dht.transmissionbt.com";
34
+ readonly port: 6881;
35
+ }];
36
+ readonly lookupConcurrency: 8;
37
+ readonly maxLookupRounds: 8;
38
+ readonly peerCacheTtlMs: number;
39
+ readonly queryTimeoutMs: 5000;
40
+ };
41
+ readonly magnet: {
42
+ readonly trackerTimeoutMs: 3000;
43
+ readonly peerTimeoutMs: 5000;
44
+ };
25
45
  };
@@ -22,5 +22,20 @@ export const defaults = {
22
22
  announcePort: 6881,
23
23
  timeoutMs: 5_000,
24
24
  },
25
+ dht: {
26
+ bootstrapNodes: [
27
+ { host: 'router.bittorrent.com', port: 6881 },
28
+ { host: 'router.utorrent.com', port: 6881 },
29
+ { host: 'dht.transmissionbt.com', port: 6881 },
30
+ ],
31
+ lookupConcurrency: 8,
32
+ maxLookupRounds: 8,
33
+ peerCacheTtlMs: 5 * 60_000,
34
+ queryTimeoutMs: 5_000,
35
+ },
36
+ magnet: {
37
+ trackerTimeoutMs: 3_000,
38
+ peerTimeoutMs: 5_000,
39
+ },
25
40
  };
26
41
  //# sourceMappingURL=defaults.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/configs/defaults.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG;IACpB,MAAM,EAAE;QACJ,SAAS,EAAE,EAAE,GAAG,IAAI;KACvB;IACD,KAAK,EAAE;QACH,iBAAiB,EAAE,EAAE;QACrB,cAAc,EAAE,CAAC;QACjB,aAAa,EAAE,EAAE;QACjB,gBAAgB,EAAE,KAAK;KAC1B;IACD,QAAQ,EAAE;QACN,0BAA0B,EAAE,GAAG;QAC/B,2BAA2B,EAAE,CAAC;QAC9B,gBAAgB,EAAE,MAAM;QACxB,IAAI,EAAE,KAAK;KACd;IACD,QAAQ,EAAE;QACN,MAAM,EAAE,OAAO;QACf,qBAAqB,EAAE,GAAG;KAC7B;IACD,QAAQ,EAAE;QACN,YAAY,EAAE,IAAI;QAClB,SAAS,EAAE,KAAK;KACnB;CACK,CAAC"}
1
+ {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/configs/defaults.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG;IACpB,MAAM,EAAE;QACJ,SAAS,EAAE,EAAE,GAAG,IAAI;KACvB;IACD,KAAK,EAAE;QACH,iBAAiB,EAAE,EAAE;QACrB,cAAc,EAAE,CAAC;QACjB,aAAa,EAAE,EAAE;QACjB,gBAAgB,EAAE,KAAK;KAC1B;IACD,QAAQ,EAAE;QACN,0BAA0B,EAAE,GAAG;QAC/B,2BAA2B,EAAE,CAAC;QAC9B,gBAAgB,EAAE,MAAM;QACxB,IAAI,EAAE,KAAK;KACd;IACD,QAAQ,EAAE;QACN,MAAM,EAAE,OAAO;QACf,qBAAqB,EAAE,GAAG;KAC7B;IACD,QAAQ,EAAE;QACN,YAAY,EAAE,IAAI;QAClB,SAAS,EAAE,KAAK;KACnB;IACD,GAAG,EAAE;QACD,cAAc,EAAE;YACZ,EAAE,IAAI,EAAE,uBAAuB,EAAE,IAAI,EAAE,IAAI,EAAE;YAC7C,EAAE,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,IAAI,EAAE;YAC3C,EAAE,IAAI,EAAE,wBAAwB,EAAE,IAAI,EAAE,IAAI,EAAE;SACjD;QACD,iBAAiB,EAAE,CAAC;QACpB,eAAe,EAAE,CAAC;QAClB,cAAc,EAAE,CAAC,GAAG,MAAM;QAC1B,cAAc,EAAE,KAAK;KACxB;IACD,MAAM,EAAE;QACJ,gBAAgB,EAAE,KAAK;QACvB,aAAa,EAAE,KAAK;KACvB;CACK,CAAC"}
@@ -0,0 +1,52 @@
1
+ import { KrpcTransactionIdGenerator, type KrpcResponse } from './krpc';
2
+ import { DhtRoutingTable } from './RoutingTable';
3
+ import { type CreateUdpSocket } from '../utils/UdpSocket';
4
+ import type { PeerInfo } from '../tracker/types';
5
+ export type DhtEndpoint = {
6
+ host: string;
7
+ port: number;
8
+ };
9
+ export type DhtClientOptions = {
10
+ nodeId: Uint8Array;
11
+ bootstrapNodes?: DhtEndpoint[];
12
+ lookupConcurrency?: number;
13
+ maxLookupRounds?: number;
14
+ peerCacheTtlMs?: number;
15
+ timeoutMs?: number;
16
+ routingTable?: DhtRoutingTable;
17
+ transactionIds?: KrpcTransactionIdGenerator;
18
+ createSocket?: CreateUdpSocket;
19
+ };
20
+ export declare class DhtClient {
21
+ readonly routingTable: DhtRoutingTable;
22
+ private readonly nodeId;
23
+ private readonly bootstrapNodes;
24
+ private readonly lookupConcurrency;
25
+ private readonly maxLookupRounds;
26
+ private readonly peerCacheTtlMs;
27
+ private readonly timeoutMs;
28
+ private readonly transactionIds;
29
+ private readonly createSocket;
30
+ private readonly pending;
31
+ private readonly peerCache;
32
+ private socket;
33
+ private starting;
34
+ private closed;
35
+ constructor(options: DhtClientOptions);
36
+ start(): Promise<void>;
37
+ close(): void;
38
+ ping(endpoint: DhtEndpoint): Promise<KrpcResponse>;
39
+ findNode(endpoint: DhtEndpoint, target: Uint8Array): Promise<KrpcResponse>;
40
+ getPeers(endpoint: DhtEndpoint, infoHash: Uint8Array): Promise<KrpcResponse>;
41
+ rememberPeers(infoHash: Uint8Array, peers: PeerInfo[]): void;
42
+ bootstrap(nodes?: DhtEndpoint[], target?: Uint8Array): Promise<void>;
43
+ lookupPeers(infoHash: Uint8Array): Promise<PeerInfo[]>;
44
+ private sendQuery;
45
+ private openSocket;
46
+ private createQueryMessage;
47
+ private handleData;
48
+ private addCompactNodes;
49
+ private getCachedPeers;
50
+ private resolveEndpoint;
51
+ private rejectAll;
52
+ }