91 lines
2.6 KiB
TypeScript
Executable File
91 lines
2.6 KiB
TypeScript
Executable File
import {Upload} from 'tus-js-client';
|
|
import {UploadedFile} from '../../uploaded-file';
|
|
import {UploadStrategy, UploadStrategyConfig} from './upload-strategy';
|
|
import {FileEntry} from '../../file-entry';
|
|
import {getAxiosErrorMessage} from '@common/utils/http/get-axios-error-message';
|
|
import {apiClient} from '@common/http/query-client';
|
|
import {getCookie} from 'react-use-cookie';
|
|
|
|
export class TusUpload implements UploadStrategy {
|
|
constructor(private upload: Upload) {}
|
|
|
|
start() {
|
|
this.upload.start();
|
|
}
|
|
|
|
abort() {
|
|
return this.upload.abort(true);
|
|
}
|
|
|
|
static async create(
|
|
file: UploadedFile,
|
|
{
|
|
onProgress,
|
|
onSuccess,
|
|
onError,
|
|
metadata,
|
|
chunkSize,
|
|
baseUrl,
|
|
}: UploadStrategyConfig
|
|
): Promise<TusUpload> {
|
|
const tusFingerprint = ['tus', file.fingerprint, 'drive'].join('-');
|
|
const upload = new Upload(file.native, {
|
|
fingerprint: () => Promise.resolve(tusFingerprint),
|
|
removeFingerprintOnSuccess: true,
|
|
endpoint: `${baseUrl}/api/v1/tus/upload`,
|
|
chunkSize,
|
|
retryDelays: [0, 3000, 5000, 10000, 20000],
|
|
overridePatchMethod: true,
|
|
metadata: {
|
|
name: window.btoa(file.id),
|
|
clientName: file.name,
|
|
clientExtension: file.extension,
|
|
clientMime: file.mime || '',
|
|
clientSize: `${file.size}`,
|
|
...(metadata as Record<string, string>),
|
|
},
|
|
headers: {
|
|
'X-XSRF-TOKEN': getCookie('XSRF-TOKEN'),
|
|
},
|
|
onError: err => {
|
|
if ('originalResponse' in err && err.originalResponse) {
|
|
try {
|
|
const message = JSON.parse(err.originalResponse.getBody())?.message;
|
|
onError?.(message, file);
|
|
} catch (e) {
|
|
onError?.(null, file);
|
|
}
|
|
} else {
|
|
onError?.(null, file);
|
|
}
|
|
},
|
|
onProgress(bytesUploaded, bytesTotal) {
|
|
onProgress?.({bytesUploaded, bytesTotal});
|
|
},
|
|
onSuccess: async () => {
|
|
const uploadKey = upload.url?.split('/').pop();
|
|
try {
|
|
if (uploadKey) {
|
|
const response = await createFileEntry(uploadKey);
|
|
onSuccess?.(response.fileEntry, file);
|
|
}
|
|
} catch (err) {
|
|
localStorage.removeItem(tusFingerprint);
|
|
onError?.(getAxiosErrorMessage(err), file);
|
|
}
|
|
},
|
|
});
|
|
|
|
const previousUploads = await upload.findPreviousUploads();
|
|
if (previousUploads.length) {
|
|
upload.resumeFromPreviousUpload(previousUploads[0]);
|
|
}
|
|
|
|
return new TusUpload(upload);
|
|
}
|
|
}
|
|
|
|
function createFileEntry(uploadKey: string): Promise<{fileEntry: FileEntry}> {
|
|
return apiClient.post('tus/entries', {uploadKey}).then(r => r.data);
|
|
}
|