Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F32244035
D9157.1765229451.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
D9157.1765229451.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D9157: [lib] Add blobServiceUpload upload action
Attached
Detach File
Event Timeline
Log In to Comment