Changeset View
Changeset View
Standalone View
Standalone View
web/input/input-state-container.react.js
Show First 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | |||||
import { getMessageForException, cloneError } from 'lib/utils/errors.js'; | import { getMessageForException, cloneError } from 'lib/utils/errors.js'; | ||||
import { | import { | ||||
type PendingMultimediaUpload, | type PendingMultimediaUpload, | ||||
type TypeaheadState, | type TypeaheadState, | ||||
InputStateContext, | InputStateContext, | ||||
} from './input-state.js'; | } from './input-state.js'; | ||||
import { encryptFile } from '../media/encryption-utils.js'; | import { encryptFile } from '../media/encryption-utils.js'; | ||||
import { generateThumbHash } from '../media/image-utils.js'; | |||||
import { validateFile, preloadImage } from '../media/media-utils.js'; | import { validateFile, preloadImage } from '../media/media-utils.js'; | ||||
import InvalidUploadModal from '../modals/chat/invalid-upload.react.js'; | import InvalidUploadModal from '../modals/chat/invalid-upload.react.js'; | ||||
import { updateNavInfoActionType } from '../redux/action-types.js'; | import { updateNavInfoActionType } from '../redux/action-types.js'; | ||||
import { useSelector } from '../redux/redux-utils.js'; | import { useSelector } from '../redux/redux-utils.js'; | ||||
import { nonThreadCalendarQuery } from '../selectors/nav-selectors.js'; | import { nonThreadCalendarQuery } from '../selectors/nav-selectors.js'; | ||||
const browser = detectBrowser(); | const browser = detectBrowser(); | ||||
const exifRotate = | const exifRotate = | ||||
▲ Show 20 Lines • Show All 659 Lines • ▼ Show 20 Lines | if (this.shouldEncryptMedia(threadID)) { | ||||
} | } | ||||
steps.push(...encryptionResponse.steps); | steps.push(...encryptionResponse.steps); | ||||
encryptionResult = encryptionResponse.result; | encryptionResult = encryptionResponse.result; | ||||
} | } | ||||
if (encryptionResult && !encryptionResult.success) { | if (encryptionResult && !encryptionResult.success) { | ||||
return { steps, result: encryptionResult }; | return { steps, result: encryptionResult }; | ||||
} | } | ||||
const { steps: thumbHashSteps, result: thumbHashResult } = | |||||
await generateThumbHash(fixedFile, encryptionResult?.encryptionKey); | |||||
const thumbHash = thumbHashResult.success | |||||
? thumbHashResult.thumbHash | |||||
: null; | |||||
steps.push(...thumbHashSteps); | |||||
return { | return { | ||||
steps, | steps, | ||||
result: { | result: { | ||||
success: true, | success: true, | ||||
pendingUpload: { | pendingUpload: { | ||||
localID: getNextLocalUploadID(), | localID: getNextLocalUploadID(), | ||||
serverID: null, | serverID: null, | ||||
messageID: null, | messageID: null, | ||||
failed: false, | failed: false, | ||||
file: encryptionResult?.file ?? fixedFile, | file: encryptionResult?.file ?? fixedFile, | ||||
mediaType: encryptionResult ? 'encrypted_photo' : mediaType, | mediaType: encryptionResult ? 'encrypted_photo' : mediaType, | ||||
dimensions, | dimensions, | ||||
uri: encryptionResult?.uri ?? uri, | uri: encryptionResult?.uri ?? uri, | ||||
loop: false, | loop: false, | ||||
uriIsReal: false, | uriIsReal: false, | ||||
blobHash: encryptionResult?.sha256Hash, | blobHash: encryptionResult?.sha256Hash, | ||||
encryptionKey: encryptionResult?.encryptionKey, | encryptionKey: encryptionResult?.encryptionKey, | ||||
thumbHash, | |||||
progressPercent: 0, | progressPercent: 0, | ||||
abort: null, | abort: null, | ||||
steps, | steps, | ||||
selectTime, | selectTime, | ||||
}, | }, | ||||
}, | }, | ||||
}; | }; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | try { | ||||
abortHandler: (abort: () => void) => | abortHandler: (abort: () => void) => | ||||
this.handleAbortCallback(threadID, localID, abort), | this.handleAbortCallback(threadID, localID, abort), | ||||
}; | }; | ||||
if ( | if ( | ||||
this.useBlobServiceUploads && | this.useBlobServiceUploads && | ||||
(upload.mediaType === 'encrypted_photo' || | (upload.mediaType === 'encrypted_photo' || | ||||
upload.mediaType === 'encrypted_video') | upload.mediaType === 'encrypted_video') | ||||
) { | ) { | ||||
const { blobHash, dimensions } = upload; | const { blobHash, dimensions, thumbHash } = upload; | ||||
invariant( | invariant( | ||||
encryptionKey && blobHash && dimensions, | encryptionKey && blobHash && dimensions, | ||||
'incomplete encrypted upload', | 'incomplete encrypted upload', | ||||
); | ); | ||||
uploadResult = await this.blobServiceUpload( | uploadResult = await this.blobServiceUpload( | ||||
{ | { | ||||
file: upload.file, | file: upload.file, | ||||
blobHash, | blobHash, | ||||
encryptionKey, | encryptionKey, | ||||
dimensions, | dimensions, | ||||
loop: false, | loop: false, | ||||
...(thumbHash ? { thumbHash } : undefined), | |||||
}, | }, | ||||
{ ...callbacks }, | { ...callbacks }, | ||||
); | ); | ||||
} else { | } else { | ||||
let uploadExtras = { ...upload.dimensions, loop: false }; | let uploadExtras = { | ||||
...upload.dimensions, | |||||
loop: false, | |||||
thumbHash: upload.thumbHash, | |||||
}; | |||||
if (encryptionKey) { | if (encryptionKey) { | ||||
uploadExtras = { ...uploadExtras, encryptionKey }; | uploadExtras = { ...uploadExtras, encryptionKey }; | ||||
} | } | ||||
uploadResult = await this.props.uploadMultimedia( | uploadResult = await this.props.uploadMultimedia( | ||||
upload.file, | upload.file, | ||||
uploadExtras, | uploadExtras, | ||||
callbacks, | callbacks, | ||||
); | ); | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | const uploadAfterPreload = | ||||
this.state.pendingUploads[preloadThreadID][localID]; | this.state.pendingUploads[preloadThreadID][localID]; | ||||
invariant( | invariant( | ||||
uploadAfterPreload, | uploadAfterPreload, | ||||
`pendingUpload ${localID}/${result.id} for ${preloadThreadID} missing ` + | `pendingUpload ${localID}/${result.id} for ${preloadThreadID} missing ` + | ||||
`after preload`, | `after preload`, | ||||
); | ); | ||||
if (uploadAfterPreload.messageID) { | if (uploadAfterPreload.messageID) { | ||||
const { mediaType, uri, dimensions, loop } = result; | const { mediaType, uri, dimensions, loop } = result; | ||||
let mediaUpdate; | const { thumbHash } = upload; | ||||
let mediaUpdate = { | |||||
loop, | |||||
dimensions, | |||||
...(thumbHash ? { thumbHash } : undefined), | |||||
}; | |||||
if (!isEncrypted) { | if (!isEncrypted) { | ||||
mediaUpdate = { type: mediaType, uri, dimensions, loop }; | mediaUpdate = { | ||||
...mediaUpdate, | |||||
type: mediaType, | |||||
uri, | |||||
}; | |||||
} else { | } else { | ||||
mediaUpdate = { | mediaUpdate = { | ||||
...mediaUpdate, | |||||
type: outputMediaType, | type: outputMediaType, | ||||
holder: uri, | holder: uri, | ||||
encryptionKey, | encryptionKey, | ||||
dimensions, | |||||
loop, | |||||
}; | }; | ||||
} | } | ||||
this.props.dispatch({ | this.props.dispatch({ | ||||
type: updateMultimediaMessageMediaActionType, | type: updateMultimediaMessageMediaActionType, | ||||
payload: { | payload: { | ||||
messageID: uploadAfterPreload.messageID, | messageID: uploadAfterPreload.messageID, | ||||
currentMediaID: uploadAfterPreload.serverID | currentMediaID: uploadAfterPreload.serverID | ||||
? uploadAfterPreload.serverID | ? uploadAfterPreload.serverID | ||||
Show All 38 Lines | this.setState(prevState => { | ||||
}, | }, | ||||
}, | }, | ||||
}; | }; | ||||
}); | }); | ||||
} | } | ||||
async blobServiceUpload( | async blobServiceUpload( | ||||
input: { | input: { | ||||
file: File, | +file: File, | ||||
blobHash: string, | +blobHash: string, | ||||
encryptionKey: string, | +encryptionKey: string, | ||||
dimensions: Dimensions, | +dimensions: Dimensions, | ||||
loop?: boolean, | +loop?: boolean, | ||||
+thumbHash?: string, | |||||
}, | }, | ||||
options?: ?CallServerEndpointOptions, | options?: ?CallServerEndpointOptions, | ||||
): Promise<void> { | ): Promise<void> { | ||||
const newHolder = uuid.v4(); | const newHolder = uuid.v4(); | ||||
const blobHash = toBase64URL(input.blobHash); | const blobHash = toBase64URL(input.blobHash); | ||||
// 1. Assign new holder for blob with given blobHash | // 1. Assign new holder for blob with given blobHash | ||||
let blobAlreadyExists: boolean; | let blobAlreadyExists: boolean; | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | ): Promise<void> { | ||||
// 3. Send upload metadata to the keyserver, return response | // 3. Send upload metadata to the keyserver, return response | ||||
return await this.props.uploadMediaMetadata({ | return await this.props.uploadMediaMetadata({ | ||||
...input.dimensions, | ...input.dimensions, | ||||
loop: input.loop ?? false, | loop: input.loop ?? false, | ||||
blobHolder: newHolder, | blobHolder: newHolder, | ||||
encryptionKey: input.encryptionKey, | encryptionKey: input.encryptionKey, | ||||
mimeType: input.file.type, | mimeType: input.file.type, | ||||
filename: input.file.name, | filename: input.file.name, | ||||
thumbHash: input.thumbHash, | |||||
}); | }); | ||||
} | } | ||||
handleAbortCallback( | handleAbortCallback( | ||||
threadID: string, | threadID: string, | ||||
localUploadID: string, | localUploadID: string, | ||||
abort: () => void, | abort: () => void, | ||||
) { | ) { | ||||
▲ Show 20 Lines • Show All 587 Lines • Show Last 20 Lines |