2021-08-11 04:45:19 +00:00
|
|
|
import {
|
|
|
|
CHUNKS_COMBINED_FOR_A_UPLOAD_PART,
|
|
|
|
DataStream,
|
|
|
|
MultipartUploadURLs,
|
|
|
|
RANDOM_PERCENTAGE_PROGRESS_FOR_PUT,
|
|
|
|
} from './uploadService';
|
2021-08-09 15:15:11 +00:00
|
|
|
import NetworkClient from './networkClient';
|
|
|
|
import * as convert from 'xml-js';
|
2021-08-11 05:26:40 +00:00
|
|
|
import UIService from './uiService';
|
2021-08-09 15:15:11 +00:00
|
|
|
|
2021-08-11 04:45:19 +00:00
|
|
|
interface PartEtag {
|
|
|
|
PartNumber: number;
|
|
|
|
Etag: string;
|
2021-08-09 15:15:11 +00:00
|
|
|
}
|
2021-08-10 05:36:03 +00:00
|
|
|
export function calculatePartCount(chunkCount: number) {
|
2021-08-11 04:45:19 +00:00
|
|
|
const partCount = Math.ceil(chunkCount / CHUNKS_COMBINED_FOR_A_UPLOAD_PART);
|
2021-08-09 15:15:11 +00:00
|
|
|
return partCount;
|
|
|
|
}
|
2021-08-11 04:45:19 +00:00
|
|
|
export async function uploadStreamUsingMultipart(
|
|
|
|
filename: string,
|
|
|
|
dataStream: DataStream,
|
|
|
|
) {
|
2021-08-10 05:36:03 +00:00
|
|
|
const uploadPartCount = calculatePartCount(dataStream.chunkCount);
|
|
|
|
const multipartUploadURLs = await NetworkClient.fetchMultipartUploadURLs(
|
2021-08-09 15:15:11 +00:00
|
|
|
uploadPartCount,
|
|
|
|
);
|
|
|
|
const fileObjectKey = await uploadStreamInParts(
|
2021-08-10 05:36:03 +00:00
|
|
|
multipartUploadURLs,
|
|
|
|
dataStream.stream,
|
2021-08-09 15:15:11 +00:00
|
|
|
filename,
|
|
|
|
uploadPartCount,
|
|
|
|
);
|
|
|
|
return fileObjectKey;
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function uploadStreamInParts(
|
|
|
|
multipartUploadURLs: MultipartUploadURLs,
|
2021-08-10 05:36:03 +00:00
|
|
|
dataStream: ReadableStream<Uint8Array>,
|
2021-08-09 15:15:11 +00:00
|
|
|
filename: string,
|
|
|
|
uploadPartCount: number,
|
|
|
|
) {
|
2021-08-10 05:36:03 +00:00
|
|
|
const streamReader = dataStream.getReader();
|
2021-08-09 15:15:11 +00:00
|
|
|
const percentPerPart = getRandomProgressPerPartUpload(uploadPartCount);
|
|
|
|
|
2021-08-11 04:45:19 +00:00
|
|
|
const partEtags: PartEtag[] = [];
|
2021-08-09 15:15:11 +00:00
|
|
|
for (const [
|
|
|
|
index,
|
|
|
|
fileUploadURL,
|
|
|
|
] of multipartUploadURLs.partURLs.entries()) {
|
2021-08-10 05:36:03 +00:00
|
|
|
const uploadChunk = await combineChunksToFormUploadPart(streamReader);
|
2021-08-11 05:26:40 +00:00
|
|
|
const progressTracker = UIService.trackUploadProgress(
|
2021-08-11 04:45:19 +00:00
|
|
|
filename,
|
|
|
|
percentPerPart,
|
|
|
|
index,
|
|
|
|
);
|
|
|
|
|
|
|
|
const eTag = await NetworkClient.putFilePart(
|
|
|
|
fileUploadURL,
|
|
|
|
uploadChunk,
|
|
|
|
progressTracker,
|
|
|
|
);
|
|
|
|
partEtags.push({ PartNumber: index + 1, Etag: eTag });
|
2021-08-09 15:15:11 +00:00
|
|
|
}
|
|
|
|
await completeMultipartUpload(partEtags, multipartUploadURLs.completeURL);
|
|
|
|
return multipartUploadURLs.objectKey;
|
|
|
|
}
|
|
|
|
|
2021-08-11 04:45:19 +00:00
|
|
|
export function getRandomProgressPerPartUpload(uploadPartCount: number) {
|
2021-08-09 15:15:11 +00:00
|
|
|
const percentPerPart = Math.round(
|
|
|
|
RANDOM_PERCENTAGE_PROGRESS_FOR_PUT() / uploadPartCount,
|
|
|
|
);
|
|
|
|
return percentPerPart;
|
|
|
|
}
|
|
|
|
|
2021-08-11 04:45:19 +00:00
|
|
|
export async function combineChunksToFormUploadPart(
|
|
|
|
streamReader: ReadableStreamDefaultReader<Uint8Array>,
|
|
|
|
) {
|
2021-08-09 15:15:11 +00:00
|
|
|
const combinedChunks = [];
|
|
|
|
for (let i = 0; i < CHUNKS_COMBINED_FOR_A_UPLOAD_PART; i++) {
|
2021-08-11 04:45:19 +00:00
|
|
|
const { done, value: chunk } = await streamReader.read();
|
2021-08-09 15:15:11 +00:00
|
|
|
if (done) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for (let index = 0; index < chunk.length; index++) {
|
|
|
|
combinedChunks.push(chunk[index]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Uint8Array.from(combinedChunks);
|
|
|
|
}
|
|
|
|
|
2021-08-11 04:45:19 +00:00
|
|
|
async function completeMultipartUpload(
|
|
|
|
partEtags: PartEtag[],
|
|
|
|
completeURL: string,
|
|
|
|
) {
|
2021-08-09 15:15:11 +00:00
|
|
|
const options = { compact: true, ignoreComment: true, spaces: 4 };
|
|
|
|
const body = convert.js2xml(
|
|
|
|
{ CompleteMultipartUpload: { Part: partEtags } },
|
|
|
|
options,
|
|
|
|
);
|
|
|
|
await NetworkClient.completeMultipartUpload(completeURL, body);
|
|
|
|
}
|