@xtr-dev/rondevu-webtorrent 0.0.1 → 0.0.3

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.
@@ -1,11 +1,16 @@
1
1
  import WebTorrent from 'webtorrent';
2
- import { Credentials } from '@xtr-dev/rondevu-client';
2
+ /**
3
+ * Credential type for rondevu authentication
4
+ */
5
+ export interface Credential {
6
+ name: string;
7
+ secret: string;
8
+ }
3
9
  /**
4
10
  * WebRTC polyfill interface for Node.js environments
5
11
  */
6
12
  export interface WebRTCPolyfill {
7
13
  RTCPeerConnection: typeof RTCPeerConnection;
8
- RTCSessionDescription: typeof RTCSessionDescription;
9
14
  RTCIceCandidate: typeof RTCIceCandidate;
10
15
  }
11
16
  /**
@@ -35,7 +40,7 @@ export interface RondevuConnectionManagerOptions {
35
40
  /**
36
41
  * Existing rondevu credentials to reuse
37
42
  */
38
- credentials?: Credentials;
43
+ credential?: Credential;
39
44
  /**
40
45
  * WebRTC polyfill for Node.js (e.g., @roamhq/wrtc)
41
46
  * Required for WebRTC functionality in Node.js environments
@@ -50,15 +55,14 @@ export interface RondevuConnectionManagerOptions {
50
55
  export declare class RondevuConnectionManager {
51
56
  private client;
52
57
  private rondevu;
58
+ private torrentOfferHandles;
53
59
  private torrentPeers;
54
- private torrentOffers;
55
60
  private torrentCleanupHandlers;
56
61
  private refreshTimers;
57
- private torrentBloomFilters;
58
62
  private options;
59
63
  constructor(client: WebTorrent.Instance, options?: RondevuConnectionManagerOptions);
60
64
  /**
61
- * Initialize the connection manager by setting up event listeners and registering with rondevu
65
+ * Initialize the connection manager by setting up event listeners and connecting to rondevu
62
66
  */
63
67
  private initialize;
64
68
  /**
@@ -69,10 +73,6 @@ export declare class RondevuConnectionManager {
69
73
  * Discover peers for a torrent using rondevu
70
74
  */
71
75
  private discoverPeersForTorrent;
72
- /**
73
- * Set up event handlers for a rondevu peer
74
- */
75
- private setupPeerHandlers;
76
76
  /**
77
77
  * Log a message if debug mode is enabled
78
78
  */
@@ -86,7 +86,7 @@ export declare class RondevuConnectionManager {
86
86
  */
87
87
  getStats(): {
88
88
  activeTorrents: number;
89
- peerId: string | undefined;
89
+ username: string | undefined;
90
90
  rondevuServer: string;
91
91
  torrents: {
92
92
  infoHash: string;
@@ -94,9 +94,9 @@ export declare class RondevuConnectionManager {
94
94
  }[];
95
95
  };
96
96
  /**
97
- * Get the rondevu credentials for persistence
97
+ * Get the rondevu credential for persistence
98
98
  */
99
- getCredentials(): Credentials | undefined;
99
+ getCredential(): Credential | undefined;
100
100
  /**
101
101
  * Clean up all resources and disconnect from rondevu
102
102
  */
@@ -1,4 +1,18 @@
1
- import { Rondevu, BloomFilter } from '@xtr-dev/rondevu-client';
1
+ import { Rondevu } from '@xtr-dev/rondevu-client';
2
+ /**
3
+ * Simple WebRTC adapter for Node.js using wrtc polyfill
4
+ */
5
+ class NodeWebRTCAdapter {
6
+ constructor(polyfills) {
7
+ this.polyfills = polyfills;
8
+ }
9
+ createPeerConnection(config) {
10
+ return new this.polyfills.RTCPeerConnection(config);
11
+ }
12
+ createIceCandidate(candidateInit) {
13
+ return new this.polyfills.RTCIceCandidate(candidateInit);
14
+ }
15
+ }
2
16
  /**
3
17
  * Connection manager that uses Rondevu for WebTorrent peer discovery via WebRTC.
4
18
  * This class acts as a plugin for WebTorrent, automatically discovering
@@ -6,11 +20,11 @@ import { Rondevu, BloomFilter } from '@xtr-dev/rondevu-client';
6
20
  */
7
21
  export class RondevuConnectionManager {
8
22
  constructor(client, options = {}) {
23
+ this.rondevu = null;
24
+ this.torrentOfferHandles = new Map();
9
25
  this.torrentPeers = new Map();
10
- this.torrentOffers = new Map();
11
26
  this.torrentCleanupHandlers = new Map();
12
27
  this.refreshTimers = new Map();
13
- this.torrentBloomFilters = new Map();
14
28
  this.client = client;
15
29
  this.options = {
16
30
  rondevuServer: options.rondevuServer,
@@ -19,32 +33,36 @@ export class RondevuConnectionManager {
19
33
  refreshInterval: options.refreshInterval ?? 30000,
20
34
  rtcConfig: options.rtcConfig,
21
35
  wrtc: options.wrtc,
36
+ credential: options.credential,
22
37
  };
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
38
  this.initialize();
31
39
  }
32
40
  /**
33
- * Initialize the connection manager by setting up event listeners and registering with rondevu
41
+ * Initialize the connection manager by setting up event listeners and connecting to rondevu
34
42
  */
35
43
  async initialize() {
36
44
  this.log('Initializing RondevuConnectionManager');
37
45
  try {
38
- if (!this.rondevu.isAuthenticated()) {
39
- const credentials = await this.rondevu.register();
40
- this.log(`Registered with rondevu: ${credentials.peerId}`);
46
+ // Build connection options
47
+ const connectOptions = {
48
+ apiUrl: this.options.rondevuServer,
49
+ credential: this.options.credential,
50
+ debug: this.options.debug,
51
+ };
52
+ // Add WebRTC adapter if wrtc polyfill provided
53
+ if (this.options.wrtc) {
54
+ connectOptions.webrtcAdapter = new NodeWebRTCAdapter(this.options.wrtc);
41
55
  }
42
- else {
43
- this.log(`Using existing credentials: ${this.rondevu.getCredentials()?.peerId}`);
56
+ // Add ICE servers if custom config provided
57
+ if (this.options.rtcConfig?.iceServers) {
58
+ connectOptions.iceServers = this.options.rtcConfig.iceServers;
44
59
  }
60
+ // Connect to rondevu (auto-generates credentials if not provided)
61
+ this.rondevu = await Rondevu.connect(connectOptions);
62
+ this.log(`Connected to rondevu as: ${this.rondevu.getName()}`);
45
63
  }
46
64
  catch (error) {
47
- this.log(`Failed to register with rondevu: ${error}`);
65
+ this.log(`Failed to connect to rondevu: ${error}`);
48
66
  return;
49
67
  }
50
68
  // Listen for new torrents being added
@@ -60,12 +78,14 @@ export class RondevuConnectionManager {
60
78
  * Handle a torrent being added to the WebTorrent client
61
79
  */
62
80
  async handleTorrentAdded(torrent) {
81
+ if (!this.rondevu) {
82
+ this.log('Rondevu not initialized, skipping torrent');
83
+ return;
84
+ }
63
85
  const infoHash = torrent.infoHash;
64
86
  this.log(`Torrent added: ${infoHash}`);
65
87
  // Initialize tracking for this torrent
66
88
  this.torrentPeers.set(infoHash, new Set());
67
- this.torrentOffers.set(infoHash, []);
68
- this.torrentBloomFilters.set(infoHash, new BloomFilter(1024, 3));
69
89
  // Start discovering peers and creating offers
70
90
  await this.discoverPeersForTorrent(torrent);
71
91
  // Set up periodic peer refresh
@@ -81,6 +101,12 @@ export class RondevuConnectionManager {
81
101
  clearInterval(timer);
82
102
  this.refreshTimers.delete(infoHash);
83
103
  }
104
+ // Cancel our offer for this torrent
105
+ const offerHandle = this.torrentOfferHandles.get(infoHash);
106
+ if (offerHandle) {
107
+ offerHandle.cancel();
108
+ this.torrentOfferHandles.delete(infoHash);
109
+ }
84
110
  // Close all peer connections for this torrent
85
111
  const peers = this.torrentPeers.get(infoHash);
86
112
  if (peers) {
@@ -94,21 +120,6 @@ export class RondevuConnectionManager {
94
120
  });
95
121
  this.torrentPeers.delete(infoHash);
96
122
  }
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
123
  this.torrentCleanupHandlers.delete(infoHash);
113
124
  };
114
125
  torrent.on('done', () => {
@@ -122,6 +133,8 @@ export class RondevuConnectionManager {
122
133
  * Discover peers for a torrent using rondevu
123
134
  */
124
135
  async discoverPeersForTorrent(torrent) {
136
+ if (!this.rondevu)
137
+ return;
125
138
  const infoHash = torrent.infoHash;
126
139
  const currentPeerCount = this.torrentPeers.get(infoHash)?.size ?? 0;
127
140
  // Check if we already have enough peers
@@ -130,50 +143,79 @@ export class RondevuConnectionManager {
130
143
  return;
131
144
  }
132
145
  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);
146
+ // Create offers for this torrent if we haven't already
147
+ if (!this.torrentOfferHandles.has(infoHash)) {
148
+ this.log(`Creating offers for torrent ${infoHash}`);
149
+ const offerHandle = await this.rondevu.offer({
150
+ tags: [infoHash],
151
+ maxOffers: 3, // Maintain pool of 3 offers
152
+ ttl: 300000, // 5 minutes
153
+ autoStart: true,
154
+ });
155
+ this.torrentOfferHandles.set(infoHash, offerHandle);
156
+ // Listen for incoming connections on our offers
157
+ this.rondevu.on('connection:opened', (_offerId, connection) => {
158
+ this.log(`Incoming connection for torrent ${infoHash}`);
159
+ connection.on('connected', () => {
160
+ // Add the WebRTC peer connection to the torrent
161
+ try {
162
+ const pc = connection.getPeerConnection();
163
+ if (pc) {
164
+ torrent.addPeer(pc);
165
+ this.log(`Added incoming peer to torrent ${infoHash}`);
166
+ }
167
+ }
168
+ catch (error) {
169
+ this.log(`Failed to add incoming peer: ${error}`);
170
+ }
171
+ });
172
+ });
173
+ }
145
174
  // Discover other peers' offers for this torrent
146
175
  this.log(`Discovering peers for torrent ${infoHash}`);
147
- const bloomFilter = this.torrentBloomFilters.get(infoHash);
148
- const offers = await this.rondevu.offers.findByTopic(infoHash, {
176
+ const result = await this.rondevu.discover([infoHash], {
149
177
  limit: this.options.maxPeersPerTorrent - currentPeerCount,
150
- bloomFilter: bloomFilter?.toBytes(),
151
178
  });
152
- this.log(`Found ${offers.length} offers for torrent ${infoHash}`);
153
- // Connect to discovered peers
154
- for (const remoteOffer of offers) {
179
+ this.log(`Found ${result.offers.length} offers for torrent ${infoHash}`);
180
+ // Connect to discovered peers using the simplified peer() API
181
+ for (const remoteOffer of result.offers) {
155
182
  // Skip our own offers
156
- if (remoteOffer.peerId === this.rondevu.getCredentials()?.peerId) {
157
- continue;
158
- }
159
- // Skip if already answered
160
- if (remoteOffer.answererPeerId) {
183
+ if (remoteOffer.username === this.rondevu.getName()) {
161
184
  continue;
162
185
  }
163
- // Add to bloom filter to avoid rediscovering
164
- bloomFilter?.add(remoteOffer.peerId);
165
186
  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],
187
+ this.log(`Connecting to peer ${remoteOffer.username} for torrent ${infoHash}`);
188
+ const peer = await this.rondevu.peer({
189
+ tags: [infoHash],
190
+ username: remoteOffer.username,
191
+ });
192
+ // Track this peer
193
+ this.torrentPeers.get(infoHash)?.add(peer);
194
+ // Set up peer handlers
195
+ peer.on('open', () => {
196
+ this.log(`Connected to peer ${peer.peerUsername} for torrent ${infoHash}`);
197
+ // Add the WebRTC peer connection to the torrent
198
+ try {
199
+ const pc = peer.peerConnection;
200
+ if (pc) {
201
+ torrent.addPeer(pc);
202
+ }
203
+ }
204
+ catch (error) {
205
+ this.log(`Failed to add WebRTC peer to torrent: ${error}`);
206
+ }
207
+ });
208
+ peer.on('close', () => {
209
+ this.log(`Peer disconnected for torrent ${infoHash}`);
210
+ this.torrentPeers.get(infoHash)?.delete(peer);
211
+ });
212
+ peer.on('error', (error) => {
213
+ this.log(`Peer error for torrent ${infoHash}: ${error.message}`);
214
+ this.torrentPeers.get(infoHash)?.delete(peer);
171
215
  });
172
- // Set up peer connection handlers
173
- this.setupPeerHandlers(answerPeer, torrent, false);
174
216
  }
175
217
  catch (error) {
176
- this.log(`Failed to answer offer ${remoteOffer.id}: ${error}`);
218
+ this.log(`Failed to connect to peer ${remoteOffer.username}: ${error}`);
177
219
  }
178
220
  }
179
221
  }
@@ -181,35 +223,6 @@ export class RondevuConnectionManager {
181
223
  this.log(`Error discovering peers for ${infoHash}: ${error}`);
182
224
  }
183
225
  }
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
226
  /**
214
227
  * Log a message if debug mode is enabled
215
228
  */
@@ -239,16 +252,16 @@ export class RondevuConnectionManager {
239
252
  }));
240
253
  return {
241
254
  activeTorrents: this.client.torrents.length,
242
- peerId: this.rondevu.getCredentials()?.peerId,
255
+ username: this.rondevu?.getName(),
243
256
  rondevuServer: this.options.rondevuServer ?? 'https://api.ronde.vu',
244
257
  torrents: torrentStats,
245
258
  };
246
259
  }
247
260
  /**
248
- * Get the rondevu credentials for persistence
261
+ * Get the rondevu credential for persistence
249
262
  */
250
- getCredentials() {
251
- return this.rondevu.getCredentials();
263
+ getCredential() {
264
+ return this.rondevu?.getCredential();
252
265
  }
253
266
  /**
254
267
  * Clean up all resources and disconnect from rondevu
@@ -259,8 +272,7 @@ export class RondevuConnectionManager {
259
272
  this.torrentCleanupHandlers.forEach((cleanup) => cleanup());
260
273
  this.torrentCleanupHandlers.clear();
261
274
  this.torrentPeers.clear();
262
- this.torrentOffers.clear();
275
+ this.torrentOfferHandles.clear();
263
276
  this.refreshTimers.clear();
264
- this.torrentBloomFilters.clear();
265
277
  }
266
278
  }
package/dist/index.d.ts CHANGED
@@ -1 +1 @@
1
- export { RondevuConnectionManager, RondevuConnectionManagerOptions } from './RondevuConnectionManager.js';
1
+ export { RondevuConnectionManager, RondevuConnectionManagerOptions, Credential, WebRTCPolyfill } from './RondevuConnectionManager.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xtr-dev/rondevu-webtorrent",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "WebTorrent peer discovery plugin using Rondevu WebRTC signaling",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -36,7 +36,7 @@
36
36
  "homepage": "https://github.com/xtr-dev/rondevu-webtorrent#readme",
37
37
  "dependencies": {
38
38
  "@roamhq/wrtc": "^0.9.1",
39
- "@xtr-dev/rondevu-client": "^0.7.4",
39
+ "@xtr-dev/rondevu-client": "^0.21.3",
40
40
  "webtorrent": "^2.8.4"
41
41
  },
42
42
  "devDependencies": {