Skip to content

Commit

Permalink
Allow Transloadit-hosted Companion with other uploaders
Browse files Browse the repository at this point in the history
  • Loading branch information
Murderlon committed Dec 19, 2024
1 parent d6156bb commit 22b183a
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 12 deletions.
16 changes: 15 additions & 1 deletion packages/@uppy/aws-s3/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -923,10 +923,24 @@ export default class AwsS3Multipart<

// eslint-disable-next-line class-methods-use-this
#getCompanionClientArgs(file: UppyFile<M, B>) {
const opts = { ...this.opts }

// When you .use(AwsS3) with .use(Transloadit, { companionOnly: true }),
// local files are uploaded with this plugin and remote files with the Transloadit plugin.
// Since the Transloadit plugin uses the tus plugin underneath, it's possible to have file.tus
// even though we are in this plugin.
// @ts-expect-error typed in @uppy/tus
if (file.tus) {
// @ts-expect-error typed in @uppy/tus
Object.assign(opts, file.tus)
}

return {
...file.remote?.body,
protocol: 's3-multipart',
endpoint: opts.endpoint,
protocol: this.uppy.getState().remoteUploader || 's3-multipart',
size: file.data.size,
headers: opts.headers,
metadata: file.meta,
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/@uppy/core/src/Uppy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ export interface State<M extends Meta, B extends Body>
currentUploads: Record<string, CurrentUpload<M, B>>
allowNewUpload: boolean
recoveredState: null | Required<Pick<State<M, B>, 'files' | 'currentUploads'>>
remoteUploader?: 'tus' | 's3-multipart' | 'multipart'
error: string | null
files: {
[key: string]: UppyFile<M, B>
Expand Down
35 changes: 26 additions & 9 deletions packages/@uppy/transloadit/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ export interface TransloaditOptions<M extends Meta, B extends Body>
waitForMetadata?: boolean
importFromUploadURLs?: boolean
alwaysRunAssembly?: boolean
/**
* Only use Transloadit for remote file uploads (such as from Google Drive).
* Enabling this means you have to install another plugin for local files,
* such as @uppy/aws-s3 or @uppy/xhr-upload.
*/
companionOnly?: boolean
limit?: number
clientName?: string | null
retryDelays?: number[]
Expand All @@ -145,6 +151,7 @@ const defaultOptions = {
waitForMetadata: false,
alwaysRunAssembly: false,
importFromUploadURLs: false,
companionOnly: false,
limit: 20,
retryDelays: [7_000, 10_000, 15_000, 20_000],
clientName: null,
Expand Down Expand Up @@ -295,6 +302,13 @@ export default class Transloadit<

this.i18nInit()

if (this.opts.companionOnly) {
// Transloadit is only a pre and post processor.
// To let Transloadit hosted Companion download the file,
// we instruct any other upload plugin to use tus for remote uploads.
this.uppy.setState({ remoteUploader: 'tus' })
}

this.client = new Client({
service: this.opts.service,
client: this.#getClientVersion(),
Expand Down Expand Up @@ -802,26 +816,30 @@ export default class Transloadit<

assemblyOptions.fields ??= {}
validateParams(assemblyOptions.params)
const ids =
this.opts.companionOnly ?
fileIDs.filter((id) => this.uppy.getFile(id).isRemote)
: fileIDs

try {
const assembly =
// this.assembly can already be defined if we recovered files with Golden Retriever (this.#onRestored)
this.assembly ?? (await this.#createAssembly(fileIDs, assemblyOptions))
this.assembly ?? (await this.#createAssembly(ids, assemblyOptions))

if (assembly == null)
throw new Error('All files were canceled after assembly was created')

if (this.opts.importFromUploadURLs) {
await this.#reserveFiles(assembly, fileIDs)
await this.#reserveFiles(assembly, ids)
}
fileIDs.forEach((fileID) => {
ids.forEach((fileID) => {
const file = this.uppy.getFile(fileID)
this.uppy.emit('preprocess-complete', file)
})
this.#createAssemblyWatcher(assembly.status.assembly_id)
this.#connectAssembly(assembly, fileIDs)
this.#connectAssembly(assembly, ids)
} catch (err) {
fileIDs.forEach((fileID) => {
ids.forEach((fileID) => {
const file = this.uppy.getFile(fileID)
// Clear preprocessing state when the Assembly could not be created,
// otherwise the UI gets confused about the lingering progress keys
Expand Down Expand Up @@ -937,9 +955,9 @@ export default class Transloadit<
if (this.opts.importFromUploadURLs) {
// No uploader needed when importing; instead we take the upload URL from an existing uploader.
this.uppy.on('upload-success', this.#onFileUploadURLAvailable)
} else {
// we don't need it here.
// the regional endpoint from the Transloadit API before we can set it.
// If companionOnly is true, another uploader plugin is installed for local uploads
// and we only use Transloadit to create an assembly for the remote files.
} else if (!this.opts.companionOnly) {
this.uppy.use(Tus, {
// Disable tus-js-client fingerprinting, otherwise uploading the same file at different times
// will upload to an outdated Assembly, and we won't get socket events for it.
Expand All @@ -954,7 +972,6 @@ export default class Transloadit<
// Send all metadata to Transloadit. Metadata set by the user
// ends up as in the template as `file.user_meta`
allowedMetaFields: true,
// Pass the limit option to @uppy/tus
limit: this.opts.limit,
rateLimitedQueue: this.#rateLimitedQueue,
retryDelays: this.opts.retryDelays,
Expand Down
12 changes: 11 additions & 1 deletion packages/@uppy/xhr-upload/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,9 +438,19 @@ export default class XHRUpload<
opts.allowedMetaFields,
file.meta,
)
// When you .use(AwsS3) with .use(Transloadit, { companionOnly: true }),
// local files are uploaded with this plugin and remote files with the Transloadit plugin.
// Since the Transloadit plugin uses the tus plugin underneath, it's possible to have file.tus
// even though we are in this plugin.
// @ts-expect-error typed in @uppy/tus
if (file.tus) {
// @ts-expect-error typed in @uppy/tus
Object.assign(opts, file.tus)
}

return {
...file.remote?.body,
protocol: 'multipart',
protocol: this.uppy.getState().remoteUploader || 'multipart',
endpoint: opts.endpoint,
size: file.data.size,
fieldname: opts.fieldName,
Expand Down
18 changes: 17 additions & 1 deletion private/dev/Dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ export default () => {
.use(Webdav, {
target: Dashboard,
companionUrl: COMPANION_URL,
companionAllowedHosts
companionAllowedHosts,
})
.use(Audio, {
target: Dashboard,
Expand All @@ -195,6 +195,15 @@ export default () => {
shouldUseMultipart: false,
})
break
case 's3-with-transloadit-companion':
uppyDashboard.use(AwsS3, { endpoint: COMPANION_URL })
uppyDashboard.use(Transloadit, {
service: TRANSLOADIT_SERVICE_URL,
waitForEncoding: true,
assemblyOptions,
companionOnly: true,
})
break
case 's3-multipart':
uppyDashboard.use(AwsS3, {
endpoint: COMPANION_URL,
Expand All @@ -207,6 +216,12 @@ export default () => {
limit: 6,
bundle: false,
})
uppyDashboard.use(Transloadit, {
service: TRANSLOADIT_SERVICE_URL,
waitForEncoding: true,
assemblyOptions,
companionOnly: true,
})
break
case 'transloadit':
uppyDashboard.use(Transloadit, {
Expand All @@ -221,6 +236,7 @@ export default () => {
waitForEncoding: true,
importFromUploadURLs: true,
assemblyOptions,
companionOnly: true,
})
break
case 'transloadit-xhr':
Expand Down

0 comments on commit 22b183a

Please sign in to comment.