diff --git a/lib/types/media-types.js b/lib/types/media-types.js --- a/lib/types/media-types.js +++ b/lib/types/media-types.js @@ -179,7 +179,7 @@ +success: boolean, +exceptionMessage: ?string, +time: number, // ms - +path: string, + +uri: string, }; export type MakeDirectoryMediaMissionStep = { diff --git a/native/input/input-state-container.react.js b/native/input/input-state-container.react.js --- a/native/input/input-state-container.react.js +++ b/native/input/input-state-container.react.js @@ -758,7 +758,7 @@ let userTime; let errorMessage; let reportPromise: ?Promise<$ReadOnlyArray>; - const filesToDispose = []; + const fileURIsToDispose = []; const onUploadFinished = async (result: MediaMissionResult) => { if (!this.props.mediaReportsEnabled) { @@ -805,8 +805,8 @@ onUploadFailed(message); return await onUploadFinished(processResult); } - if (processResult.shouldDisposePath) { - filesToDispose.push(processResult.shouldDisposePath); + if (processResult.shouldDisposeURI) { + fileURIsToDispose.push(processResult.shouldDisposeURI); } processedMedia = processResult; } catch (e) { @@ -828,8 +828,8 @@ onUploadFailed(encryptionResult.reason); return await onUploadFinished(encryptionResult); } - if (encryptionResult.shouldDisposePath) { - filesToDispose.push(encryptionResult.shouldDisposePath); + if (encryptionResult.shouldDisposeURI) { + fileURIsToDispose.push(encryptionResult.shouldDisposeURI); } processedMedia = encryptionResult; } catch (e) { @@ -1046,15 +1046,15 @@ const cleanupPromises = []; - if (filesToDispose.length > 0) { - // If processMedia needed to do any transcoding before upload, we dispose - // of the resultant temporary file here. Since the transcoded temporary - // file is only used for upload, we can dispose of it after processMedia - // (reportPromise) and the upload are complete - filesToDispose.forEach(shouldDisposePath => { + if (fileURIsToDispose.length > 0) { + // If processMedia and/or encryptMedia needed to do any transcoding before + // upload, we dispose of the resultant temporary files here. Since the + // transcoded temporary files are only prior to upload, we can dispose of + // them after the upload is complete + fileURIsToDispose.forEach(shouldDisposeURI => { cleanupPromises.push( (async () => { - const disposeStep = await disposeTempFile(shouldDisposePath); + const disposeStep = await disposeTempFile(shouldDisposeURI); steps.push(disposeStep); })(), ); @@ -1067,13 +1067,10 @@ const { uploadThumbnailURI } = processedMedia; cleanupPromises.push( (async () => { - const { steps: clearSteps, result: thumbnailPath } = + const { steps: clearSteps } = await this.waitForCaptureURIUnload(uploadThumbnailURI); steps.push(...clearSteps); - if (!thumbnailPath) { - return; - } - const disposeStep = await disposeTempFile(thumbnailPath); + const disposeStep = await disposeTempFile(uploadThumbnailURI); steps.push(disposeStep); })(), ); @@ -1090,13 +1087,10 @@ const captureURI = selection.uri; cleanupPromises.push( (async () => { - const { steps: clearSteps, result: capturePath } = + const { steps: clearSteps } = await this.waitForCaptureURIUnload(captureURI); steps.push(...clearSteps); - if (!capturePath) { - return; - } - const disposeStep = await disposeTempFile(capturePath); + const disposeStep = await disposeTempFile(captureURI); steps.push(disposeStep); })(), ); @@ -1617,26 +1611,10 @@ waitForCaptureURIUnload(uri: string): Promise<{ +steps: $ReadOnlyArray, - +result: ?string, }> { const start = Date.now(); - const path = pathFromURI(uri); - if (!path) { - return Promise.resolve({ - result: null, - steps: [ - { - step: 'wait_for_capture_uri_unload', - success: false, - time: Date.now() - start, - uri, - }, - ], - }); - } const getResult = () => ({ - result: path, steps: [ { step: 'wait_for_capture_uri_unload', diff --git a/native/media/encryption-utils.js b/native/media/encryption-utils.js --- a/native/media/encryption-utils.js +++ b/native/media/encryption-utils.js @@ -216,7 +216,7 @@ blobHash: encryptionResult.sha256Hash, thumbHash: thumbHashResult?.base64, encryptionKey: encryptionResult.encryptionKey, - shouldDisposePath: pathFromURI(encryptionResult.uri), + shouldDisposeURI: encryptionResult.uri, }, }; } @@ -249,7 +249,7 @@ uploadThumbnailURI: thumbnailEncryptionResult.uri, thumbnailBlobHash: thumbnailEncryptionResult.sha256Hash, thumbnailEncryptionKey: thumbnailEncryptionResult.encryptionKey, - shouldDisposePath: pathFromURI(encryptionResult.uri), + shouldDisposeURI: encryptionResult.uri, }, }; } diff --git a/native/media/file-utils.js b/native/media/file-utils.js --- a/native/media/file-utils.js +++ b/native/media/file-utils.js @@ -330,13 +330,13 @@ } async function disposeTempFile( - path: string, + uri: string, ): Promise { let success = false, exceptionMessage; const start = Date.now(); try { - await filesystem.unlink(path); + await ExpoFileSystem.deleteAsync(uri); success = true; } catch (e) { exceptionMessage = getMessageForException(e); @@ -346,7 +346,7 @@ success, exceptionMessage, time: Date.now() - start, - path, + uri, }; } diff --git a/native/media/image-utils.js b/native/media/image-utils.js --- a/native/media/image-utils.js +++ b/native/media/image-utils.js @@ -26,7 +26,7 @@ +mime: string, +dimensions: Dimensions, +thumbHash: ?string, - +shouldDisposePath: ?string, + +shouldDisposeURI: ?string, }; async function processImage(input: ProcessImageInfo): Promise<{ steps: $ReadOnlyArray, @@ -54,7 +54,7 @@ dimensions, mime, thumbHash, - shouldDisposePath: null, + shouldDisposeURI: null, }, }; } @@ -78,7 +78,7 @@ let success = false, exceptionMessage, - shouldDisposePath; + shouldDisposeURI; const start = Date.now(); try { const result = await ImageManipulator.manipulateAsync( @@ -90,7 +90,7 @@ uri = result.uri; mime = targetMIME; dimensions = { width: result.width, height: result.height }; - shouldDisposePath = result.uri; + shouldDisposeURI = result.uri; } catch (e) { exceptionMessage = getMessageForException(e); } @@ -128,7 +128,7 @@ dimensions, mime, thumbHash, - shouldDisposePath, + shouldDisposeURI, }, }; } diff --git a/native/media/media-utils.js b/native/media/media-utils.js --- a/native/media/media-utils.js +++ b/native/media/media-utils.js @@ -28,7 +28,7 @@ type SharedMediaResult = { +success: true, +uploadURI: string, - +shouldDisposePath: ?string, + +shouldDisposeURI: ?string, +filename: string, +mime: string, +dimensions: Dimensions, @@ -95,7 +95,7 @@ loop = false, resultReturned = false, thumbHash = null, - shouldDisposePath = null; + shouldDisposeURI = null; const returnResult = (failure?: MediaMissionFailure) => { invariant( !resultReturned, @@ -117,7 +117,7 @@ success: true, uploadURI, uploadThumbnailURI, - shouldDisposePath, + shouldDisposeURI, filename, mime, mediaType, @@ -129,7 +129,7 @@ sendResult({ success: true, uploadURI, - shouldDisposePath, + shouldDisposeURI, filename, mime, mediaType, @@ -220,7 +220,7 @@ dimensions, loop, thumbHash, - shouldDisposePath, + shouldDisposeURI, } = videoResult); } else if (mediaType === 'photo') { const { steps: imageSteps, result: imageResult } = await processImage({ @@ -245,7 +245,7 @@ mime, dimensions, thumbHash, - shouldDisposePath, + shouldDisposeURI, } = imageResult); } else { invariant(false, `unknown mediaType ${mediaType}`); diff --git a/native/media/save-media.js b/native/media/save-media.js --- a/native/media/save-media.js +++ b/native/media/save-media.js @@ -240,7 +240,7 @@ ); let uri = inputURI; - let tempFile, mime; + let tempFileURI, mime; if (uri.startsWith('http') || isBlobServiceURI(uri)) { promises.push( (async () => { @@ -255,16 +255,24 @@ success = false; sendResult(tempSaveResult); } else { - tempFile = tempSaveResult.path; - uri = `file://${tempFile}`; + ({ uri } = tempSaveResult); + tempFileURI = uri; mime = tempSaveResult.mime; } })(), ); } + const disposeTempSavedFile = async () => { + if (tempFileURI) { + const disposeStep = await disposeTempFile(tempFileURI); + steps.push(disposeStep); + } + }; + await Promise.all(promises); if (!success) { + await disposeTempSavedFile(); return steps; } @@ -276,12 +284,14 @@ steps.push(...copySteps); if (!copyResult.success) { sendResult(copyResult); + await disposeTempSavedFile(); return steps; } sendResult({ success: true }); const postResultPromises = []; + postResultPromises.push(disposeTempSavedFile()); postResultPromises.push( (async () => { const scanFileStep = await androidScanFile(copyResult.path); @@ -289,15 +299,6 @@ })(), ); - if (tempFile) { - postResultPromises.push( - (async (file: string) => { - const disposeStep = await disposeTempFile(file); - steps.push(disposeStep); - })(tempFile), - ); - } - await Promise.all(postResultPromises); return steps; } @@ -316,11 +317,11 @@ ); steps.push(...saveMediaToDiskIOSResult.steps); - const { tempFilePath } = saveMediaToDiskIOSResult; + const { tempFileURI } = saveMediaToDiskIOSResult; if (!saveMediaToDiskIOSResult.success) { - if (tempFilePath) { - const disposeStep = await disposeTempFile(tempFilePath); + if (tempFileURI) { + const disposeStep = await disposeTempFile(tempFileURI); steps.push(disposeStep); } sendResult(saveMediaToDiskIOSResult.result); @@ -352,8 +353,8 @@ sendResult({ success: false, reason: 'save_to_library_failed', uri }); } - if (tempFilePath) { - const disposeStep = await disposeTempFile(tempFilePath); + if (tempFileURI) { + const disposeStep = await disposeTempFile(tempFileURI); steps.push(disposeStep); } return steps; @@ -363,13 +364,13 @@ | { +success: true, +uri: string, - +tempFilePath: ?string, + +tempFileURI: ?string, +steps: $ReadOnlyArray, } | { +success: false, +result: MediaMissionResult, - +tempFilePath?: ?string, + +tempFileURI?: ?string, +steps: $ReadOnlyArray, }; async function saveMediaToDiskIOS( @@ -379,7 +380,7 @@ const steps: Array = []; let uri = inputURI; - let tempFilePath; + let tempFileURI; if (uri.startsWith('http') || isBlobServiceURI(uri)) { const { result: tempSaveResult, steps: tempSaveSteps } = await saveRemoteMediaToDisk(uri, encryptionKey, temporaryDirectoryPath); @@ -391,8 +392,8 @@ steps, }; } - tempFilePath = tempSaveResult.path; - uri = `file://${tempFilePath}`; + ({ uri } = tempSaveResult); + tempFileURI = uri; } else if (!uri.startsWith('file://')) { const mediaNativeID = getMediaLibraryIdentifier(uri); if (mediaNativeID) { @@ -410,7 +411,7 @@ return { success: false, result: { success: false, reason: 'resolve_failed', uri }, - tempFilePath, + tempFileURI, steps, }; } @@ -418,23 +419,22 @@ return { success: true, uri, - tempFilePath, + tempFileURI, steps, }; } -type IntermediateSaveResult = { +type SaveRemoteMediaToDiskResult = { +result: - | { +success: true, +path: string, +mime: string } + | { +success: true, +uri: string, +mime: string } | MediaMissionFailure, +steps: $ReadOnlyArray, }; - async function saveRemoteMediaToDisk( inputURI: string, encryptionKey?: ?string, directory: string, // should end with a / -): Promise { +): Promise { const steps: Array = []; if (encryptionKey) { const authMetadata = await commCoreModule.getCommServicesAuthMetadata(); @@ -449,13 +449,6 @@ return { result: decryptionResult, steps }; } const { uri } = decryptionResult; - const path = pathFromURI(uri); - if (!path) { - return { - result: { success: false, reason: 'resolve_failed', uri }, - steps, - }; - } const { steps: fetchFileInfoSteps, result: fetchFileInfoResult } = await fetchFileInfo(uri, undefined, { @@ -478,7 +471,7 @@ } return { - result: { success: true, path, mime }, + result: { success: true, uri, mime }, steps, }; } @@ -521,14 +514,20 @@ if (!success) { return { result: { success: false, reason: 'write_file_failed' }, steps }; } - return { result: { success: true, path: tempPath, mime }, steps }; + return { result: { success: true, uri: `file://${tempPath}`, mime }, steps }; } +type CopyToSortedDirectoryResult = { + +result: + | { +success: true, +path: string, +mime: string } + | MediaMissionFailure, + +steps: $ReadOnlyArray, +}; async function copyToSortedDirectory( localURI: string, directory: string, // should end with a / inputMIME: ?string, -): Promise { +): Promise { const steps: Array = []; const path = pathFromURI(localURI); @@ -617,9 +616,9 @@ ); if (!saveMediaToDiskIOSResult.success) { - const { tempFilePath } = saveMediaToDiskIOSResult; - if (tempFilePath) { - await disposeTempFile(tempFilePath); + const { tempFileURI } = saveMediaToDiskIOSResult; + if (tempFileURI) { + await disposeTempFile(tempFileURI); } return { success: false }; } diff --git a/native/media/video-utils.js b/native/media/video-utils.js --- a/native/media/video-utils.js +++ b/native/media/video-utils.js @@ -53,7 +53,7 @@ +dimensions: Dimensions, +loop: boolean, +thumbHash: ?string, - +shouldDisposePath: ?string, + +shouldDisposeURI: ?string, }; async function processVideo( input: ProcessVideoInfo, @@ -114,7 +114,7 @@ mime: 'video/mp4', dimensions: input.dimensions, loop: false, - shouldDisposePath: null, + shouldDisposeURI: null, }, }; } @@ -182,7 +182,7 @@ mime: 'video/mp4', dimensions, loop, - shouldDisposePath: uri, + shouldDisposeURI: uri, }, }; }