Skip to content

Commit

Permalink
fix uploadRemoteFile undefined
Browse files Browse the repository at this point in the history
for some reason, only when testing locally using VITE_COMPANION_URL=https://api2.transloadit.com/companion only
we get this error...
i'm thinking for some reason, the remote file gets serialized into state and then de-serialized again
causing remote.requestClient to be gone
so I solve it by instead storing the request clients in Uppy

fixes #4791
  • Loading branch information
mifi committed Dec 7, 2023
1 parent 1b6c260 commit a4df077
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 176 deletions.
2 changes: 2 additions & 0 deletions examples/custom-provider/client/MyCustomProvider.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export default class MyCustomProvider extends UIPlugin {
pluginId: this.id,
})

uppy.requestClientById.set(`provider-${this.provider}`, this.provider)

this.defaultLocale = {
strings: {
pluginNameMyUnsplash: 'MyUnsplash',
Expand Down
82 changes: 41 additions & 41 deletions packages/@uppy/aws-s3-multipart/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import MultipartUploader, { pausingUploadReason } from './MultipartUploader.js'
import createSignedURL from './createSignedURL.js'
import packageJson from '../package.json'

function assertServerError (res) {
function assertServerError(res) {
if (res && res.error) {
const error = new Error(res.message)
Object.assign(error, res.error)
Expand All @@ -18,7 +18,7 @@ function assertServerError (res) {
return res
}

function removeMetadataFromURL (urlString) {
function removeMetadataFromURL(urlString) {
const urlObject = new URL(urlString)
urlObject.search = ''
urlObject.hash = ''
Expand All @@ -35,7 +35,7 @@ function removeMetadataFromURL (urlString) {
* @param {import('../types/index.js').AwsS3STSResponse['credentials']} credentials
* @returns {number | undefined}
*/
function getExpiry (credentials) {
function getExpiry(credentials) {
const expirationDate = credentials.Expiration
if (expirationDate) {
const timeUntilExpiry = Math.floor((new Date(expirationDate) - Date.now()) / 1000)
Expand All @@ -46,7 +46,7 @@ function getExpiry (credentials) {
return undefined
}

function getAllowedMetadata ({ meta, allowedMetaFields, querify = false }) {
function getAllowedMetadata({ meta, allowedMetaFields, querify = false }) {
const metaFields = allowedMetaFields ?? Object.keys(meta)

if (!meta) return {}
Expand All @@ -62,7 +62,7 @@ function getAllowedMetadata ({ meta, allowedMetaFields, querify = false }) {
)
}

function throwIfAborted (signal) {
function throwIfAborted(signal) {
if (signal?.aborted) { throw createAbortError('The operation was aborted', { cause: signal.reason }) }
}

Expand Down Expand Up @@ -93,21 +93,21 @@ class HTTPCommunicationQueue {

#getFile

constructor (requests, options, setS3MultipartState, getFile) {
constructor(requests, options, setS3MultipartState, getFile) {
this.#requests = requests
this.#setS3MultipartState = setS3MultipartState
this.#getFile = getFile
this.setOptions(options)
}

setOptions (options) {
setOptions(options) {
const requests = this.#requests

if ('abortMultipartUpload' in options) {
this.#abortMultipartUpload = requests.wrapPromiseFunction(options.abortMultipartUpload, { priority:1 })
this.#abortMultipartUpload = requests.wrapPromiseFunction(options.abortMultipartUpload, { priority: 1 })
}
if ('createMultipartUpload' in options) {
this.#createMultipartUpload = requests.wrapPromiseFunction(options.createMultipartUpload, { priority:-1 })
this.#createMultipartUpload = requests.wrapPromiseFunction(options.createMultipartUpload, { priority: -1 })
}
if ('signPart' in options) {
this.#fetchSignature = requests.wrapPromiseFunction(options.signPart)
Expand All @@ -116,20 +116,20 @@ class HTTPCommunicationQueue {
this.#listParts = requests.wrapPromiseFunction(options.listParts)
}
if ('completeMultipartUpload' in options) {
this.#sendCompletionRequest = requests.wrapPromiseFunction(options.completeMultipartUpload, { priority:1 })
this.#sendCompletionRequest = requests.wrapPromiseFunction(options.completeMultipartUpload, { priority: 1 })
}
if ('retryDelays' in options) {
this.#retryDelays = options.retryDelays ?? []
}
if ('uploadPartBytes' in options) {
this.#uploadPartBytes = requests.wrapPromiseFunction(options.uploadPartBytes, { priority:Infinity })
this.#uploadPartBytes = requests.wrapPromiseFunction(options.uploadPartBytes, { priority: Infinity })
}
if ('getUploadParameters' in options) {
this.#getUploadParameters = requests.wrapPromiseFunction(options.getUploadParameters)
}
}

async #shouldRetry (err, retryDelayIterator) {
async #shouldRetry(err, retryDelayIterator) {
const requests = this.#requests
const status = err?.source?.status

Expand Down Expand Up @@ -191,7 +191,7 @@ class HTTPCommunicationQueue {
return true
}

async getUploadId (file, signal) {
async getUploadId(file, signal) {
let cachedResult
// As the cache is updated asynchronously, there could be a race condition
// where we just miss a new result so we loop here until we get nothing back,
Expand Down Expand Up @@ -225,7 +225,7 @@ class HTTPCommunicationQueue {
return promise
}

async abortFileUpload (file) {
async abortFileUpload(file) {
const result = this.#cache.get(file.data)
if (result == null) {
// If the createMultipartUpload request never was made, we don't
Expand All @@ -246,7 +246,7 @@ class HTTPCommunicationQueue {
await this.#abortMultipartUpload(this.#getFile(file), awaitedResult)
}

async #nonMultipartUpload (file, chunk, signal) {
async #nonMultipartUpload(file, chunk, signal) {
const {
method = 'POST',
url,
Expand Down Expand Up @@ -288,7 +288,7 @@ class HTTPCommunicationQueue {
* @param {AbortSignal} signal
* @returns {Promise<void>}
*/
async uploadFile (file, chunks, signal) {
async uploadFile(file, chunks, signal) {
throwIfAborted(signal)
if (chunks.length === 1 && !chunks[0].shouldUseMultipart) {
return this.#nonMultipartUpload(file, chunks[0], signal)
Expand All @@ -314,11 +314,11 @@ class HTTPCommunicationQueue {
}
}

restoreUploadFile (file, uploadIdAndKey) {
restoreUploadFile(file, uploadIdAndKey) {
this.#cache.set(file.data, uploadIdAndKey)
}

async resumeUploadFile (file, chunks, signal) {
async resumeUploadFile(file, chunks, signal) {
throwIfAborted(signal)
if (chunks.length === 1 && chunks[0] != null && !chunks[0].shouldUseMultipart) {
return this.#nonMultipartUpload(file, chunks[0], signal)
Expand Down Expand Up @@ -360,7 +360,7 @@ class HTTPCommunicationQueue {
* @param {AbortSignal} signal
* @returns {Promise<object>}
*/
async uploadChunk (file, partNumber, chunk, signal) {
async uploadChunk(file, partNumber, chunk, signal) {
throwIfAborted(signal)
const { uploadId, key } = await this.getUploadId(file, signal)

Expand All @@ -374,7 +374,7 @@ class HTTPCommunicationQueue {
return next.value
}

for (;;) {
for (; ;) {
throwIfAborted(signal)
const chunkData = chunk.getData()
const { onProgress, onComplete } = chunk
Expand Down Expand Up @@ -416,7 +416,7 @@ export default class AwsS3Multipart extends BasePlugin {

#client

constructor (uppy, opts) {
constructor(uppy, opts) {
super(uppy, opts)
this.type = 'uploader'
this.id = this.opts.id || 'AwsS3Multipart'
Expand Down Expand Up @@ -472,9 +472,9 @@ export default class AwsS3Multipart extends BasePlugin {
this.uploaderSockets = Object.create(null)
}

[Symbol.for('uppy test: getClient')] () { return this.#client }
[Symbol.for('uppy test: getClient')]() { return this.#client }

setOptions (newOptions) {
setOptions(newOptions) {
this.#companionCommunicationQueue.setOptions(newOptions)
super.setOptions(newOptions)
this.#setCompanionHeaders()
Expand All @@ -487,7 +487,7 @@ export default class AwsS3Multipart extends BasePlugin {
* Set `opts.abort` to tell S3 that the multipart upload is cancelled and must be removed.
* This should be done when the user cancels the upload, not when the upload is completed or errored.
*/
resetUploaderReferences (fileID, opts = {}) {
resetUploaderReferences(fileID, opts = {}) {
if (this.uploaders[fileID]) {
this.uploaders[fileID].abort({ really: opts.abort || false })
this.uploaders[fileID] = null
Expand All @@ -503,13 +503,13 @@ export default class AwsS3Multipart extends BasePlugin {
}

// TODO: make this a private method in the next major
assertHost (method) {
assertHost(method) {
if (!this.opts.companionUrl) {
throw new Error(`Expected a \`companionUrl\` option containing a Companion address, or if you are not using Companion, a custom \`${method}\` implementation.`)
}
}

createMultipartUpload (file, signal) {
createMultipartUpload(file, signal) {
this.assertHost('createMultipartUpload')
throwIfAborted(signal)

Expand All @@ -522,7 +522,7 @@ export default class AwsS3Multipart extends BasePlugin {
}, { signal }).then(assertServerError)
}

listParts (file, { key, uploadId }, signal) {
listParts(file, { key, uploadId }, signal) {
this.assertHost('listParts')
throwIfAborted(signal)

Expand All @@ -531,7 +531,7 @@ export default class AwsS3Multipart extends BasePlugin {
.then(assertServerError)
}

completeMultipartUpload (file, { key, uploadId, parts }, signal) {
completeMultipartUpload(file, { key, uploadId, parts }, signal) {
this.assertHost('completeMultipartUpload')
throwIfAborted(signal)

Expand All @@ -546,7 +546,7 @@ export default class AwsS3Multipart extends BasePlugin {
*/
#cachedTemporaryCredentials

async #getTemporarySecurityCredentials (options) {
async #getTemporarySecurityCredentials(options) {
throwIfAborted(options?.signal)

if (this.#cachedTemporaryCredentials == null) {
Expand All @@ -573,7 +573,7 @@ export default class AwsS3Multipart extends BasePlugin {
return this.#cachedTemporaryCredentials
}

async createSignedURL (file, options) {
async createSignedURL(file, options) {
const data = await this.#getTemporarySecurityCredentials(options)
const expires = getExpiry(data.credentials) || 604_800 // 604 800 is the max value accepted by AWS.

Expand Down Expand Up @@ -603,7 +603,7 @@ export default class AwsS3Multipart extends BasePlugin {
}
}

signPart (file, { uploadId, key, partNumber, signal }) {
signPart(file, { uploadId, key, partNumber, signal }) {
this.assertHost('signPart')
throwIfAborted(signal)

Expand All @@ -616,7 +616,7 @@ export default class AwsS3Multipart extends BasePlugin {
.then(assertServerError)
}

abortMultipartUpload (file, { key, uploadId }, signal) {
abortMultipartUpload(file, { key, uploadId }, signal) {
this.assertHost('abortMultipartUpload')

const filename = encodeURIComponent(key)
Expand All @@ -625,7 +625,7 @@ export default class AwsS3Multipart extends BasePlugin {
.then(assertServerError)
}

getUploadParameters (file, options) {
getUploadParameters(file, options) {
const { meta } = file
const { type, name: filename } = meta
const metadata = getAllowedMetadata({ meta, allowedMetaFields: this.opts.allowedMetaFields, querify: true })
Expand All @@ -635,7 +635,7 @@ export default class AwsS3Multipart extends BasePlugin {
return this.#client.get(`s3/params?${query}`, options)
}

static async uploadPartBytes ({ signature: { url, expires, headers, method = 'PUT' }, body, size = body.size, onProgress, onComplete, signal }) {
static async uploadPartBytes({ signature: { url, expires, headers, method = 'PUT' }, body, size = body.size, onProgress, onComplete, signal }) {
throwIfAborted(signal)

if (url == null) {
Expand All @@ -655,10 +655,10 @@ export default class AwsS3Multipart extends BasePlugin {
xhr.timeout = expires * 1000
}

function onabort () {
function onabort() {
xhr.abort()
}
function cleanup () {
function cleanup() {
signal.removeEventListener('abort', onabort)
}
signal.addEventListener('abort', onabort)
Expand Down Expand Up @@ -751,7 +751,7 @@ export default class AwsS3Multipart extends BasePlugin {
return this.uppy.getFile(file.id) || file
}

#uploadLocalFile (file) {
#uploadLocalFile(file) {
return new Promise((resolve, reject) => {
const onProgress = (bytesUploaded, bytesTotal) => {
this.uppy.emit('upload-progress', file, {
Expand Down Expand Up @@ -849,7 +849,7 @@ export default class AwsS3Multipart extends BasePlugin {
}

// eslint-disable-next-line class-methods-use-this
#getCompanionClientArgs (file) {
#getCompanionClientArgs(file) {
return {
...file.remote.body,
protocol: 's3-multipart',
Expand Down Expand Up @@ -878,7 +878,7 @@ export default class AwsS3Multipart extends BasePlugin {
}
this.uppy.on('file-removed', removedHandler)

const uploadPromise = file.remote.requestClient.uploadRemoteFile(
const uploadPromise = this.uppy.requestClientById.get(file.remote.requestClientId).uploadRemoteFile(
file,
this.#getCompanionClientArgs(file),
{ signal: controller.signal, getQueue },
Expand Down Expand Up @@ -919,14 +919,14 @@ export default class AwsS3Multipart extends BasePlugin {
this.#setResumableUploadsCapability(true)
}

install () {
install() {
this.#setResumableUploadsCapability(true)
this.uppy.addPreProcessor(this.#setCompanionHeaders)
this.uppy.addUploader(this.#upload)
this.uppy.on('cancel-all', this.#resetResumableCapability)
}

uninstall () {
uninstall() {
this.uppy.removePreProcessor(this.#setCompanionHeaders)
this.uppy.removeUploader(this.#upload)
this.uppy.off('cancel-all', this.#resetResumableCapability)
Expand Down
Loading

0 comments on commit a4df077

Please sign in to comment.