diff --git a/web/input/input-state-container.react.js b/web/input/input-state-container.react.js --- a/web/input/input-state-container.react.js +++ b/web/input/input-state-container.react.js @@ -87,7 +87,11 @@ useServerCall, useDispatchActionPromise, } from 'lib/utils/action-utils.js'; -import { makeBlobServiceEndpointURL } from 'lib/utils/blob-service.js'; +import { + makeBlobServiceEndpointURL, + holderFromBlobServiceURI, + isBlobServiceURI, +} from 'lib/utils/blob-service.js'; import type { CallServerEndpointOptions } from 'lib/utils/call-server-endpoint.js'; import { getConfig } from 'lib/utils/config.js'; import { getMessageForException, cloneError } from 'lib/utils/errors.js'; @@ -178,6 +182,9 @@ }; replyCallbacks: Array<(message: string) => void> = []; pendingThreadCreations = new Map>(); + // TODO: flip the switch + // Note that this enables Blob service for encrypted media only + useBlobServiceUploads = true; // When the user sends a multimedia message that triggers the creation of a // sidebar, the sidebar gets created right away, but the message needs to wait @@ -783,6 +790,7 @@ uri: encryptionResult ? encryptionResult.uri : uri, loop: false, uriIsReal: false, + blobHash: encryptionResult ? encryptionResult.sha256Hash : null, encryptionKey: encryptionResult ? encryptionResult.encryptionKey : null, @@ -838,20 +846,43 @@ let uploadResult, uploadExceptionMessage; const uploadStart = Date.now(); try { - let uploadExtras = { ...upload.dimensions, loop: false }; - if (encryptionKey) { - uploadExtras = { ...uploadExtras, encryptionKey }; + const callbacks = { + onProgress: (percent: number) => + this.setProgress(threadID, localID, percent), + abortHandler: (abort: () => void) => + this.handleAbortCallback(threadID, localID, abort), + }; + if ( + this.useBlobServiceUploads && + (upload.mediaType === 'encrypted_photo' || + upload.mediaType === 'encrypted_video') + ) { + const { blobHash, dimensions } = upload; + invariant( + encryptionKey && blobHash && dimensions, + 'incomplete encrypted upload', + ); + uploadResult = await this.blobServiceUpload( + { + file: upload.file, + blobHash, + encryptionKey, + dimensions, + loop: false, + }, + { ...callbacks }, + ); + } else { + let uploadExtras = { ...upload.dimensions, loop: false }; + if (encryptionKey) { + uploadExtras = { ...uploadExtras, encryptionKey }; + } + uploadResult = await this.props.uploadMultimedia( + upload.file, + uploadExtras, + callbacks, + ); } - uploadResult = await this.props.uploadMultimedia( - upload.file, - uploadExtras, - { - onProgress: (percent: number) => - this.setProgress(threadID, localID, percent), - abortHandler: (abort: () => void) => - this.handleAbortCallback(threadID, localID, abort), - }, - ); } catch (e) { uploadExceptionMessage = getMessageForException(e); this.handleUploadFailure(threadID, localID); @@ -1223,6 +1254,13 @@ } if (pendingUpload.serverID) { this.props.deleteUpload(pendingUpload.serverID); + if (isBlobServiceURI(pendingUpload.uri)) { + const endpoint = blobService.httpEndpoints.DELETE_BLOB; + const holder = holderFromBlobServiceURI(pendingUpload.uri); + fetch(makeBlobServiceEndpointURL(endpoint, { holder }), { + method: endpoint.method, + }); + } } const newPendingUploads = _omit([localUploadID])(currentPendingUploads); return { diff --git a/web/input/input-state.js b/web/input/input-state.js --- a/web/input/input-state.js +++ b/web/input/input-state.js @@ -23,6 +23,7 @@ mediaType: MediaType | EncryptedMediaType, dimensions: ?Dimensions, uri: string, + blobHash: ?string, encryptionKey: ?string, loop: boolean, // URLs created with createObjectURL aren't considered "real". The distinction