@rpldy/chunked-sender
Version:
adds chunked upload capabilities on top of the regular XHR uploads
84 lines • 3.02 kB
JavaScript
import { FILE_STATES, logger } from "@rpldy/shared";
import ChunkedSendError from "./ChunkedSendError";
import handleChunkRequest from "./handleChunkRequest";
import getChunksToSend from "./getChunksToSend";
import sendChunk from "./sendChunk";
const resolveOnError = (chunkedState, resolve, ex) => {
if (ex instanceof ChunkedSendError) {
const chunkError = chunkedState.getState().lastChunkErrorData;
resolve({
state: FILE_STATES.ERROR,
response: {
reason: "At least one chunk failed",
chunkUploadResponse: chunkError
}
});
} else {
resolve({
state: FILE_STATES.ERROR,
response: ex.message
});
}
};
const finalizeOnFinish = (chunkedState, item, resolve, status) => {
chunkedState.updateState(state => {
state.finished = true;
});
resolve({
state: status,
response: {
results: chunkedState.getState().responses
}
});
};
const resolveOnAllChunksFinished = (chunkedState, item, resolve) => {
const state = chunkedState.getState();
const finished = !state.chunks.length;
if (state.aborted) {
logger.debugLog(`chunkedSender: chunked upload aborted for item: ${item.id}`);
finalizeOnFinish(chunkedState, item, resolve, FILE_STATES.ABORTED);
} else if (finished && !state.error) {
logger.debugLog(`chunkedSender: chunked upload finished for item: ${item.id}`, state.responses);
finalizeOnFinish(chunkedState, item, resolve, FILE_STATES.FINISHED);
}
return finished || state.error;
};
export const handleChunk = (chunkedState, item, onProgress, chunkResolve, chunk, trigger) => new Promise((resolve, reject) => {
try {
const chunkSendResult = sendChunk(chunk, chunkedState, item, onProgress, trigger);
handleChunkRequest(chunkedState, item, chunk.id, chunkSendResult, trigger, onProgress).then(() => {
resolve();
if (!resolveOnAllChunksFinished(chunkedState, item, chunkResolve)) {
sendChunks(chunkedState, item, onProgress, chunkResolve, trigger);
}
});
} catch (ex) {
reject(ex);
}
});
const sendChunks = (chunkedState, item, onProgress, resolve, trigger) => {
const state = chunkedState.getState();
if (!state.finished && !state.aborted) {
const inProgress = Object.keys(state.requests).length;
if (!inProgress || state.parallel && state.parallel > inProgress) {
let chunks;
try {
chunks = getChunksToSend(chunkedState);
} catch (ex) {
resolveOnError(chunkedState, resolve, ex);
}
if (chunks) {
logger.debugLog(`chunkedSender: about to send ${chunks.length} chunks for item: ${item.id} with parallel: ${state.parallel}`);
chunks.forEach(chunk => {
handleChunk(chunkedState, item, onProgress, resolve, chunk, trigger).catch(ex => {
chunkedState.updateState(state => {
state.error = true;
});
resolveOnError(chunkedState, resolve, ex);
});
});
}
}
}
};
export default sendChunks;