Changeset View
Changeset View
Standalone View
Standalone View
web/input/input-state-container.react.js
Show First 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | import { | ||||
threadTypes, | threadTypes, | ||||
} from 'lib/types/thread-types.js'; | } from 'lib/types/thread-types.js'; | ||||
import { | import { | ||||
type DispatchActionPromise, | type DispatchActionPromise, | ||||
useServerCall, | useServerCall, | ||||
useDispatchActionPromise, | useDispatchActionPromise, | ||||
} from 'lib/utils/action-utils.js'; | } from 'lib/utils/action-utils.js'; | ||||
import { toBase64URL } from 'lib/utils/base64.js'; | import { toBase64URL } from 'lib/utils/base64.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 type { CallServerEndpointOptions } from 'lib/utils/call-server-endpoint.js'; | ||||
import { getConfig } from 'lib/utils/config.js'; | import { getConfig } from 'lib/utils/config.js'; | ||||
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, | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | typeaheadState: { | ||||
moveChoiceUp: null, | moveChoiceUp: null, | ||||
moveChoiceDown: null, | moveChoiceDown: null, | ||||
close: null, | close: null, | ||||
accept: null, | accept: null, | ||||
}, | }, | ||||
}; | }; | ||||
replyCallbacks: Array<(message: string) => void> = []; | replyCallbacks: Array<(message: string) => void> = []; | ||||
pendingThreadCreations = new Map<string, Promise<string>>(); | pendingThreadCreations = new Map<string, Promise<string>>(); | ||||
// TODO: flip the switch | |||||
// Note that this enables Blob service for encrypted media only | |||||
useBlobServiceUploads = false; | |||||
// When the user sends a multimedia message that triggers the creation of a | // 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 | // sidebar, the sidebar gets created right away, but the message needs to wait | ||||
// for the uploads to complete before sending. We use this Set to track the | // for the uploads to complete before sending. We use this Set to track the | ||||
// message localIDs that need sidebarCreation: true. | // message localIDs that need sidebarCreation: true. | ||||
pendingSidebarCreationMessageLocalIDs = new Set<string>(); | pendingSidebarCreationMessageLocalIDs = new Set<string>(); | ||||
static reassignToRealizedThreads<T>( | static reassignToRealizedThreads<T>( | ||||
▲ Show 20 Lines • Show All 583 Lines • ▼ Show 20 Lines | 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 ? encryptionResult.file : fixedFile, | file: encryptionResult?.file ?? fixedFile, | ||||
mediaType: encryptionResult ? 'encrypted_photo' : mediaType, | mediaType: encryptionResult ? 'encrypted_photo' : mediaType, | ||||
dimensions, | dimensions, | ||||
uri: encryptionResult ? encryptionResult.uri : uri, | uri: encryptionResult?.uri ?? uri, | ||||
loop: false, | loop: false, | ||||
uriIsReal: false, | uriIsReal: false, | ||||
encryptionKey: encryptionResult | blobHash: encryptionResult?.sha256Hash, | ||||
? encryptionResult.encryptionKey | encryptionKey: encryptionResult?.encryptionKey, | ||||
: null, | |||||
progressPercent: 0, | progressPercent: 0, | ||||
abort: null, | abort: null, | ||||
steps, | steps, | ||||
selectTime, | selectTime, | ||||
}, | }, | ||||
}, | }, | ||||
}; | }; | ||||
} | } | ||||
Show All 36 Lines | const sendReport = (missionResult: MediaMissionResult) => { | ||||
messageLocalID: messageID, | messageLocalID: messageID, | ||||
}, | }, | ||||
]); | ]); | ||||
}; | }; | ||||
let uploadResult, uploadExceptionMessage; | let uploadResult, uploadExceptionMessage; | ||||
const uploadStart = Date.now(); | const uploadStart = Date.now(); | ||||
try { | try { | ||||
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 }; | let uploadExtras = { ...upload.dimensions, loop: false }; | ||||
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, | ||||
onProgress: (percent: number) => | |||||
this.setProgress(threadID, localID, percent), | |||||
abortHandler: (abort: () => void) => | |||||
this.handleAbortCallback(threadID, localID, abort), | |||||
}, | |||||
); | ); | ||||
} | |||||
} catch (e) { | } catch (e) { | ||||
uploadExceptionMessage = getMessageForException(e); | uploadExceptionMessage = getMessageForException(e); | ||||
this.handleUploadFailure(threadID, localID); | this.handleUploadFailure(threadID, localID); | ||||
} | } | ||||
userTime = Date.now() - selectTime; | userTime = Date.now() - selectTime; | ||||
steps.push({ | steps.push({ | ||||
step: 'upload', | step: 'upload', | ||||
success: !!uploadResult, | success: !!uploadResult, | ||||
▲ Show 20 Lines • Show All 352 Lines • ▼ Show 20 Lines | this.setState( | ||||
if (!pendingUpload.uriIsReal) { | if (!pendingUpload.uriIsReal) { | ||||
revokeURL = pendingUpload.uri; | revokeURL = pendingUpload.uri; | ||||
} | } | ||||
if (pendingUpload.abort) { | if (pendingUpload.abort) { | ||||
abortRequest = pendingUpload.abort; | abortRequest = pendingUpload.abort; | ||||
} | } | ||||
if (pendingUpload.serverID) { | if (pendingUpload.serverID) { | ||||
this.props.deleteUpload(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); | const newPendingUploads = _omit([localUploadID])(currentPendingUploads); | ||||
return { | return { | ||||
pendingUploads: { | pendingUploads: { | ||||
...prevState.pendingUploads, | ...prevState.pendingUploads, | ||||
[newThreadID]: newPendingUploads, | [newThreadID]: newPendingUploads, | ||||
}, | }, | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 477 Lines • Show Last 20 Lines |