I have a scenario where I need to upload a series of files to a web server sequentially, with chunking involved for each file. The upload process is quite simple when implemented procedurally, and looks approximately like:
foreach file in files:
const result = await createMultipartUpload();
do {
const chunk = takeChunk();
const result = await uploadChunk(chunk);
chunksRemain = doChunksRemain();
} while (chunksRemain);
await completeUpload();
That is, for each sequential upload process, a single creation request occurs, multiple chunks are uploaded sequentially—but I don't know how many chunks will be uploaded—and then a single completion request occurs.
I need to convert this into reactive code with RxJs. What I have actually works for single-chunk uploads, where only one chunk is needed. But I haven't figured out how dynamically generate the upload chunk observables and push them onto some kind of array that they can then be retrieved from.
Here's what I have so far:
// Contains single request.
public createMultipartUpload(file: File): Observable<File> {
return this.filesHttp.store(file);
}
// Contains two HTTP requests. Generates a presigned URL, then uploads the chunk with the presaged URL.
public uploadChunk(file: File): Observable<File> {
let chunk: Blob;
// Determine the bytes of the file to take and assign to chunk.
if (file.originalFile.size < this.chunkSize) {
chunk = file.originalFile;
} else {
chunk = file.originalFile.slice(file.currentByteOffset, file.currentByteOffset + this.chunkSize);
}
return this.filesHttp.getPresignedUrlForUpload(file)
.pipe(
concatMap(res => {
return this.filesHttp.upload(res.uri, chunk);
}),
map(f => {
// Set next chunk to take
f.currentByteOffset += this.chunkSize;
return f;
})
);
}
public completeUpload(file: File): Observable<MultipartCompletionResponse> {
return this.filesHttp.complete(file);
}
from(this.files)
.pipe(
concatMap(f => this.createMultipartUpload(f)),
switchMap(f => this.uploadChunk(f)),
concatMap(f => this.completeUpload(f))
).subscribe(output => {
// done?
});
How can I sequentially upload all chunks, and not just the first one, given this scenario?