"use strict"; const Promise = require("bluebird"); const pDefer = require("p-defer"); const defaultValue = require("default-value"); const pListen = require("p-listen"); module.exports = function createRequestQueue(options = {}) { // FIXME: Validatem, docs let requestBuffer = []; let responseBuffer = []; let seenError; let requestDrainListener = pListen(); let responseDrainListener = pListen(); function failAllRequests(error) { let failedRequests = requestBuffer; requestBuffer = []; seenError = error; for (let request of failedRequests) { request.reject(error); } } function handleOnMatch() { return Promise.try(() => { if (requestBuffer.length === 0) { requestDrainListener.notify(); } if (responseBuffer.length === 0) { responseDrainListener.notify(); } return maybeCall(options.onMatch); }).catch((error) => { failAllRequests(error); }); } function maybeCall(func, ... args) { if (func != null) { return func(... args); } } return { pushRequest: function (onQueuedRequest) { if (responseBuffer.length > 0) { let returnValue = Promise.resolve(responseBuffer.shift()); handleOnMatch(); return returnValue; } else if (seenError !== undefined) { return Promise.reject(seenError); } else { let { resolve, reject, promise } = pDefer(); requestBuffer.push({ resolve, reject }); return Promise.try(() => { return maybeCall(defaultValue(onQueuedRequest, options.onQueuedRequest)); }).then(() => { return promise; }); } }, pushResponse: function (response, onQueuedResponse) { if (requestBuffer.length > 0) { let request = requestBuffer.shift(); request.resolve(response); handleOnMatch(); } else { responseBuffer.push(response); return maybeCall(defaultValue(onQueuedResponse, options.onQueuedResponse)); } }, failAllRequests: failAllRequests, requestCount: function () { return requestBuffer.length; }, responseCount: function () { return responseBuffer.length; }, awaitRequestDrain: function () { if (this.requestCount() === 0) { return Promise.resolve(); } else { return requestDrainListener.listen(); } }, awaitResponseDrain: function () { if (this.responseCount() === 0) { return Promise.resolve(); } else { return responseDrainListener.listen(); } } }; };