@@ -14,8 +14,8 @@ import {
14
14
import fs from 'fs' ;
15
15
import path from 'path' ;
16
16
import url from 'url' ;
17
+ import sanitizeFilename from 'sanitize-filename' ;
17
18
18
- import { NFTInfo } from '@chia-network/api' ;
19
19
import { initialize , enable } from '@electron/remote/main' ;
20
20
import axios from 'axios' ;
21
21
import windowStateKeeper from 'electron-window-state' ;
@@ -32,6 +32,7 @@ import AppIcon from '../assets/img/chia64x64.png';
32
32
import About from '../components/about/About' ;
33
33
import { i18n } from '../config/locales' ;
34
34
import chiaEnvironment , { chiaInit } from '../util/chiaEnvironment' ;
35
+ import downloadFile from './utils/downloadFile' ;
35
36
import loadConfig , { checkConfigFileExists } from '../util/loadConfig' ;
36
37
import manageDaemonLifetime from '../util/manageDaemonLifetime' ;
37
38
import { setUserDataDir } from '../util/userData' ;
@@ -261,20 +262,7 @@ if (ensureSingleInstance() && ensureCorrectEnvironment()) {
261
262
return { err, statusCode, statusMessage, responseBody } ;
262
263
} ) ;
263
264
264
- function getRemoteFileSize ( urlLocal : string ) : Promise < number > {
265
- return new Promise ( ( resolve , reject ) => {
266
- axios ( {
267
- method : 'HEAD' ,
268
- url : urlLocal ,
269
- } )
270
- . then ( ( response ) => {
271
- resolve ( Number ( response . headers [ 'content-length' ] || - 1 ) ) ;
272
- } )
273
- . catch ( ( e ) => {
274
- reject ( e . message ) ;
275
- } ) ;
276
- } ) ;
277
- }
265
+
278
266
279
267
ipcMain . handle ( 'showMessageBox' , async ( _event , options ) => dialog . showMessageBox ( mainWindow , options ) ) ;
280
268
@@ -334,93 +322,46 @@ if (ensureSingleInstance() && ensureCorrectEnvironment()) {
334
322
return responseObj ;
335
323
} ) ;
336
324
337
- type DownloadFileWithProgressProps = {
338
- folder : string ;
339
- nft : NFTInfo ;
340
- current : number ;
341
- total : number ;
342
- } ;
343
-
344
- function downloadFileWithProgress ( props : DownloadFileWithProgressProps ) : Promise < number > {
345
- const { folder, nft, current, total } = props ;
346
- const uri = nft . dataUris [ 0 ] ;
347
- return new Promise ( ( resolve , reject ) => {
348
- getRemoteFileSize ( uri )
349
- . then ( ( fileSize : number ) => {
350
- let totalLength = 0 ;
351
- currentDownloadRequest = net . request ( uri ) ;
352
- currentDownloadRequest . on ( 'response' , ( response : IncomingMessage ) => {
353
- let fileName : string = '' ;
354
- /* first try to get file name from server headers */
355
- const disposition = response . headers [ 'content-disposition' ] ;
356
- if ( disposition && typeof disposition === 'string' ) {
357
- const filenameRegex = / f i l e n a m e [ ^ ; = \n ] * = ( ( [ ' " ] ) .* ?\2| [ ^ ; \n ] * ) / ;
358
- const matches = filenameRegex . exec ( disposition ) ;
359
- if ( matches != null && matches [ 1 ] ) {
360
- fileName = matches [ 1 ] . replace ( / [ ' " ] / g, '' ) ;
361
- }
362
- }
363
- /* if we didn't get file name from server headers, then parse it from uri */
364
- fileName = fileName || uri . replace ( / \/ $ / , '' ) . split ( '/' ) . splice ( - 1 , 1 ) [ 0 ] ;
365
- currentDownloadRequest . on ( 'abort' , ( ) => {
366
- reject ( new Error ( 'download aborted' ) ) ;
367
- } ) ;
368
-
369
- /* if there is already a file with that name in this folder, add nftId to the file name */
370
- if ( fs . existsSync ( path . join ( folder , fileName ) ) ) {
371
- fileName = `${ fileName } -${ nft . $nftId } ` ;
372
- }
373
-
374
- const fileStream = fs . createWriteStream ( path . join ( folder , fileName ) ) ;
375
- response . on ( 'data' , ( chunk ) => {
376
- fileStream . write ( chunk ) ;
377
- totalLength += chunk . byteLength ;
378
- if ( fileSize > 0 ) {
379
- mainWindow ?. webContents . send ( 'downloadProgress' , {
380
- url : nft . dataUris [ 0 ] ,
381
- nftId : nft . $nftId ,
382
- progress : totalLength / fileSize ,
383
- i : current ,
384
- total,
385
- } ) ;
386
- }
387
- } ) ;
388
- response . on ( 'end' , ( ) => {
389
- if ( fileStream ) {
390
- fileStream . end ( ) ;
391
- }
392
- resolve ( totalLength ) ;
393
- } ) ;
394
- } ) ;
395
- currentDownloadRequest . end ( ) ;
396
- } )
397
- . catch ( ( error ) => {
398
- reject ( error ) ;
399
- } ) ;
400
- } ) ;
401
- }
402
325
403
- ipcMain . handle ( 'startMultipleDownload' , async ( _event : any , options : any ) => {
326
+ ipcMain . handle ( 'startMultipleDownload' , async ( _event : any , options : { folder : string , tasks : { url : string ; filename : string } [ ] } ) => {
404
327
/* eslint no-await-in-loop: off -- we want to handle each file separately! */
405
328
let totalDownloadedSize = 0 ;
406
329
let successFileCount = 0 ;
407
330
let errorFileCount = 0 ;
408
- for ( let i = 0 ; i < options . nfts . length ; i ++ ) {
409
- let fileSize ;
331
+
332
+ const { folder, tasks } = options ;
333
+
334
+ for ( let i = 0 ; i < tasks . length ; i ++ ) {
335
+ const { url : downloadUrl , filename } = tasks [ i ] ;
336
+
410
337
try {
411
- fileSize = await downloadFileWithProgress ( {
412
- folder : options . folder ,
413
- nft : options . nfts [ i ] ,
414
- current : i ,
415
- total : options . nfts . length ,
338
+ const sanitizedFilename = sanitizeFilename ( filename ) ;
339
+ if ( sanitizedFilename !== filename ) {
340
+ throw new Error ( `Filename ${ filename } contains invalid characters. Filename sanitized to ${ sanitizedFilename } ` ) ;
341
+ }
342
+
343
+ const filePath = path . join ( folder , sanitizedFilename ) ;
344
+
345
+ await downloadFile ( downloadUrl , filePath , {
346
+ onProgress : ( progress ) => {
347
+ mainWindow ?. webContents . send ( 'multipleDownloadProgress' , {
348
+ progress,
349
+ url : downloadUrl ,
350
+ index : i ,
351
+ total : tasks . length ,
352
+ } ) ;
353
+ } ,
416
354
} ) ;
417
- totalDownloadedSize += fileSize ;
355
+
356
+ const fileStats = await fs . promises . stat ( filePath ) ;
357
+
358
+ totalDownloadedSize += fileStats . size ;
418
359
successFileCount ++ ;
419
360
} catch ( e : any ) {
420
361
if ( e . message === 'download aborted' && abortDownloadingFiles ) {
421
362
break ;
422
363
}
423
- mainWindow ?. webContents . send ( 'errorDownloadingUrl' , options . nfts [ i ] ) ;
364
+ mainWindow ?. webContents . send ( 'errorDownloadingUrl' , downloadUrl ) ;
424
365
errorFileCount ++ ;
425
366
}
426
367
}
0 commit comments