|
import { execute } from "./utils"; |
|
import { CompletedPartList } from "aws-sdk/clients/s3"; |
|
|
|
const MinMultipartSize = 5 * 1024 ** 2; // 5MiB |
|
interface PartInfo { |
|
partNumber: number; |
|
rangeStart: number; |
|
rangeEnd: number; |
|
} |
|
|
|
execute(async (source, dest): Promise<void> => { |
|
const headObjectResponse = await source.instance |
|
.headObject({ |
|
Bucket: source.bucket, |
|
Key: source.key, |
|
}) |
|
.promise(); |
|
const { ContentType, ContentLength } = headObjectResponse; |
|
|
|
const createMultipartUploadResponse = await dest.instance |
|
.createMultipartUpload({ |
|
Bucket: dest.bucket, |
|
Key: dest.key, |
|
ContentType, |
|
}) |
|
.promise(); |
|
const UploadId = createMultipartUploadResponse?.UploadId ?? ""; |
|
console.log(`[CreateMultipartUpload] UploadId: ${UploadId}`); |
|
|
|
const objectSize: number = ContentLength ?? 0; |
|
const parts: PartInfo[] = Array.from({ length: Math.ceil(objectSize / MinMultipartSize) }).map( |
|
(_, i): PartInfo => ({ |
|
partNumber: i + 1, |
|
rangeStart: i * MinMultipartSize, |
|
rangeEnd: ((i + 1) * MinMultipartSize < objectSize ? (i + 1) * MinMultipartSize : objectSize) - 1, |
|
}), |
|
); |
|
|
|
const Parts: CompletedPartList = []; |
|
for await (const { partNumber, rangeStart, rangeEnd } of parts) { |
|
const getObjectResponse = await source.instance |
|
.getObject({ |
|
Bucket: source.bucket, |
|
Key: source.key, |
|
Range: `bytes=${rangeStart}-${rangeEnd}`, |
|
}) |
|
.promise(); |
|
const { Body } = getObjectResponse; |
|
console.log(`[GetObject #${partNumber}] ${rangeStart}-${rangeEnd} Bytes`); |
|
|
|
const uploadPartResponse = await dest.instance |
|
.uploadPart({ |
|
Bucket: dest.bucket, |
|
Key: dest.key, |
|
PartNumber: partNumber, |
|
UploadId, |
|
Body, |
|
}) |
|
.promise(); |
|
Parts.push({ |
|
ETag: uploadPartResponse.ETag, |
|
PartNumber: partNumber, |
|
}); |
|
console.log(`[UploadPart #${partNumber}] ${rangeStart}-${rangeEnd} Bytes, ETag: ${uploadPartResponse.ETag}`); |
|
} |
|
|
|
await dest.instance |
|
.completeMultipartUpload({ |
|
Bucket: dest.bucket, |
|
Key: dest.key, |
|
MultipartUpload: { Parts }, |
|
UploadId, |
|
}) |
|
.promise(); |
|
console.log(`[CompleteMultipartUpload] UploadId: ${UploadId}`); |
|
}); |