Page MenuHomePhorge

D9157.1765229451.diff
No OneTemporary

Size
6 KB
Referenced Files
None
Subscribers
None

D9157.1765229451.diff

diff --git a/lib/actions/upload-actions.js b/lib/actions/upload-actions.js
--- a/lib/actions/upload-actions.js
+++ b/lib/actions/upload-actions.js
@@ -1,18 +1,31 @@
// @flow
+import uuid from 'uuid';
+
+import blobService from '../facts/blob-service.js';
import type { Shape } from '../types/core.js';
import type {
UploadMediaMetadataRequest,
UploadMultimediaResult,
Dimensions,
} from '../types/media-types';
+import { toBase64URL } from '../utils/base64.js';
+import {
+ blobServiceUploadHandler,
+ type BlobServiceUploadHandler,
+} from '../utils/blob-service-upload.js';
+import { makeBlobServiceEndpointURL } from '../utils/blob-service.js';
import type { CallServerEndpoint } from '../utils/call-server-endpoint.js';
-import type { UploadBlob } from '../utils/upload-blob.js';
+import { getMessageForException } from '../utils/errors.js';
+import { handleHTTPResponseError } from '../utils/services-utils.js';
+import { type UploadBlob } from '../utils/upload-blob.js';
export type MultimediaUploadCallbacks = Shape<{
onProgress: (percent: number) => void,
abortHandler: (abort: () => void) => void,
uploadBlob: UploadBlob,
+ blobServiceUploadHandler: BlobServiceUploadHandler,
+ timeout: ?number,
}>;
export type MultimediaUploadExtras = Shape<{
...Dimensions,
@@ -102,8 +115,119 @@
await callServerEndpoint('delete_upload', { id });
};
+export type BlobServiceUploadFile =
+ | { +type: 'file', +file: File }
+ | {
+ +type: 'uri',
+ +uri: string,
+ +filename: string,
+ +mimeType: string,
+ };
+
+export type BlobServiceUploadInput = {
+ +blobInput: BlobServiceUploadFile,
+ +blobHash: string,
+ +encryptionKey: string,
+ +dimensions: ?Dimensions,
+ +thumbHash?: ?string,
+ +loop?: boolean,
+};
+
+export type BlobServiceUploadAction = (args: {
+ +input: BlobServiceUploadInput,
+ +callbacks?: MultimediaUploadCallbacks,
+}) => Promise<{ ...UploadMultimediaResult, blobHolder: ?string }>;
+
+const blobServiceUpload =
+ (callServerEndpoint: CallServerEndpoint): BlobServiceUploadAction =>
+ async args => {
+ const { input, callbacks } = args;
+ const { encryptionKey, loop, dimensions, thumbHash, blobInput } = input;
+ const blobHolder = uuid.v4();
+ const blobHash = toBase64URL(input.blobHash);
+
+ // 1. Assign new holder for blob with given blobHash
+ let blobAlreadyExists: boolean;
+ try {
+ const assignHolderEndpoint = blobService.httpEndpoints.ASSIGN_HOLDER;
+ const assignHolderResponse = await fetch(
+ makeBlobServiceEndpointURL(assignHolderEndpoint),
+ {
+ method: assignHolderEndpoint.method,
+ body: JSON.stringify({
+ holder: blobHolder,
+ blob_hash: blobHash,
+ }),
+ headers: {
+ 'content-type': 'application/json',
+ },
+ },
+ );
+ handleHTTPResponseError(assignHolderResponse);
+ const { data_exists: dataExistsResponse } =
+ await assignHolderResponse.json();
+ blobAlreadyExists = dataExistsResponse;
+ } catch (e) {
+ throw new Error(
+ `Failed to assign holder: ${
+ getMessageForException(e) ?? 'unknown error'
+ }`,
+ );
+ }
+
+ // 2. Upload blob contents if blob doesn't exist
+ if (!blobAlreadyExists) {
+ const uploadEndpoint = blobService.httpEndpoints.UPLOAD_BLOB;
+ let blobServiceUploadCallback = blobServiceUploadHandler;
+ if (callbacks && callbacks.blobServiceUploadHandler) {
+ blobServiceUploadCallback = callbacks.blobServiceUploadHandler;
+ }
+ try {
+ await blobServiceUploadCallback(
+ makeBlobServiceEndpointURL(uploadEndpoint),
+ uploadEndpoint.method,
+ {
+ blobHash,
+ blobInput,
+ },
+ { ...callbacks },
+ );
+ } catch (e) {
+ throw new Error(
+ `Failed to upload blob: ${
+ getMessageForException(e) ?? 'unknown error'
+ }`,
+ );
+ }
+ }
+
+ // 3. Upload metadata to keyserver
+ const response = await callServerEndpoint('upload_media_metadata', {
+ blobHash,
+ blobHolder,
+ encryptionKey,
+ filename:
+ blobInput.type === 'file' ? blobInput.file.name : blobInput.filename,
+ mimeType:
+ blobInput.type === 'file' ? blobInput.file.type : blobInput.mimeType,
+ loop,
+ thumbHash,
+ ...dimensions,
+ });
+
+ return {
+ id: response.id,
+ uri: response.uri,
+ mediaType: response.mediaType,
+ dimensions: response.dimensions,
+ loop: response.loop,
+ blobHolder,
+ };
+ };
+
export {
uploadMultimedia,
+ blobServiceUpload,
uploadMediaMetadata,
updateMultimediaMessageMediaActionType,
deleteUpload,
diff --git a/lib/utils/blob-service-upload.js b/lib/utils/blob-service-upload.js
new file mode 100644
--- /dev/null
+++ b/lib/utils/blob-service-upload.js
@@ -0,0 +1,84 @@
+// @flow
+
+import invariant from 'invariant';
+import _throttle from 'lodash/throttle.js';
+
+import type {
+ MultimediaUploadCallbacks,
+ BlobServiceUploadFile,
+} from '../actions/upload-actions.js';
+
+function blobServiceUploadHandler(
+ url: string,
+ method: string,
+ input: {
+ blobHash: string,
+ blobInput: BlobServiceUploadFile,
+ },
+ options?: ?MultimediaUploadCallbacks,
+): Promise<void> {
+ if (input.blobInput.type !== 'file') {
+ throw new Error('Use file to upload blob to blob service!');
+ }
+ const formData = new FormData();
+ formData.append('blob_hash', input.blobHash);
+ invariant(input.blobInput.file, 'file should be defined');
+ formData.append('blob_data', input.blobInput.file);
+
+ const xhr = new XMLHttpRequest();
+ xhr.open(method, url);
+
+ const { timeout, onProgress, abortHandler } = options ?? {};
+
+ if (timeout) {
+ xhr.timeout = timeout;
+ }
+
+ if (onProgress) {
+ xhr.upload.onprogress = _throttle(
+ ({ loaded, total }) => onProgress(loaded / total),
+ 50,
+ );
+ }
+
+ let failed = false;
+ const responsePromise = new Promise((resolve, reject) => {
+ xhr.onload = () => {
+ if (failed) {
+ return;
+ }
+ resolve();
+ };
+ xhr.onabort = () => {
+ failed = true;
+ reject(new Error('request aborted'));
+ };
+ xhr.onerror = event => {
+ failed = true;
+ reject(event);
+ };
+ if (timeout) {
+ xhr.ontimeout = event => {
+ failed = true;
+ reject(event);
+ };
+ }
+ if (abortHandler) {
+ abortHandler(() => {
+ failed = true;
+ reject(new Error('request aborted'));
+ xhr.abort();
+ });
+ }
+ });
+
+ if (!failed) {
+ xhr.send(formData);
+ }
+
+ return responsePromise;
+}
+
+export type BlobServiceUploadHandler = typeof blobServiceUploadHandler;
+
+export { blobServiceUploadHandler };

File Metadata

Mime Type
text/plain
Expires
Mon, Dec 8, 9:30 PM (15 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5850883
Default Alt Text
D9157.1765229451.diff (6 KB)

Event Timeline