Page MenuHomePhabricator

D13501.id44638.diff
No OneTemporary

D13501.id44638.diff

diff --git a/lib/hooks/input-state-container-hooks.js b/lib/hooks/input-state-container-hooks.js
--- a/lib/hooks/input-state-container-hooks.js
+++ b/lib/hooks/input-state-container-hooks.js
@@ -9,8 +9,18 @@
useSendMultimediaMessage,
useSendTextMessage,
} from '../actions/message-actions.js';
+import type { MediaMetadataUploadAction } from '../actions/upload-actions.js';
+import {
+ useMediaMetadataUpload,
+ updateMultimediaMessageMediaActionType,
+} from '../actions/upload-actions.js';
+import {
+ encryptedMediaBlobURI,
+ encryptedVideoThumbnailBlobURI,
+} from '../media/media-utils.js';
import { dmOperationSpecificationTypes } from '../shared/dm-ops/dm-op-utils.js';
import { useSendComposableDMOperation } from '../shared/dm-ops/process-dm-ops.js';
+import type { Media } from '../types/media-types.js';
import type {
RawMultimediaMessageInfo,
SendMessagePayload,
@@ -18,11 +28,16 @@
import { getMediaMessageServerDBContentsFromMedia } from '../types/messages/media.js';
import type { RawTextMessageInfo } from '../types/messages/text.js';
import type { ThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js';
+import type { Dispatch } from '../types/redux-types.js';
import {
thickThreadTypes,
threadTypeIsThick,
} from '../types/thread-types-enum.js';
-import { useSelector } from '../utils/redux-utils.js';
+import {
+ blobHashFromBlobServiceURI,
+ isBlobServiceURI,
+} from '../utils/blob-service.js';
+import { useSelector, useDispatch } from '../utils/redux-utils.js';
function useInputStateContainerSendTextMessage(): (
messageInfo: RawTextMessageInfo,
@@ -116,6 +131,9 @@
const sendComposableDMOperation = useSendComposableDMOperation();
const threadInfos = useSelector(state => state.threadStore.threadInfos);
+ const uploadMediaMetadata = useMediaMetadataUpload();
+ const dispatch = useDispatch();
+
return React.useCallback(
async (
messageInfo: RawMultimediaMessageInfo,
@@ -132,8 +150,13 @@
const isThickThread = threadInfo && threadTypeIsThick(threadInfo.type);
if (!isThickThread && isLegacy) {
+ const { messageMedia } = await migrateMessageMediaToKeyserver(
+ messageInfo,
+ uploadMediaMetadata,
+ dispatch,
+ );
const mediaIDs = [];
- for (const { id } of messageInfo.media) {
+ for (const { id } of messageMedia) {
mediaIDs.push(id);
}
const result = await legacySendMultimediaMessage({
@@ -151,9 +174,13 @@
}
if (!isThickThread && !isLegacy) {
- const mediaMessageContents = getMediaMessageServerDBContentsFromMedia(
- messageInfo.media,
+ const { messageMedia } = await migrateMessageMediaToKeyserver(
+ messageInfo,
+ uploadMediaMetadata,
+ dispatch,
);
+ const mediaMessageContents =
+ getMediaMessageServerDBContentsFromMedia(messageMedia);
const result = await sendMultimediaMessage({
threadID: messageInfo.threadID,
localID,
@@ -206,14 +233,126 @@
};
},
[
+ dispatch,
legacySendMultimediaMessage,
sendComposableDMOperation,
sendMultimediaMessage,
threadInfos,
+ uploadMediaMetadata,
],
);
}
+function mediaIDIsKeyserverID(mediaID: string): boolean {
+ return mediaID.indexOf('|') !== -1;
+}
+
+type MediaIDUpdates = { +[string]: { id: string, thumbnailID?: string } };
+
+async function migrateMessageMediaToKeyserver(
+ messageInfo: RawMultimediaMessageInfo,
+ uploadMediaMetadata: MediaMetadataUploadAction,
+ dispatch: Dispatch,
+): Promise<{
+ +messageMedia: $ReadOnlyArray<Media>,
+ +mediaIDUpdates: MediaIDUpdates,
+}> {
+ const newMedia = [];
+ let mediaIDUpdates: MediaIDUpdates = {};
+ for (const media of messageInfo.media) {
+ if (
+ mediaIDIsKeyserverID(media.id) ||
+ (media.type !== 'encrypted_photo' && media.type !== 'encrypted_video')
+ ) {
+ newMedia.push(media);
+ continue;
+ }
+
+ const mediaURI = encryptedMediaBlobURI(media);
+ invariant(
+ isBlobServiceURI(mediaURI),
+ 'non-blob media had non-keyserver ID',
+ );
+
+ // This is only to determine server-side if media is photo or video.
+ // We can mock mime type to represent one of them.
+ const mimeType =
+ media.type === 'encrypted_photo' ? 'image/jpeg' : 'video/mp4';
+ const blobHash = blobHashFromBlobServiceURI(mediaURI);
+ const { id } = await uploadMediaMetadata({
+ keyserverOrThreadID: messageInfo.threadID,
+ uploadInput: {
+ blobHash,
+ mimeType,
+ dimensions: media.dimensions,
+ thumbHash: media.thumbHash,
+ encryptionKey: media.encryptionKey,
+ loop: media.loop,
+ },
+ });
+
+ if (media.type !== 'encrypted_video') {
+ mediaIDUpdates = {
+ ...mediaIDUpdates,
+ [media.id]: { id },
+ };
+ newMedia.push({
+ ...media,
+ id,
+ });
+ continue;
+ }
+
+ const thumbnailMediaURI = encryptedVideoThumbnailBlobURI(media);
+ invariant(
+ isBlobServiceURI(thumbnailMediaURI),
+ 'non-blob media had non-keyserver thumbnail ID',
+ );
+
+ const thumbnailBlobHash = blobHashFromBlobServiceURI(thumbnailMediaURI);
+ const { id: thumbnailID } = await uploadMediaMetadata({
+ keyserverOrThreadID: messageInfo.threadID,
+ uploadInput: {
+ blobHash: thumbnailBlobHash,
+ mimeType: 'image/jpeg',
+ dimensions: media.dimensions,
+ thumbHash: media.thumbnailThumbHash,
+ encryptionKey: media.thumbnailEncryptionKey,
+ loop: false,
+ },
+ });
+
+ mediaIDUpdates = {
+ ...mediaIDUpdates,
+ [media.id]: { id, thumbnailID },
+ };
+ newMedia.push({
+ ...media,
+ id,
+ thumbnailID,
+ });
+ }
+
+ for (const [prevID, { id, thumbnailID }] of Object.entries(mediaIDUpdates)) {
+ dispatch({
+ type: updateMultimediaMessageMediaActionType,
+ payload: {
+ messageID: messageInfo.localID,
+ currentMediaID: prevID,
+ mediaUpdate: {
+ id,
+ ...(thumbnailID ? { thumbnailID } : {}),
+ },
+ },
+ });
+ }
+
+ return {
+ messageMedia: newMedia,
+ mediaIDUpdates,
+ };
+}
+
export {
useInputStateContainerSendTextMessage,
useInputStateContainerSendMultimediaMessage,

File Metadata

Mime Type
text/plain
Expires
Mon, Dec 23, 4:19 AM (18 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2693537
Default Alt Text
D13501.id44638.diff (6 KB)

Event Timeline