@xtr-dev/rondevu-webtorrent 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 XTR Development
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,300 @@
1
+ # @xtr-dev/rondevu-webtorrent
2
+
3
+ > **⚠️ EARLY DEVELOPMENT WARNING**: This package is in early development (version < 1.0.0). The API is subject to change, and there may be bugs or incomplete features. Use at your own risk in production environments.
4
+
5
+ WebTorrent peer discovery plugin using [Rondevu](https://github.com/xtr-dev/rondevu) WebRTC signaling for peer connectivity.
6
+
7
+ ## Overview
8
+
9
+ `@xtr-dev/rondevu-webtorrent` acts as a plugin for [WebTorrent](https://webtorrent.io/), providing automatic peer discovery through the Rondevu WebRTC signaling service. It complements traditional BitTorrent peer discovery methods (DHT, trackers) by using WebRTC data channels for direct peer-to-peer connections.
10
+
11
+ ## Features
12
+
13
+ - **Automatic Peer Discovery**: Automatically discovers and connects to peers for each torrent
14
+ - **WebRTC Signaling**: Uses Rondevu for WebRTC offer/answer exchange and ICE candidate signaling
15
+ - **Topic-Based Discovery**: Each torrent's `infoHash` is used as a topic for peer discovery
16
+ - **Bloom Filter Optimization**: Uses bloom filters to avoid rediscovering peers, reducing bandwidth and API calls
17
+ - **Configurable**: Control max peers per torrent, refresh intervals, and WebRTC configuration
18
+ - **Credential Persistence**: Save and reuse Rondevu credentials across sessions
19
+ - **Debug Mode**: Enable detailed logging to monitor peer discovery and connections
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install @xtr-dev/rondevu-webtorrent
25
+ ```
26
+
27
+ ## Demo
28
+
29
+ A complete working demo is available in the [`demo/`](./demo) folder. The demo includes:
30
+ - **Seeder script** - Creates and seeds a torrent
31
+ - **Leecher script** - Downloads the torrent
32
+ - Step-by-step instructions
33
+
34
+ See the [demo README](./demo/README.md) for details.
35
+
36
+ ## Quick Start
37
+
38
+ ### Browser
39
+
40
+ ```typescript
41
+ import WebTorrent from 'webtorrent';
42
+ import { RondevuConnectionManager } from '@xtr-dev/rondevu-webtorrent';
43
+
44
+ // Create WebTorrent client
45
+ const client = new WebTorrent();
46
+
47
+ // Initialize Rondevu connection manager
48
+ const connectionManager = new RondevuConnectionManager(client, {
49
+ rondevuServer: 'https://api.ronde.vu', // Optional: defaults to this
50
+ maxPeersPerTorrent: 50,
51
+ debug: true,
52
+ refreshInterval: 30000, // 30 seconds
53
+ });
54
+
55
+ // Add a torrent
56
+ const magnetURI = 'magnet:?xt=urn:btih:...';
57
+ client.add(magnetURI, (torrent) => {
58
+ console.log(`Torrent added: ${torrent.name}`);
59
+
60
+ torrent.on('download', () => {
61
+ console.log(`Progress: ${(torrent.progress * 100).toFixed(2)}%`);
62
+ console.log(`Peers: ${torrent.numPeers}`);
63
+ });
64
+
65
+ torrent.on('done', () => {
66
+ console.log('Download complete!');
67
+ });
68
+ });
69
+ ```
70
+
71
+ ### Node.js (with WebRTC polyfill)
72
+
73
+ ```typescript
74
+ import WebTorrent from 'webtorrent';
75
+ import { RondevuConnectionManager } from '@xtr-dev/rondevu-webtorrent';
76
+ import wrtc from '@roamhq/wrtc';
77
+
78
+ const client = new WebTorrent();
79
+
80
+ // Initialize with wrtc polyfill for Node.js
81
+ const connectionManager = new RondevuConnectionManager(client, {
82
+ rondevuServer: 'https://api.ronde.vu',
83
+ maxPeersPerTorrent: 50,
84
+ debug: true,
85
+ wrtc: wrtc, // Required for WebRTC in Node.js
86
+ });
87
+
88
+ // Rest is the same as browser...
89
+ ```
90
+
91
+ ## API
92
+
93
+ ### `RondevuConnectionManager`
94
+
95
+ The main class that manages peer discovery for WebTorrent.
96
+
97
+ #### Constructor
98
+
99
+ ```typescript
100
+ new RondevuConnectionManager(client: WebTorrent.Instance, options?: RondevuConnectionManagerOptions)
101
+ ```
102
+
103
+ #### Options
104
+
105
+ ```typescript
106
+ interface RondevuConnectionManagerOptions {
107
+ /**
108
+ * Rondevu server base URL
109
+ * @default 'https://api.ronde.vu'
110
+ */
111
+ rondevuServer?: string;
112
+
113
+ /**
114
+ * Maximum number of peer connections per torrent
115
+ * @default 50
116
+ */
117
+ maxPeersPerTorrent?: number;
118
+
119
+ /**
120
+ * Enable debug logging
121
+ * @default false
122
+ */
123
+ debug?: boolean;
124
+
125
+ /**
126
+ * Interval in milliseconds to refresh peer discovery
127
+ * @default 30000 (30 seconds)
128
+ */
129
+ refreshInterval?: number;
130
+
131
+ /**
132
+ * Custom RTCConfiguration for WebRTC peer connections
133
+ */
134
+ rtcConfig?: RTCConfiguration;
135
+
136
+ /**
137
+ * Existing Rondevu credentials to reuse
138
+ */
139
+ credentials?: { peerId: string; secret: string };
140
+
141
+ /**
142
+ * WebRTC polyfill for Node.js (e.g., @roamhq/wrtc)
143
+ * Required for WebRTC functionality in Node.js environments
144
+ */
145
+ wrtc?: {
146
+ RTCPeerConnection: typeof RTCPeerConnection;
147
+ RTCSessionDescription: typeof RTCSessionDescription;
148
+ RTCIceCandidate: typeof RTCIceCandidate;
149
+ };
150
+ }
151
+ ```
152
+
153
+ #### Methods
154
+
155
+ ##### `discoverPeers(infoHash: string): Promise<void>`
156
+
157
+ Manually trigger peer discovery for a specific torrent.
158
+
159
+ ```typescript
160
+ await connectionManager.discoverPeers(torrent.infoHash);
161
+ ```
162
+
163
+ ##### `getStats()`
164
+
165
+ Get statistics about the connection manager.
166
+
167
+ ```typescript
168
+ const stats = connectionManager.getStats();
169
+ console.log(stats);
170
+ // {
171
+ // activeTorrents: 1,
172
+ // peerId: 'abc123...',
173
+ // rondevuServer: 'https://api.ronde.vu',
174
+ // torrents: [
175
+ // { infoHash: '...', peerCount: 5 }
176
+ // ]
177
+ // }
178
+ ```
179
+
180
+ ##### `getCredentials(): Credentials | undefined`
181
+
182
+ Get the current Rondevu credentials for persistence across sessions.
183
+
184
+ ```typescript
185
+ const credentials = connectionManager.getCredentials();
186
+ // Save credentials to storage
187
+ localStorage.setItem('rondevu-credentials', JSON.stringify(credentials));
188
+
189
+ // Later, reuse credentials
190
+ const savedCredentials = JSON.parse(localStorage.getItem('rondevu-credentials'));
191
+ const newManager = new RondevuConnectionManager(client, {
192
+ credentials: savedCredentials
193
+ });
194
+ ```
195
+
196
+ ##### `destroy(): void`
197
+
198
+ Clean up all resources and disconnect from Rondevu.
199
+
200
+ ```typescript
201
+ connectionManager.destroy();
202
+ ```
203
+
204
+ ## How It Works
205
+
206
+ 1. **Initialization**: When you create a `RondevuConnectionManager`, it registers with the Rondevu signaling server
207
+ 2. **Torrent Added**: When a torrent is added to WebTorrent:
208
+ - The manager creates a bloom filter to track seen peers
209
+ - The manager creates a WebRTC offer and publishes it to Rondevu with the torrent's `infoHash` as the topic
210
+ - The manager queries Rondevu for other peers offering the same `infoHash`, passing the bloom filter to exclude already-seen peers
211
+ - WebRTC connections are established with discovered peers
212
+ - Each discovered peer ID is added to the bloom filter
213
+ 3. **Peer Connection**: Once WebRTC connections are established, the peer connections are added to the WebTorrent instance
214
+ 4. **Periodic Refresh**: The manager periodically refreshes peer discovery to find new peers, using the bloom filter to avoid reconnecting to already-seen peers
215
+ 5. **Cleanup**: When a torrent is removed, all associated peer connections, offers, and bloom filters are cleaned up
216
+
217
+ ## Advanced Usage
218
+
219
+ ### Custom RTCConfiguration
220
+
221
+ Provide custom STUN/TURN servers for WebRTC connections:
222
+
223
+ ```typescript
224
+ const connectionManager = new RondevuConnectionManager(client, {
225
+ rtcConfig: {
226
+ iceServers: [
227
+ { urls: 'stun:stun.l.google.com:19302' },
228
+ {
229
+ urls: 'turn:turn.example.com:3478',
230
+ username: 'user',
231
+ credential: 'pass'
232
+ }
233
+ ]
234
+ }
235
+ });
236
+ ```
237
+
238
+ ### Persistent Credentials
239
+
240
+ Save and reuse credentials to maintain the same peer ID:
241
+
242
+ ```typescript
243
+ // First time
244
+ const manager = new RondevuConnectionManager(client, { debug: true });
245
+
246
+ // Save credentials after initialization
247
+ setTimeout(() => {
248
+ const credentials = manager.getCredentials();
249
+ fs.writeFileSync('credentials.json', JSON.stringify(credentials));
250
+ }, 1000);
251
+
252
+ // Next time
253
+ const savedCredentials = JSON.parse(fs.readFileSync('credentials.json', 'utf8'));
254
+ const manager = new RondevuConnectionManager(client, {
255
+ credentials: savedCredentials
256
+ });
257
+ ```
258
+
259
+ ### Graceful Shutdown
260
+
261
+ Always clean up when your application exits:
262
+
263
+ ```typescript
264
+ process.on('SIGINT', () => {
265
+ console.log('Shutting down...');
266
+ connectionManager.destroy();
267
+ client.destroy(() => {
268
+ console.log('WebTorrent client destroyed');
269
+ process.exit(0);
270
+ });
271
+ });
272
+ ```
273
+
274
+ ## Limitations
275
+
276
+ - **Node.js WebRTC Support**: Node.js doesn't have native WebRTC support. To enable WebRTC functionality in Node.js, you need to install and pass a WebRTC polyfill like `@roamhq/wrtc` via the `wrtc` option (see the Node.js Quick Start example above). The polyfill requires native compilation during installation. Without the polyfill, the package will still work in Node.js using WebTorrent's traditional peer discovery methods (DHT, trackers), but Rondevu WebRTC peer discovery will not be available.
277
+ - **Browser Support**: WebRTC works natively in modern browsers, making this the ideal environment for full Rondevu WebRTC functionality without requiring any polyfills
278
+ - **Network Requirements**: The Rondevu signaling server must be accessible to all peers
279
+ - **Restrictive Networks**: WebRTC connections may not work in restrictive network environments without TURN servers
280
+
281
+ ## Roadmap
282
+
283
+ - [x] Bloom filter support for efficient peer discovery
284
+ - [ ] Better error handling and recovery
285
+ - [ ] Metrics and monitoring
286
+ - [ ] Connection pooling and optimization
287
+ - [ ] Automated testing suite
288
+
289
+ ## License
290
+
291
+ MIT
292
+
293
+ ## Contributing
294
+
295
+ Contributions are welcome! Please open an issue or pull request on GitHub.
296
+
297
+ ## Related Projects
298
+
299
+ - [WebTorrent](https://webtorrent.io/) - Streaming torrent client for Node.js and the browser
300
+ - [Rondevu](https://github.com/xtr-dev/rondevu) - WebRTC signaling and peer discovery service
@@ -0,0 +1,104 @@
1
+ import WebTorrent from 'webtorrent';
2
+ import { Credentials } from '@xtr-dev/rondevu-client';
3
+ /**
4
+ * WebRTC polyfill interface for Node.js environments
5
+ */
6
+ export interface WebRTCPolyfill {
7
+ RTCPeerConnection: typeof RTCPeerConnection;
8
+ RTCSessionDescription: typeof RTCSessionDescription;
9
+ RTCIceCandidate: typeof RTCIceCandidate;
10
+ }
11
+ /**
12
+ * Options for configuring the RondevuConnectionManager
13
+ */
14
+ export interface RondevuConnectionManagerOptions {
15
+ /**
16
+ * Rondevu server base URL (default: 'https://api.ronde.vu')
17
+ */
18
+ rondevuServer?: string;
19
+ /**
20
+ * Maximum number of peer connections to establish per torrent (default: 50)
21
+ */
22
+ maxPeersPerTorrent?: number;
23
+ /**
24
+ * Enable debug logging
25
+ */
26
+ debug?: boolean;
27
+ /**
28
+ * Interval in milliseconds to refresh peer discovery (default: 30000ms)
29
+ */
30
+ refreshInterval?: number;
31
+ /**
32
+ * Custom RTCConfiguration for WebRTC peer connections
33
+ */
34
+ rtcConfig?: RTCConfiguration;
35
+ /**
36
+ * Existing rondevu credentials to reuse
37
+ */
38
+ credentials?: Credentials;
39
+ /**
40
+ * WebRTC polyfill for Node.js (e.g., @roamhq/wrtc)
41
+ * Required for WebRTC functionality in Node.js environments
42
+ */
43
+ wrtc?: WebRTCPolyfill;
44
+ }
45
+ /**
46
+ * Connection manager that uses Rondevu for WebTorrent peer discovery via WebRTC.
47
+ * This class acts as a plugin for WebTorrent, automatically discovering
48
+ * and connecting to peers through rondevu WebRTC signaling.
49
+ */
50
+ export declare class RondevuConnectionManager {
51
+ private client;
52
+ private rondevu;
53
+ private torrentPeers;
54
+ private torrentOffers;
55
+ private torrentCleanupHandlers;
56
+ private refreshTimers;
57
+ private torrentBloomFilters;
58
+ private options;
59
+ constructor(client: WebTorrent.Instance, options?: RondevuConnectionManagerOptions);
60
+ /**
61
+ * Initialize the connection manager by setting up event listeners and registering with rondevu
62
+ */
63
+ private initialize;
64
+ /**
65
+ * Handle a torrent being added to the WebTorrent client
66
+ */
67
+ private handleTorrentAdded;
68
+ /**
69
+ * Discover peers for a torrent using rondevu
70
+ */
71
+ private discoverPeersForTorrent;
72
+ /**
73
+ * Set up event handlers for a rondevu peer
74
+ */
75
+ private setupPeerHandlers;
76
+ /**
77
+ * Log a message if debug mode is enabled
78
+ */
79
+ private log;
80
+ /**
81
+ * Manually trigger peer discovery for a specific torrent
82
+ */
83
+ discoverPeers(infoHash: string): Promise<void>;
84
+ /**
85
+ * Get statistics about the connection manager
86
+ */
87
+ getStats(): {
88
+ activeTorrents: number;
89
+ peerId: string | undefined;
90
+ rondevuServer: string;
91
+ torrents: {
92
+ infoHash: string;
93
+ peerCount: number;
94
+ }[];
95
+ };
96
+ /**
97
+ * Get the rondevu credentials for persistence
98
+ */
99
+ getCredentials(): Credentials | undefined;
100
+ /**
101
+ * Clean up all resources and disconnect from rondevu
102
+ */
103
+ destroy(): void;
104
+ }
@@ -0,0 +1,266 @@
1
+ import { Rondevu, BloomFilter } from '@xtr-dev/rondevu-client';
2
+ /**
3
+ * Connection manager that uses Rondevu for WebTorrent peer discovery via WebRTC.
4
+ * This class acts as a plugin for WebTorrent, automatically discovering
5
+ * and connecting to peers through rondevu WebRTC signaling.
6
+ */
7
+ export class RondevuConnectionManager {
8
+ constructor(client, options = {}) {
9
+ this.torrentPeers = new Map();
10
+ this.torrentOffers = new Map();
11
+ this.torrentCleanupHandlers = new Map();
12
+ this.refreshTimers = new Map();
13
+ this.torrentBloomFilters = new Map();
14
+ this.client = client;
15
+ this.options = {
16
+ rondevuServer: options.rondevuServer,
17
+ maxPeersPerTorrent: options.maxPeersPerTorrent ?? 50,
18
+ debug: options.debug ?? false,
19
+ refreshInterval: options.refreshInterval ?? 30000,
20
+ rtcConfig: options.rtcConfig,
21
+ wrtc: options.wrtc,
22
+ };
23
+ this.rondevu = new Rondevu({
24
+ baseUrl: options.rondevuServer,
25
+ credentials: options.credentials,
26
+ RTCPeerConnection: options.wrtc?.RTCPeerConnection,
27
+ RTCSessionDescription: options.wrtc?.RTCSessionDescription,
28
+ RTCIceCandidate: options.wrtc?.RTCIceCandidate,
29
+ });
30
+ this.initialize();
31
+ }
32
+ /**
33
+ * Initialize the connection manager by setting up event listeners and registering with rondevu
34
+ */
35
+ async initialize() {
36
+ this.log('Initializing RondevuConnectionManager');
37
+ try {
38
+ if (!this.rondevu.isAuthenticated()) {
39
+ const credentials = await this.rondevu.register();
40
+ this.log(`Registered with rondevu: ${credentials.peerId}`);
41
+ }
42
+ else {
43
+ this.log(`Using existing credentials: ${this.rondevu.getCredentials()?.peerId}`);
44
+ }
45
+ }
46
+ catch (error) {
47
+ this.log(`Failed to register with rondevu: ${error}`);
48
+ return;
49
+ }
50
+ // Listen for new torrents being added
51
+ this.client.on('torrent', (torrent) => {
52
+ this.handleTorrentAdded(torrent);
53
+ });
54
+ // Handle existing torrents if any
55
+ this.client.torrents.forEach((torrent) => {
56
+ this.handleTorrentAdded(torrent);
57
+ });
58
+ }
59
+ /**
60
+ * Handle a torrent being added to the WebTorrent client
61
+ */
62
+ async handleTorrentAdded(torrent) {
63
+ const infoHash = torrent.infoHash;
64
+ this.log(`Torrent added: ${infoHash}`);
65
+ // Initialize tracking for this torrent
66
+ this.torrentPeers.set(infoHash, new Set());
67
+ this.torrentOffers.set(infoHash, []);
68
+ this.torrentBloomFilters.set(infoHash, new BloomFilter(1024, 3));
69
+ // Start discovering peers and creating offers
70
+ await this.discoverPeersForTorrent(torrent);
71
+ // Set up periodic peer refresh
72
+ const refreshTimer = setInterval(() => {
73
+ this.discoverPeersForTorrent(torrent);
74
+ }, this.options.refreshInterval);
75
+ this.refreshTimers.set(infoHash, refreshTimer);
76
+ // Set up cleanup handler for when torrent is destroyed
77
+ const cleanup = () => {
78
+ this.log(`Cleaning up torrent ${infoHash}`);
79
+ const timer = this.refreshTimers.get(infoHash);
80
+ if (timer) {
81
+ clearInterval(timer);
82
+ this.refreshTimers.delete(infoHash);
83
+ }
84
+ // Close all peer connections for this torrent
85
+ const peers = this.torrentPeers.get(infoHash);
86
+ if (peers) {
87
+ peers.forEach((peer) => {
88
+ try {
89
+ peer.close();
90
+ }
91
+ catch (error) {
92
+ this.log(`Error closing peer: ${error}`);
93
+ }
94
+ });
95
+ this.torrentPeers.delete(infoHash);
96
+ }
97
+ // Delete our offers for this torrent
98
+ const offerIds = this.torrentOffers.get(infoHash);
99
+ if (offerIds) {
100
+ offerIds.forEach(async (offerId) => {
101
+ try {
102
+ await this.rondevu.offers.delete(offerId);
103
+ }
104
+ catch (error) {
105
+ this.log(`Error deleting offer: ${error}`);
106
+ }
107
+ });
108
+ this.torrentOffers.delete(infoHash);
109
+ }
110
+ // Clean up bloom filter
111
+ this.torrentBloomFilters.delete(infoHash);
112
+ this.torrentCleanupHandlers.delete(infoHash);
113
+ };
114
+ torrent.on('done', () => {
115
+ this.log(`Torrent ${infoHash} completed`);
116
+ });
117
+ // Clean up when torrent is destroyed
118
+ torrent.once('destroyed', cleanup);
119
+ this.torrentCleanupHandlers.set(infoHash, cleanup);
120
+ }
121
+ /**
122
+ * Discover peers for a torrent using rondevu
123
+ */
124
+ async discoverPeersForTorrent(torrent) {
125
+ const infoHash = torrent.infoHash;
126
+ const currentPeerCount = this.torrentPeers.get(infoHash)?.size ?? 0;
127
+ // Check if we already have enough peers
128
+ if (currentPeerCount >= this.options.maxPeersPerTorrent) {
129
+ this.log(`Max peers reached for ${infoHash}`);
130
+ return;
131
+ }
132
+ try {
133
+ // Create our own offer for this torrent using rondevu.createPeer() to get WebRTC polyfills
134
+ const peer = this.rondevu.createPeer(this.options.rtcConfig);
135
+ this.log(`Creating offer for torrent ${infoHash}`);
136
+ const offerId = await peer.createOffer({
137
+ topics: [infoHash],
138
+ ttl: 300000, // 5 minutes in milliseconds
139
+ createDataChannel: true,
140
+ dataChannelLabel: 'webtorrent',
141
+ });
142
+ this.torrentOffers.get(infoHash)?.push(offerId);
143
+ // Set up peer connection handlers
144
+ this.setupPeerHandlers(peer, torrent, true);
145
+ // Discover other peers' offers for this torrent
146
+ this.log(`Discovering peers for torrent ${infoHash}`);
147
+ const bloomFilter = this.torrentBloomFilters.get(infoHash);
148
+ const offers = await this.rondevu.offers.findByTopic(infoHash, {
149
+ limit: this.options.maxPeersPerTorrent - currentPeerCount,
150
+ bloomFilter: bloomFilter?.toBytes(),
151
+ });
152
+ this.log(`Found ${offers.length} offers for torrent ${infoHash}`);
153
+ // Connect to discovered peers
154
+ for (const remoteOffer of offers) {
155
+ // Skip our own offers
156
+ if (remoteOffer.peerId === this.rondevu.getCredentials()?.peerId) {
157
+ continue;
158
+ }
159
+ // Skip if already answered
160
+ if (remoteOffer.answererPeerId) {
161
+ continue;
162
+ }
163
+ // Add to bloom filter to avoid rediscovering
164
+ bloomFilter?.add(remoteOffer.peerId);
165
+ try {
166
+ // Create peer using rondevu.createPeer() to get WebRTC polyfills
167
+ const answerPeer = this.rondevu.createPeer(this.options.rtcConfig);
168
+ this.log(`Answering offer ${remoteOffer.id} for torrent ${infoHash}`);
169
+ await answerPeer.answer(remoteOffer.id, remoteOffer.sdp, {
170
+ topics: [infoHash],
171
+ });
172
+ // Set up peer connection handlers
173
+ this.setupPeerHandlers(answerPeer, torrent, false);
174
+ }
175
+ catch (error) {
176
+ this.log(`Failed to answer offer ${remoteOffer.id}: ${error}`);
177
+ }
178
+ }
179
+ }
180
+ catch (error) {
181
+ this.log(`Error discovering peers for ${infoHash}: ${error}`);
182
+ }
183
+ }
184
+ /**
185
+ * Set up event handlers for a rondevu peer
186
+ */
187
+ setupPeerHandlers(peer, torrent, isOfferer) {
188
+ const infoHash = torrent.infoHash;
189
+ peer.on('connected', () => {
190
+ this.log(`Peer connected for torrent ${infoHash}`);
191
+ this.torrentPeers.get(infoHash)?.add(peer);
192
+ // Add the WebRTC peer connection to the torrent
193
+ // WebTorrent can use WebRTC peer connections directly
194
+ try {
195
+ torrent.addPeer(peer.pc);
196
+ }
197
+ catch (error) {
198
+ this.log(`Failed to add WebRTC peer to torrent: ${error}`);
199
+ }
200
+ });
201
+ peer.on('disconnected', () => {
202
+ this.log(`Peer disconnected for torrent ${infoHash}`);
203
+ this.torrentPeers.get(infoHash)?.delete(peer);
204
+ });
205
+ peer.on('failed', (error) => {
206
+ this.log(`Peer failed for torrent ${infoHash}: ${error.message}`);
207
+ this.torrentPeers.get(infoHash)?.delete(peer);
208
+ });
209
+ peer.on('datachannel', (channel) => {
210
+ this.log(`Data channel opened for torrent ${infoHash}: ${channel.label}`);
211
+ });
212
+ }
213
+ /**
214
+ * Log a message if debug mode is enabled
215
+ */
216
+ log(message) {
217
+ if (this.options.debug) {
218
+ console.log(`[RondevuConnectionManager] ${message}`);
219
+ }
220
+ }
221
+ /**
222
+ * Manually trigger peer discovery for a specific torrent
223
+ */
224
+ async discoverPeers(infoHash) {
225
+ const torrent = this.client.torrents.find((t) => t.infoHash === infoHash);
226
+ if (!torrent) {
227
+ this.log(`Torrent ${infoHash} not found`);
228
+ return;
229
+ }
230
+ await this.discoverPeersForTorrent(torrent);
231
+ }
232
+ /**
233
+ * Get statistics about the connection manager
234
+ */
235
+ getStats() {
236
+ const torrentStats = Array.from(this.torrentPeers.entries()).map(([infoHash, peers]) => ({
237
+ infoHash,
238
+ peerCount: peers.size,
239
+ }));
240
+ return {
241
+ activeTorrents: this.client.torrents.length,
242
+ peerId: this.rondevu.getCredentials()?.peerId,
243
+ rondevuServer: this.options.rondevuServer ?? 'https://api.ronde.vu',
244
+ torrents: torrentStats,
245
+ };
246
+ }
247
+ /**
248
+ * Get the rondevu credentials for persistence
249
+ */
250
+ getCredentials() {
251
+ return this.rondevu.getCredentials();
252
+ }
253
+ /**
254
+ * Clean up all resources and disconnect from rondevu
255
+ */
256
+ destroy() {
257
+ this.log('Destroying RondevuConnectionManager');
258
+ // Run all cleanup handlers
259
+ this.torrentCleanupHandlers.forEach((cleanup) => cleanup());
260
+ this.torrentCleanupHandlers.clear();
261
+ this.torrentPeers.clear();
262
+ this.torrentOffers.clear();
263
+ this.refreshTimers.clear();
264
+ this.torrentBloomFilters.clear();
265
+ }
266
+ }
@@ -0,0 +1 @@
1
+ export { RondevuConnectionManager, RondevuConnectionManagerOptions } from './RondevuConnectionManager.js';
package/dist/index.js ADDED
@@ -0,0 +1,40 @@
1
+ import WebTorrent from 'webtorrent';
2
+ import { RondevuConnectionManager } from './RondevuConnectionManager.js';
3
+ export { RondevuConnectionManager } from './RondevuConnectionManager.js';
4
+ // Example usage
5
+ // Check if this file is being run directly (not imported)
6
+ const isMainModule = import.meta.url === `file://${process.argv[1]}`;
7
+ if (isMainModule) {
8
+ const client = new WebTorrent();
9
+ // Initialize the Rondevu connection manager
10
+ const connectionManager = new RondevuConnectionManager(client, {
11
+ rondevuServer: 'https://api.ronde.vu', // Optional: defaults to this
12
+ maxPeersPerTorrent: 50,
13
+ debug: true,
14
+ refreshInterval: 30000, // 30 seconds
15
+ });
16
+ // Add a torrent (example with a magnet link)
17
+ const magnetURI = 'magnet:?xt=urn:btih:08ada5a7a6183aae1e09d831df6748d566095a10';
18
+ client.add(magnetURI, (torrent) => {
19
+ console.log(`Torrent added: ${torrent.name}`);
20
+ console.log(`Info hash: ${torrent.infoHash}`);
21
+ torrent.on('download', () => {
22
+ console.log(`Progress: ${(torrent.progress * 100).toFixed(2)}%`);
23
+ console.log(`Peers: ${torrent.numPeers}`);
24
+ console.log(`Download speed: ${(torrent.downloadSpeed / 1024).toFixed(2)} KB/s`);
25
+ });
26
+ torrent.on('done', () => {
27
+ console.log('Download complete!');
28
+ console.log('Stats:', connectionManager.getStats());
29
+ });
30
+ });
31
+ // Graceful shutdown
32
+ process.on('SIGINT', () => {
33
+ console.log('\nShutting down...');
34
+ connectionManager.destroy();
35
+ client.destroy(() => {
36
+ console.log('WebTorrent client destroyed');
37
+ process.exit(0);
38
+ });
39
+ });
40
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@xtr-dev/rondevu-webtorrent",
3
+ "version": "0.0.1",
4
+ "description": "WebTorrent peer discovery plugin using Rondevu WebRTC signaling",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "README.md",
11
+ "LICENSE"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "prepublishOnly": "npm run build",
16
+ "demo:seed": "npm run build && node demo/seed.mjs",
17
+ "demo:leech": "npm run build && node demo/leech.mjs"
18
+ },
19
+ "keywords": [
20
+ "webtorrent",
21
+ "rondevu",
22
+ "webrtc",
23
+ "peer-discovery",
24
+ "bittorrent",
25
+ "p2p"
26
+ ],
27
+ "author": "XTR Development",
28
+ "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/xtr-dev/rondevu-webtorrent.git"
32
+ },
33
+ "bugs": {
34
+ "url": "https://github.com/xtr-dev/rondevu-webtorrent/issues"
35
+ },
36
+ "homepage": "https://github.com/xtr-dev/rondevu-webtorrent#readme",
37
+ "dependencies": {
38
+ "@roamhq/wrtc": "^0.9.1",
39
+ "@xtr-dev/rondevu-client": "^0.7.4",
40
+ "webtorrent": "^2.8.4"
41
+ },
42
+ "devDependencies": {
43
+ "@types/webtorrent": "^0.110.1",
44
+ "typescript": "^5.5.3"
45
+ }
46
+ }