@@ -17,12 +17,46 @@ import crypto from 'crypto';
1717// Configuration
1818const CONFIG = {
1919 digDirectory : path . join ( os . homedir ( ) , '.dig' ) ,
20- discoveryIntervalMs : 30000 , // 30 seconds
20+ discoveryIntervalMs : 30000 , // 5 minutes
2121 peers : [ 'http://dig-relay-prod.eba-2cmanxbe.us-east-1.elasticbeanstalk.com/gun' ]
2222} ;
2323
2424// Track files currently being downloaded to prevent duplicates
2525const downloadingFiles = new Set ( ) ;
26+ const downloadQueue = [ ] ; // Queue for pending downloads
27+ let currentDownload = null ; // Track current download
28+
29+ /**
30+ * Process the next download in the queue
31+ */
32+ function processNextDownload ( natTools ) {
33+ // If already downloading or queue is empty, do nothing
34+ if ( currentDownload !== null || downloadQueue . length === 0 ) {
35+ return ;
36+ }
37+
38+ // Get the next download from the queue
39+ const { magnetUri, displayName, existingFiles } = downloadQueue . shift ( ) ;
40+ currentDownload = magnetUri ;
41+ downloadingFiles . add ( magnetUri ) ;
42+
43+ logger . info ( `\n📥 Starting download: ${ displayName } (${ downloadQueue . length } remaining in queue)` ) ;
44+
45+ // Fire-and-forget: just start the download
46+ // Events will be handled by the global listeners set up in main()
47+ natTools . downloadFromMagnet ( magnetUri ) ;
48+ }
49+
50+ /**
51+ * Add a download to the queue and start processing if not already downloading
52+ */
53+ function queueDownload ( natTools , magnetUri , displayName , existingFiles ) {
54+ downloadQueue . push ( { magnetUri, displayName, existingFiles } ) ;
55+ logger . info ( `📋 Queued: ${ displayName } (queue size: ${ downloadQueue . length } )` ) ;
56+
57+ // Start processing if not already downloading
58+ processNextDownload ( natTools ) ;
59+ }
2660
2761// Create a simple logger
2862const logger = {
@@ -165,73 +199,38 @@ async function discoverAndDownload(natTools) {
165199 return ;
166200 }
167201
168- logger . info ( `📥 Found ${ newMagnetUris . length } new files to download` ) ;
169-
170202 // Ensure download directory exists
171203 if ( ! fs . existsSync ( CONFIG . digDirectory ) ) {
172204 fs . mkdirSync ( CONFIG . digDirectory , { recursive : true } ) ;
173205 }
174206
175- // Download new files
176- for ( const magnetUri of newMagnetUris ) {
177- try {
178- // Extract display name from magnet URI (dn parameter) or use timestamp
179- const displayNameMatch = magnetUri . match ( / d n = ( [ ^ & ] + ) / ) ;
180- const displayName = displayNameMatch ? decodeURIComponent ( displayNameMatch [ 1 ] ) : `file-${ Date . now ( ) } ` ;
181-
182- // Check if already downloading
183- if ( downloadingFiles . has ( magnetUri ) ) {
184- logger . debug ( `⏳ Already downloading: ${ displayName } ` ) ;
185- continue ;
186- }
187-
188- // Mark as downloading
189- downloadingFiles . add ( magnetUri ) ;
190-
191- logger . info ( `📥 Downloading: ${ displayName } ...` ) ;
192-
193- try {
194- // Download the file
195- const buffer = await natTools . downloadFromMagnet ( magnetUri ) ;
196-
197- // Calculate hash of downloaded content
198- const contentHash = crypto . createHash ( 'sha256' ) . update ( buffer ) . digest ( 'hex' ) ;
199-
200- // Check if we already have this content
201- if ( existingFiles . has ( contentHash ) ) {
202- logger . info ( `⏭️ Already have file with hash ${ contentHash . substring ( 0 , 16 ) } ...` ) ;
203- downloadingFiles . delete ( magnetUri ) ;
204- continue ;
205- }
206-
207- // Save the file with the display name or content hash
208- const fileName = displayName . endsWith ( '.dig' ) ? displayName : `${ contentHash } .dig` ;
209- const filePath = path . join ( CONFIG . digDirectory , fileName ) ;
210- fs . writeFileSync ( filePath , buffer ) ;
207+ logger . info ( `📥 Found ${ newMagnetUris . length } new files to download` ) ;
208+ logger . info ( `🔄 Adding to sequential download queue...` ) ;
211209
212- logger . info ( `✅ Downloaded: ${ fileName } (${ buffer . length } bytes)` ) ;
210+ // Create a set of magnet URIs already in the queue
211+ const queuedMagnetUris = new Set ( downloadQueue . map ( item => item . magnetUri ) ) ;
213212
214- // Add to existing files set
215- existingFiles . add ( contentHash ) ;
213+ // Queue all new downloads
214+ let addedCount = 0 ;
215+ for ( const magnetUri of newMagnetUris ) {
216+ // Skip if already downloading, in queue, or we already have it seeded
217+ if ( downloadingFiles . has ( magnetUri ) || queuedMagnetUris . has ( magnetUri ) ) {
218+ continue ;
219+ }
216220
217- // Remove from downloading set
218- downloadingFiles . delete ( magnetUri ) ;
221+ // Extract display name from magnet URI (dn parameter) or use timestamp
222+ const displayNameMatch = magnetUri . match ( / d n = ( [ ^ & ] + ) / ) ;
223+ const displayName = displayNameMatch ? decodeURIComponent ( displayNameMatch [ 1 ] ) : `file-${ Date . now ( ) } ` ;
219224
220- // Optionally seed the downloaded file
221- try {
222- await natTools . seedFile ( filePath ) ;
223- logger . info ( `🌱 Now seeding downloaded file: ${ fileName } ` ) ;
224- } catch ( error ) {
225- logger . warn ( `⚠️ Could not seed downloaded file:` , error . message ) ;
226- }
227- } catch ( downloadError ) {
228- downloadingFiles . delete ( magnetUri ) ;
229- throw downloadError ;
230- }
225+ // Add to queue
226+ queueDownload ( natTools , magnetUri , displayName , existingFiles ) ;
227+ addedCount ++ ;
228+ }
231229
232- } catch ( error ) {
233- logger . error ( `❌ Failed to download file:` , error . message ) ;
234- }
230+ if ( addedCount > 0 ) {
231+ logger . info ( `✅ Added ${ addedCount } new downloads to queue` ) ;
232+ } else {
233+ logger . info ( `ℹ️ No new downloads to add (all are already downloading or queued)` ) ;
235234 }
236235
237236 } catch ( error ) {
@@ -264,10 +263,8 @@ async function main() {
264263 await natTools . initialize ( ) ;
265264 logger . info ( '✅ NAT Tools initialized' ) ;
266265
267- // Set up download progress tracking
268- let currentDownload = null ;
266+ // Set up download event handlers
269267 webTorrentManager . on ( 'metadata' , ( data ) => {
270- currentDownload = data . name ;
271268 logger . info ( `📋 Metadata received: ${ data . name } (${ ( data . size / 1024 / 1024 ) . toFixed ( 2 ) } MB)` ) ;
272269 } ) ;
273270
@@ -280,6 +277,65 @@ async function main() {
280277 }
281278 } ) ;
282279
280+ // Handle download completion
281+ webTorrentManager . on ( 'download-complete' , async ( data ) => {
282+ logger . info ( `✅ Download complete: ${ data . name } (${ data . size } bytes)` ) ;
283+
284+ try {
285+ // Calculate hash of downloaded content
286+ const contentHash = crypto . createHash ( 'sha256' ) . update ( data . buffer ) . digest ( 'hex' ) ;
287+
288+ // Find the display name from the magnet URI
289+ const displayNameMatch = data . magnetUri . match ( / d n = ( [ ^ & ] + ) / ) ;
290+ const displayName = displayNameMatch ? decodeURIComponent ( displayNameMatch [ 1 ] ) : `file-${ Date . now ( ) } ` ;
291+
292+ // Save the file with the display name or content hash
293+ const fileName = displayName . endsWith ( '.dig' ) ? displayName : `${ contentHash } .dig` ;
294+ const filePath = path . join ( CONFIG . digDirectory , fileName ) ;
295+
296+ // Check if we already have this file
297+ if ( fs . existsSync ( filePath ) ) {
298+ logger . info ( `⏭️ File already exists: ${ fileName } ` ) ;
299+ } else {
300+ fs . writeFileSync ( filePath , data . buffer ) ;
301+ logger . info ( `💾 Saved file: ${ fileName } ` ) ;
302+
303+ // Optionally seed the downloaded file
304+ try {
305+ await natTools . seedFile ( filePath ) ;
306+ logger . info ( `🌱 Now seeding downloaded file: ${ fileName } ` ) ;
307+ } catch ( error ) {
308+ logger . warn ( `⚠️ Could not seed downloaded file:` , error . message ) ;
309+ }
310+ }
311+ } catch ( error ) {
312+ logger . error ( `❌ Error processing downloaded file:` , error . message ) ;
313+ } finally {
314+ // Remove from downloading set
315+ downloadingFiles . delete ( data . magnetUri ) ;
316+ if ( currentDownload === data . magnetUri ) {
317+ currentDownload = null ;
318+ }
319+
320+ // Process next download in queue
321+ setImmediate ( ( ) => processNextDownload ( natTools ) ) ;
322+ }
323+ } ) ;
324+
325+ // Handle download errors
326+ webTorrentManager . on ( 'download-error' , ( data ) => {
327+ logger . error ( `❌ Download failed: ${ data . magnetUri . substring ( 0 , 50 ) } ...` , data . error ) ;
328+
329+ // Remove from downloading set
330+ downloadingFiles . delete ( data . magnetUri ) ;
331+ if ( currentDownload === data . magnetUri ) {
332+ currentDownload = null ;
333+ }
334+
335+ // Process next download in queue
336+ setImmediate ( ( ) => processNextDownload ( natTools ) ) ;
337+ } ) ;
338+
283339 // Check availability
284340 const webTorrentAvailable = natTools . isWebTorrentAvailable ( ) ;
285341 const registryAvailable = natTools . isRegistryAvailable ( ) ;
0 commit comments