Skip to content

Commit

Permalink
Merge pull request #727 from contember/refactor/s3-url
Browse files Browse the repository at this point in the history
s3 client accepts url signer function
  • Loading branch information
matej21 authored Jun 18, 2024
2 parents 89dfa0c + b9eb164 commit 7d74fd5
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 31 deletions.
6 changes: 4 additions & 2 deletions build/api/react-uploader.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { Environment as Environment_2 } from '@contember/react-binding';
import { ErrorAccessor } from '@contember/binding';
import { ErrorAccessorHolder } from '@contember/binding';
import { GenerateUploadUrlMutationBuilder } from '@contember/client';
import { GraphQlClient } from '@contember/graphql-client';
import { JSX as JSX_2 } from 'react/jsx-runtime';
import { JSXElementConstructor } from 'react';
import { NamedExoticComponent } from 'react';
Expand Down Expand Up @@ -273,7 +272,7 @@ export interface S3FileOptions {

// @public (undocumented)
export class S3UploadClient implements UploadClient<S3FileOptions> {
constructor(contentApiClient: GraphQlClient, options?: S3UploadClientOptions);
constructor(s3UrlSigner: S3UrlSigner, options?: S3UploadClientOptions);
// (undocumented)
readonly options: S3UploadClientOptions;
// (undocumented)
Expand All @@ -290,6 +289,9 @@ export interface S3UploadClientOptions {
getUploadOptions?: (file: File) => S3FileOptions;
}

// @public (undocumented)
export type S3UrlSigner = (parameters: GenerateUploadUrlMutationBuilder.FileParameters) => Promise<GenerateUploadUrlMutationBuilder.ResponseBody>;

// @public (undocumented)
export type StartUploadEvent = {
file: FileWithMeta;
Expand Down
3 changes: 2 additions & 1 deletion packages/react-uploader/src/hooks/useS3Client.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { S3UploadClient } from '../uploadClient/S3UploadClient'
import { useCurrentContentGraphQlClient } from '@contember/react-client'
import { createBatchSignedUrlGenerator } from '../internal/utils/urlSigner'

export const useS3Client = () => new S3UploadClient(useCurrentContentGraphQlClient())
export const useS3Client = () => new S3UploadClient(createBatchSignedUrlGenerator(useCurrentContentGraphQlClient()))
25 changes: 25 additions & 0 deletions packages/react-uploader/src/internal/utils/urlSigner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { GenerateUploadUrlMutationBuilder } from '@contember/client'
import { GraphQlClient } from '@contember/graphql-client'

export const createBatchSignedUrlGenerator = (client: GraphQlClient) => {

let uploadUrlBatchParameters: GenerateUploadUrlMutationBuilder.FileParameters[] = []
let uploadUrlBatchResult: null | Promise<GenerateUploadUrlMutationBuilder.MutationResponse> = null

return async (parameters: GenerateUploadUrlMutationBuilder.FileParameters): Promise<GenerateUploadUrlMutationBuilder.ResponseBody> => {
const index = uploadUrlBatchParameters.length
uploadUrlBatchParameters.push(parameters)
if (uploadUrlBatchResult === null) {
uploadUrlBatchResult = (async () => {
await new Promise(resolve => setTimeout(resolve, 0))

const mutation = GenerateUploadUrlMutationBuilder.buildQuery(Object.fromEntries(uploadUrlBatchParameters.map((_, i) => ['url_' + i, _])))
uploadUrlBatchResult = null
uploadUrlBatchParameters = []

return await client.execute<GenerateUploadUrlMutationBuilder.MutationResponse>(mutation.query, { variables: mutation.variables })
})()
}
return (await uploadUrlBatchResult)[`url_${index}`]
}
}
33 changes: 5 additions & 28 deletions packages/react-uploader/src/uploadClient/S3UploadClient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { FileUploadProgress, UploadClient, UploadClientUploadArgs } from './UploadClient'
import { UploadClient, UploadClientUploadArgs } from './UploadClient'
import { GenerateUploadUrlMutationBuilder } from '@contember/client'
import { GraphQlClient } from '@contember/graphql-client'
import { UploaderError } from '../UploaderError'

export interface S3UploadClientOptions {
Expand All @@ -19,17 +18,17 @@ export interface S3FileOptions {
acl?: GenerateUploadUrlMutationBuilder.Acl
}

export type S3UrlSigner = (parameters: GenerateUploadUrlMutationBuilder.FileParameters) => Promise<GenerateUploadUrlMutationBuilder.ResponseBody>

export class S3UploadClient implements UploadClient<S3FileOptions> {

private getSignedUploadUrl: ReturnType<typeof createBatchSignedUrlGenerator>
private activeCount = 0
private resolverQueue: Array<() => void> = []

public constructor(
contentApiClient: GraphQlClient,
private readonly s3UrlSigner: S3UrlSigner,
public readonly options: S3UploadClientOptions = {},
) {
this.getSignedUploadUrl = createBatchSignedUrlGenerator(contentApiClient)
}


Expand All @@ -44,7 +43,7 @@ export class S3UploadClient implements UploadClient<S3FileOptions> {
contentType: file.type,
...resolvedOptions,
}
const responseData = await this.getSignedUploadUrl(parameters)
const responseData = await this.s3UrlSigner(parameters)
await this.uploadSingleFile(responseData, { file, onProgress, signal })

return {
Expand Down Expand Up @@ -131,25 +130,3 @@ const xhrAdapter = async (
}


const createBatchSignedUrlGenerator = (client: GraphQlClient) => {

let uploadUrlBatchParameters: GenerateUploadUrlMutationBuilder.FileParameters[] = []
let uploadUrlBatchResult: null | Promise<GenerateUploadUrlMutationBuilder.MutationResponse> = null

return async (parameters: GenerateUploadUrlMutationBuilder.FileParameters): Promise<GenerateUploadUrlMutationBuilder.ResponseBody> => {
const index = uploadUrlBatchParameters.length
uploadUrlBatchParameters.push(parameters)
if (uploadUrlBatchResult === null) {
uploadUrlBatchResult = (async () => {
await new Promise(resolve => setTimeout(resolve, 0))

const mutation = GenerateUploadUrlMutationBuilder.buildQuery(Object.fromEntries(uploadUrlBatchParameters.map((_, i) => ['url_' + i, _])))
const response = await client.execute<GenerateUploadUrlMutationBuilder.MutationResponse>(mutation.query, { variables: mutation.variables })
uploadUrlBatchParameters = []
uploadUrlBatchResult = null
return response
})()
}
return (await uploadUrlBatchResult)[`url_${index}`]
}
}

0 comments on commit 7d74fd5

Please sign in to comment.