diff --git a/android/app/build.gradle b/android/app/build.gradle index 40b3e3c3c..b126d6053 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -88,8 +88,8 @@ android { applicationId 'com.internxt.cloud' minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 102 - versionName "1.7.0" + versionCode 101 + versionName "1.7.1" buildConfigField("boolean", "REACT_NATIVE_UNSTABLE_USE_RUNTIME_SCHEDULER_ALWAYS", (findProperty("reactNative.unstable_useRuntimeSchedulerAlways") ?: true).toString()) } diff --git a/ios/Internxt/Info.plist b/ios/Internxt/Info.plist index f7fcf9ce6..a7983506c 100644 --- a/ios/Internxt/Info.plist +++ b/ios/Internxt/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.7.0 + 1.7.1 CFBundleSignature ???? CFBundleURLTypes diff --git a/src/network/NetworkFacade.ts b/src/network/NetworkFacade.ts index 0a5170cd0..fe1837f28 100644 --- a/src/network/NetworkFacade.ts +++ b/src/network/NetworkFacade.ts @@ -22,8 +22,6 @@ import { Abortable } from '../types'; import { EncryptedFileDownloadedParams } from './download'; import { getAuthFromCredentials, NetworkCredentials } from './requests'; -const HUNDRED_MB = 100 * 1024 * 1024; - interface UploadMultipartOptions { partSize: number; uploadingCallback?: (progress: number) => void; @@ -523,6 +521,8 @@ export class NetworkFacade { } let isAborting = false; + const CONCURRENT_DOWNLOADS = Platform.OS === 'android' ? 3 : 6; + const limit = pLimit(CONCURRENT_DOWNLOADS); const downloadJobs: { [key: number]: { @@ -533,7 +533,6 @@ export class NetworkFacade { } = {}; let expectedFileHash: string; - const CONCURRENT_DOWNLOADS = 3; const decryptFileFromFs: DecryptFileFromFsFunction = Platform.OS === 'android' ? androidDecryptFileFromFs : iosDecryptFileFromFs; @@ -623,12 +622,14 @@ export class NetworkFacade { } }, progress: (res) => { - downloadJobs[chunkIndex].bytesWritten = res.bytesWritten; + if (Platform.OS === 'android') { + downloadJobs[chunkIndex].bytesWritten = res.bytesWritten; - const currentTotalBytes = Object.values(downloadJobs).reduce((acc, job) => { - return acc + job.bytesWritten; - }, 0); - params.downloadProgressCallback(currentTotalBytes / fileSize, currentTotalBytes, fileSize); + const currentTotalBytes = Object.values(downloadJobs).reduce((acc, job) => { + return acc + job.bytesWritten; + }, 0); + params.downloadProgressCallback(currentTotalBytes / fileSize, currentTotalBytes, fileSize); + } }, }); @@ -638,6 +639,13 @@ export class NetworkFacade { try { await downloadJob.promise; + + if (Platform.OS === 'ios') { + downloadJobs[chunkIndex].bytesWritten = range.end - range.start; + const currentTotalBytes = Object.values(downloadJobs).reduce((acc, job) => acc + job.bytesWritten, 0); + const normalizedProgress = Math.min(currentTotalBytes, fileSize); + params.downloadProgressCallback(normalizedProgress / fileSize, normalizedProgress, fileSize); + } return chunkFileURI; } catch (error) { await fileSystemService.deleteFile([chunkFileURI]); @@ -653,6 +661,8 @@ export class NetworkFacade { this.cryptoLib, Buffer.from, async (downloadables) => { + const MEGA_BYTE = 1 * 1024 * 1024; + const { isCached, path } = await drive.cache.isCached(encryptedFileName); if (isCached) { @@ -660,7 +670,9 @@ export class NetworkFacade { encryptedFileURI = path; } else { await cleanupExistingChunks(encryptedFileName); - const downloadChunkSize = HUNDRED_MB; + + // temporary workaround to display the progress of the download more continuously in iOS + const downloadChunkSize = Platform.OS === 'android' ? 100 * MEGA_BYTE : 25 * MEGA_BYTE; const ranges: { start: number; end: number }[] = []; for (let start = 0; start < fileSize; start += downloadChunkSize) { @@ -670,30 +682,18 @@ export class NetworkFacade { params.downloadProgressCallback(0, 0, 0); - for (let i = 0; i < ranges.length; i += CONCURRENT_DOWNLOADS) { - if (isAborting || params.signal?.aborted) { - throw new Error('Download aborted'); - } - - const currentBatch = ranges.slice(i, i + CONCURRENT_DOWNLOADS); - const batchPromises = currentBatch.map((range, index) => - downloadChunk(downloadables[0].url, range, i + index), + try { + const downloadTasks = ranges.map((range, index) => + limit(() => downloadChunk(downloadables[0].url, range, index)), ); - try { - await Promise.all(batchPromises); - } catch (error) { - await cleanupChunks(); - if (isAborting) { - throw new Error('Download aborted'); - } - throw error; - } - - if (Platform.OS === 'ios') { - const completedBytes = Math.min((i + CONCURRENT_DOWNLOADS) * downloadChunkSize, fileSize); - params.downloadProgressCallback(completedBytes / fileSize, completedBytes, fileSize); + await Promise.all(downloadTasks); + } catch (error) { + await cleanupChunks(); + if (isAborting) { + throw new Error('Download aborted'); } + throw error; } expectedFileHash = downloadables[0].hash;