@rpldy/uploader
Version:
the processing and queuing engine for react-uploady
150 lines • 4.83 kB
JavaScript
import { logger, hasWindow, isFunction, scheduleIdleWork } from "@rpldy/shared";
import createState from "@rpldy/simple-state";
import { SENDER_EVENTS, UPLOADER_EVENTS } from "../consts";
import processQueueNext from "./processQueueNext";
import { processAbortItem, processAbortBatch, processAbortAll } from "./processAbort";
import { detachRecycledFromPreviousBatch, getBatchFromState, preparePendingForUpload, removePendingBatches, clearBatchData, cancelBatchWithId, triggerUploaderBatchEvent } from "./batchHelpers";
const createUploaderQueue = (options, trigger, cancellable, sender, uploaderId) => {
const {
state,
update
} = createState({
itemQueue: {},
batchQueue: [],
currentBatch: null,
batchesStartPending: [],
batches: {},
items: {},
activeIds: [],
aborts: {}
});
const getState = () => state;
const updateState = updater => {
update(updater);
};
const add = item => {
if (state.items[item.id] && !item.recycled) {
throw new Error(`Uploader queue conflict - item ${item.id} already exists`);
}
if (item.recycled) {
detachRecycledFromPreviousBatch(queueState, item);
}
updateState(state => {
state.items[item.id] = item;
});
};
const handleItemProgress = (item, completed, loaded, total) => {
if (state.items[item.id]) {
updateState(state => {
const stateItem = state.items[item.id];
stateItem.loaded = loaded;
stateItem.completed = completed;
stateItem.total = total;
});
trigger(UPLOADER_EVENTS.ITEM_PROGRESS, getState().items[item.id]);
}
};
sender.on(SENDER_EVENTS.ITEM_PROGRESS, handleItemProgress);
sender.on(SENDER_EVENTS.BATCH_PROGRESS, batch => {
const batchItems = state.batches[batch.id]?.batch.items;
if (batchItems) {
const [loaded, total] = batchItems.reduce((res, {
id
}) => {
const {
loaded,
file
} = state.items[id];
const size = file?.size || loaded || 1;
res[0] += loaded;
res[1] += size;
return res;
}, [0, 0]);
updateState(state => {
const stateBatch = state.batches[batch.id].batch;
stateBatch.total = total;
stateBatch.loaded = loaded;
stateBatch.completed = loaded / total;
});
triggerUploaderBatchEvent(queueState, batch.id, UPLOADER_EVENTS.BATCH_PROGRESS);
}
});
const queueState = {
uploaderId,
getOptions: () => options,
getCurrentActiveCount: () => state.activeIds.length,
getState,
updateState,
trigger,
runCancellable: (name, ...args) => {
if (!isFunction(cancellable)) {
throw new Error("Uploader queue - cancellable is of wrong type");
}
return cancellable(name, ...args);
},
sender,
handleItemProgress,
clearAllUploads: () => {
queueState.updateState(state => {
state.itemQueue = {};
state.batchQueue = [];
state.currentBatch = null;
state.batches = {};
state.items = {};
state.activeIds = [];
});
},
clearBatchUploads: batchId => {
scheduleIdleWork(() => {
logger.debugLog(`uploader.queue: started scheduled work to clear batch uploads (${batchId})`);
if (getState().batches[batchId]) {
clearBatchData(queueState, batchId);
}
});
}
};
if (hasWindow() && logger.isDebugOn()) {
window[`__rpldy_${uploaderId}_queue_state`] = queueState;
}
return {
updateState,
getState: queueState.getState,
runCancellable: queueState.runCancellable,
uploadBatch: (batch, batchOptions) => {
if (batchOptions) {
updateState(state => {
state.batches[batch.id].batchOptions = batchOptions;
});
}
processQueueNext(queueState);
},
addBatch: (batch, batchOptions) => {
updateState(state => {
state.batches[batch.id] = {
batch,
batchOptions,
itemBatchOptions: {},
finishedCounter: 0
};
state.batchQueue.push(batch.id);
state.itemQueue[batch.id] = batch.items.map(({
id
}) => id);
});
batch.items.forEach(add);
return getBatchFromState(state, batch.id);
},
abortItem: (...args) => processAbortItem(queueState, ...args),
abortBatch: (...args) => processAbortBatch(queueState, ...args),
abortAll: (...args) => processAbortAll(queueState, ...args),
clearPendingBatches: () => {
removePendingBatches(queueState);
},
uploadPendingBatches: uploadOptions => {
preparePendingForUpload(queueState, uploadOptions);
processQueueNext(queueState);
},
cancelBatch: batch => cancelBatchWithId(queueState, batch.id)
};
};
export default createUploaderQueue;