@rpldy/uploader
Version:
the processing and queuing engine for react-uploady
144 lines • 4.54 kB
JavaScript
import { FILE_STATES, logger } from "@rpldy/shared";
import { UPLOADER_EVENTS } from "../consts";
import processFinishedRequest from "./processFinishedRequest";
import { getItemsPrepareUpdater } from "./preSendPrepare";
import { getIsItemFinalized } from "./itemHelpers";
import { getBatchDataFromItemId } from "./batchHelpers";
const preparePreRequestItems = getItemsPrepareUpdater(UPLOADER_EVENTS.REQUEST_PRE_SEND, items => items, (items, options) => ({
items,
options
}));
const updateUploadingState = (queue, items, sendResult) => {
queue.updateState(state => {
items.forEach(bi => {
const item = state.items[bi.id];
item.state = FILE_STATES.UPLOADING;
state.aborts[bi.id] = sendResult.abort;
});
});
};
const sendAllowedItems = (queue, itemsSendData, next) => {
const {
items,
options
} = itemsSendData;
const batch = queue.getState().batches[items[0].batchId]?.batch;
if (batch) {
let sendResult;
try {
sendResult = queue.sender.send(items, batch, options);
} catch (ex) {
logger.debugLog(`uploader.queue: sender failed with unexpected error`, ex);
sendResult = {
request: Promise.resolve({
status: 0,
state: FILE_STATES.ERROR,
response: ex.message
}),
abort: () => false,
senderType: "exception-handler"
};
}
const {
request
} = sendResult;
updateUploadingState(queue, items, sendResult);
request.then(requestInfo => {
const finishedData = items.map(item => ({
id: item.id,
info: requestInfo
}));
processFinishedRequest(queue, finishedData, next);
});
}
};
const reportCancelledItems = (queue, items, cancelledResults, next) => {
const cancelledItemsIds = cancelledResults.map((isCancelled, index) => isCancelled ? items[index].id : null).filter(Boolean);
if (cancelledItemsIds.length) {
const finishedData = cancelledItemsIds.map(id => ({
id,
info: {
status: 0,
state: FILE_STATES.CANCELLED,
response: "cancel"
}
}));
processFinishedRequest(queue, finishedData, next);
}
return !!cancelledItemsIds.length;
};
const reportPreparedError = (error, queue, items, next) => {
const finishedData = items.map(({
id
}) => ({
id,
info: {
status: 0,
state: FILE_STATES.ERROR,
response: error
}
}));
processFinishedRequest(queue, finishedData, next);
};
const getAllowedItem = (id, queue) => {
const item = queue.getState().items[id];
return item && !getIsItemFinalized(item) ? item : undefined;
};
const processAllowedItems = ({
allowedItems,
cancelledResults,
queue,
items,
ids,
next
}) => {
const afterPreparePromise = allowedItems.length ? preparePreRequestItems(queue, allowedItems) : Promise.resolve();
let finalCancelledResults = cancelledResults;
return afterPreparePromise.catch(err => {
logger.debugLog("uploader.queue: encountered error while preparing items for request", err);
reportPreparedError(err, queue, items, next);
}).then(itemsSendData => {
let nextP;
if (itemsSendData) {
if (itemsSendData.cancelled) {
finalCancelledResults = ids.map(() => true);
} else {
const hasAborted = itemsSendData.items.some(item => getIsItemFinalized(item));
if (!hasAborted) {
sendAllowedItems(queue, {
items: itemsSendData.items,
options: itemsSendData.options
}, next);
} else {
logger.debugLog("uploader.queue: send data contains aborted items - not sending");
}
}
}
if (!reportCancelledItems(queue, items, finalCancelledResults, next)) {
nextP = next(queue);
}
return nextP;
});
};
const processBatchItems = (queue, ids, next) => {
const state = queue.getState();
let items = Object.values(state.items);
items = items.filter(item => ids.includes(item.id) && !getIsItemFinalized(item));
return Promise.all(items.map(i => {
const {
batchOptions
} = getBatchDataFromItemId(queue, i.id);
return queue.runCancellable(UPLOADER_EVENTS.ITEM_START, i, batchOptions);
})).then(cancelledResults => {
let allowedItems = cancelledResults.map((isCancelled, index) => isCancelled ? null : getAllowedItem(items[index].id, queue)).filter(Boolean);
return {
allowedItems,
cancelledResults,
queue,
items,
ids,
next
};
}).then(processAllowedItems);
};
export default processBatchItems;