import JSZip from 'jszip' ; import { items } from '@internxt/lib' ; import { ActionState } from '@internxt/inxt-js/build/api/ActionState' ; import errorService from 'app/core/services/error.service' ; import { getEnvironmentConfig , Network } from '../../../services/network' ; import { DriveFileData , DriveFolderData , FolderTree } from '../../../types' ; import folderService from '../../folder.service' ; import internal from 'stream' ; description param folderData param isTeam export default async function downloadFolderUsingFileSystemAccessAPI ( { folder , decryptedCallback , updateProgressCallback , errorCallback , isTeam , } ) { const downloadingSize = { } ; const fileStreams = [ ] ; const actionStates = [ ] ; const handle = await window . showSaveFilePicker ( { suggestedName : `${ folder . name }.zip` , types : [ { accept : { 'application/zip' : [ '.zip' ] } } ] , } ) ; if ( ! handle ) { throw new Error ( ) ; } const writable = await handle . createWritable ( ) ; const { bucketId , bridgeUser , bridgePass , encryptionKey } = getEnvironmentConfig ( isTeam ) ; const network = new Network ( bridgeUser , bridgePass , encryptionKey ) ; const { tree , folderDecryptedNames , fileDecryptedNames , size } = await folderService . fetchFolderTree ( folder . id ) ; const zip = new JSZip ( ) ; decryptedCallback ?. ( ) ; try { const pendingFolders = [ { parentFolder : null , data : tree } ] ; while ( pendingFolders . length > 0 ) { const currentFolder = pendingFolders [ 0 ] ; const currentFolderZip = currentFolder . parentFolder ?. folder ( folderDecryptedNames [ currentFolder . data . id ] ) || zip ; const { files , folders } = { files : currentFolder . data . files , folders : currentFolder . data . children , } ; pendingFolders . shift ( ) ; for ( const file of files ) { const displayFilename = items . getItemDisplayName ( { name : fileDecryptedNames [ file . id ] , type : file . type , } ) ; const [ fileStreamPromise , actionState ] = network . getFileDownloadStream ( bucketId , file . fileId , { progressCallback : ( fileProgress ) => { downloadingSize [ file . id ] = file . size * fileProgress ; const totalDownloadedSize = Object . values ( downloadingSize ) . reduce ( ( t , x ) => t + x , 0 ) ; const totalProgress = totalDownloadedSize / size ; ( updateProgressCallback || ( ( ) => undefined ) ) ( totalProgress ) ; } , } ) ; const fileStream = await fileStreamPromise ; currentFolderZip ?. file ( displayFilename , fileStream , { compression : 'DEFLATE' } ) ; fileStreams . push ( { file , stream : fileStream } ) ; actionState && actionStates . push ( actionState ) ; } pendingFolders . push ( ... folders . map ( ( data ) => ( { parentFolder : currentFolderZip , data , } ) ) ) ; } return [ new Promise < void > ( ( resolve , reject ) => { const folderStream = zip . generateInternalStream ( { type : 'uint8array' , streamFiles : true , compression : 'DEFLATE' , } ) as internal . Readable ; folderStream ?. on ( 'data' , ( chunk ) => { writable . write ( chunk ) ; } ) . on ( 'end' , ( ) => { writable . close ( ) ; resolve ( ) ; } ) . on ( 'error' , ( err ) => { errorCallback ?. ( err ) ; reject ( err ) ; } ) ; folderStream . resume ( ) ; } ) , actionStates , ] ; } catch ( err ) { const castedError = errorService . castError ( err ) ; writable . abort ( ) ; throw castedError ; } }