UNPKG

@uppy/utils

Version:

Shared utility functions for Uppy Core and plugins maintained by the Uppy team.

304 lines (302 loc) 11.5 kB
function _classPrivateFieldLooseBase(e, t) { if (!{}.hasOwnProperty.call(e, t)) throw new TypeError("attempted to use private field on non-instance"); return e; } var id = 0; function _classPrivateFieldLooseKey(e) { return "__private_" + id++ + "_" + e; } function createCancelError(cause) { return new Error('Cancelled', { cause }); } function abortOn(signal) { if (signal != null) { var _this$then; const abortPromise = () => this.abort(signal.reason); signal.addEventListener('abort', abortPromise, { once: true }); const removeAbortListener = () => { signal.removeEventListener('abort', abortPromise); }; (_this$then = this.then) == null || _this$then.call(this, removeAbortListener, removeAbortListener); } return this; } var _activeRequests = /*#__PURE__*/_classPrivateFieldLooseKey("activeRequests"); var _queuedHandlers = /*#__PURE__*/_classPrivateFieldLooseKey("queuedHandlers"); var _paused = /*#__PURE__*/_classPrivateFieldLooseKey("paused"); var _pauseTimer = /*#__PURE__*/_classPrivateFieldLooseKey("pauseTimer"); var _downLimit = /*#__PURE__*/_classPrivateFieldLooseKey("downLimit"); var _upperLimit = /*#__PURE__*/_classPrivateFieldLooseKey("upperLimit"); var _rateLimitingTimer = /*#__PURE__*/_classPrivateFieldLooseKey("rateLimitingTimer"); var _call = /*#__PURE__*/_classPrivateFieldLooseKey("call"); var _queueNext = /*#__PURE__*/_classPrivateFieldLooseKey("queueNext"); var _next = /*#__PURE__*/_classPrivateFieldLooseKey("next"); var _queue = /*#__PURE__*/_classPrivateFieldLooseKey("queue"); var _dequeue = /*#__PURE__*/_classPrivateFieldLooseKey("dequeue"); var _resume = /*#__PURE__*/_classPrivateFieldLooseKey("resume"); var _increaseLimit = /*#__PURE__*/_classPrivateFieldLooseKey("increaseLimit"); export class RateLimitedQueue { constructor(limit) { Object.defineProperty(this, _dequeue, { value: _dequeue2 }); Object.defineProperty(this, _queue, { value: _queue2 }); Object.defineProperty(this, _next, { value: _next2 }); Object.defineProperty(this, _queueNext, { value: _queueNext2 }); Object.defineProperty(this, _call, { value: _call2 }); Object.defineProperty(this, _activeRequests, { writable: true, value: 0 }); Object.defineProperty(this, _queuedHandlers, { writable: true, value: [] }); Object.defineProperty(this, _paused, { writable: true, value: false }); Object.defineProperty(this, _pauseTimer, { writable: true, value: void 0 }); Object.defineProperty(this, _downLimit, { writable: true, value: 1 }); Object.defineProperty(this, _upperLimit, { writable: true, value: void 0 }); Object.defineProperty(this, _rateLimitingTimer, { writable: true, value: void 0 }); Object.defineProperty(this, _resume, { writable: true, value: () => this.resume() }); Object.defineProperty(this, _increaseLimit, { writable: true, value: () => { if (_classPrivateFieldLooseBase(this, _paused)[_paused]) { _classPrivateFieldLooseBase(this, _rateLimitingTimer)[_rateLimitingTimer] = setTimeout(_classPrivateFieldLooseBase(this, _increaseLimit)[_increaseLimit], 0); return; } _classPrivateFieldLooseBase(this, _downLimit)[_downLimit] = this.limit; this.limit = Math.ceil((_classPrivateFieldLooseBase(this, _upperLimit)[_upperLimit] + _classPrivateFieldLooseBase(this, _downLimit)[_downLimit]) / 2); for (let i = _classPrivateFieldLooseBase(this, _downLimit)[_downLimit]; i <= this.limit; i++) { _classPrivateFieldLooseBase(this, _queueNext)[_queueNext](); } if (_classPrivateFieldLooseBase(this, _upperLimit)[_upperLimit] - _classPrivateFieldLooseBase(this, _downLimit)[_downLimit] > 3) { _classPrivateFieldLooseBase(this, _rateLimitingTimer)[_rateLimitingTimer] = setTimeout(_classPrivateFieldLooseBase(this, _increaseLimit)[_increaseLimit], 2000); } else { _classPrivateFieldLooseBase(this, _downLimit)[_downLimit] = Math.floor(_classPrivateFieldLooseBase(this, _downLimit)[_downLimit] / 2); } } }); if (typeof limit !== 'number' || limit === 0) { this.limit = Infinity; } else { this.limit = limit; } } run(fn, queueOptions) { if (!_classPrivateFieldLooseBase(this, _paused)[_paused] && _classPrivateFieldLooseBase(this, _activeRequests)[_activeRequests] < this.limit) { return _classPrivateFieldLooseBase(this, _call)[_call](fn); } return _classPrivateFieldLooseBase(this, _queue)[_queue](fn, queueOptions); } wrapSyncFunction(fn, queueOptions) { var _this = this; return function () { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } const queuedRequest = _this.run(() => { fn(...args); queueMicrotask(() => queuedRequest.done()); return () => {}; }, queueOptions); return { abortOn, abort() { queuedRequest.abort(); } }; }; } wrapPromiseFunction(fn, queueOptions) { var _this2 = this; return function () { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } let queuedRequest; const outerPromise = new Promise((resolve, reject) => { queuedRequest = _this2.run(() => { let cancelError; let innerPromise; try { innerPromise = Promise.resolve(fn(...args)); } catch (err) { innerPromise = Promise.reject(err); } innerPromise.then(result => { if (cancelError) { reject(cancelError); } else { queuedRequest.done(); resolve(result); } }, err => { if (cancelError) { reject(cancelError); } else { queuedRequest.done(); reject(err); } }); return cause => { cancelError = createCancelError(cause); }; }, queueOptions); }); outerPromise.abort = cause => { queuedRequest.abort(cause); }; outerPromise.abortOn = abortOn; return outerPromise; }; } resume() { _classPrivateFieldLooseBase(this, _paused)[_paused] = false; clearTimeout(_classPrivateFieldLooseBase(this, _pauseTimer)[_pauseTimer]); for (let i = 0; i < this.limit; i++) { _classPrivateFieldLooseBase(this, _queueNext)[_queueNext](); } } /** * Freezes the queue for a while or indefinitely. * * @param {number | null } [duration] Duration for the pause to happen, in milliseconds. * If omitted, the queue won't resume automatically. */ pause(duration) { if (duration === void 0) { duration = null; } _classPrivateFieldLooseBase(this, _paused)[_paused] = true; clearTimeout(_classPrivateFieldLooseBase(this, _pauseTimer)[_pauseTimer]); if (duration != null) { _classPrivateFieldLooseBase(this, _pauseTimer)[_pauseTimer] = setTimeout(_classPrivateFieldLooseBase(this, _resume)[_resume], duration); } } /** * Pauses the queue for a duration, and lower the limit of concurrent requests * when the queue resumes. When the queue resumes, it tries to progressively * increase the limit in `this.#increaseLimit` until another call is made to * `this.rateLimit`. * Call this function when using the RateLimitedQueue for network requests and * the remote server responds with 429 HTTP code. * * @param {number} duration in milliseconds. */ rateLimit(duration) { clearTimeout(_classPrivateFieldLooseBase(this, _rateLimitingTimer)[_rateLimitingTimer]); this.pause(duration); if (this.limit > 1 && Number.isFinite(this.limit)) { _classPrivateFieldLooseBase(this, _upperLimit)[_upperLimit] = this.limit - 1; this.limit = _classPrivateFieldLooseBase(this, _downLimit)[_downLimit]; _classPrivateFieldLooseBase(this, _rateLimitingTimer)[_rateLimitingTimer] = setTimeout(_classPrivateFieldLooseBase(this, _increaseLimit)[_increaseLimit], duration); } } get isPaused() { return _classPrivateFieldLooseBase(this, _paused)[_paused]; } } function _call2(fn) { _classPrivateFieldLooseBase(this, _activeRequests)[_activeRequests] += 1; let done = false; let cancelActive; try { cancelActive = fn(); } catch (err) { _classPrivateFieldLooseBase(this, _activeRequests)[_activeRequests] -= 1; throw err; } return { abort: cause => { if (done) return; done = true; _classPrivateFieldLooseBase(this, _activeRequests)[_activeRequests] -= 1; cancelActive == null || cancelActive(cause); _classPrivateFieldLooseBase(this, _queueNext)[_queueNext](); }, done: () => { if (done) return; done = true; _classPrivateFieldLooseBase(this, _activeRequests)[_activeRequests] -= 1; _classPrivateFieldLooseBase(this, _queueNext)[_queueNext](); } }; } function _queueNext2() { // Do it soon but not immediately, this allows clearing out the entire queue synchronously // one by one without continuously _advancing_ it (and starting new tasks before immediately // aborting them) queueMicrotask(() => _classPrivateFieldLooseBase(this, _next)[_next]()); } function _next2() { if (_classPrivateFieldLooseBase(this, _paused)[_paused] || _classPrivateFieldLooseBase(this, _activeRequests)[_activeRequests] >= this.limit) { return; } if (_classPrivateFieldLooseBase(this, _queuedHandlers)[_queuedHandlers].length === 0) { return; } // Dispatch the next request, and update the abort/done handlers // so that cancelling it does the Right Thing (and doesn't just try // to dequeue an already-running request). const next = _classPrivateFieldLooseBase(this, _queuedHandlers)[_queuedHandlers].shift(); if (next == null) { throw new Error('Invariant violation: next is null'); } const handler = _classPrivateFieldLooseBase(this, _call)[_call](next.fn); next.abort = handler.abort; next.done = handler.done; } function _queue2(fn, options) { const handler = { fn, priority: (options == null ? void 0 : options.priority) || 0, abort: () => { _classPrivateFieldLooseBase(this, _dequeue)[_dequeue](handler); }, done: () => { throw new Error('Cannot mark a queued request as done: this indicates a bug'); } }; const index = _classPrivateFieldLooseBase(this, _queuedHandlers)[_queuedHandlers].findIndex(other => { return handler.priority > other.priority; }); if (index === -1) { _classPrivateFieldLooseBase(this, _queuedHandlers)[_queuedHandlers].push(handler); } else { _classPrivateFieldLooseBase(this, _queuedHandlers)[_queuedHandlers].splice(index, 0, handler); } return handler; } function _dequeue2(handler) { const index = _classPrivateFieldLooseBase(this, _queuedHandlers)[_queuedHandlers].indexOf(handler); if (index !== -1) { _classPrivateFieldLooseBase(this, _queuedHandlers)[_queuedHandlers].splice(index, 1); } } export const internalRateLimitedQueue = Symbol('__queue');