@ganache/utils
Version:
Utility functions for @ganache packages
129 lines • 6.08 kB
JavaScript
"use strict";
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var _RequestCoordinator_paused, _RequestCoordinator_process;
Object.defineProperty(exports, "__esModule", { value: true });
exports.RequestCoordinator = void 0;
const noop = () => { };
/**
* Responsible for managing global concurrent requests.
*/
class RequestCoordinator {
get paused() {
return __classPrivateFieldGet(this, _RequestCoordinator_paused, "f");
}
/**
* Promise-based FIFO queue.
* @param limit - The number of requests that can be processed at a time.
* Default value is is no limit (`0`).
*/
constructor(limit) {
/**
* The pending requests. You can't do anything with this array.
*/
this.pending = [];
/**
* The number of tasks currently being processed.
*/
this.runningTasks = 0;
_RequestCoordinator_paused.set(this, true);
/**
* Pause processing. This will *not* cancel any promises that are currently
* running.
*/
this.pause = () => {
__classPrivateFieldSet(this, _RequestCoordinator_paused, true, "f");
};
/**
* Resume processing.
*/
this.resume = () => {
__classPrivateFieldSet(this, _RequestCoordinator_paused, false, "f");
__classPrivateFieldGet(this, _RequestCoordinator_process, "f").call(this);
};
_RequestCoordinator_process.set(this, () => {
// if we aren't paused and the number of things we're processing is under
// our limit and we have things to process: do it!
while (!this.paused &&
this.pending.length > 0 &&
(!this.limit || this.runningTasks < this.limit)) {
const current = this.pending.shift();
this.runningTasks++;
current
.execute()
// By now, we've resolved the fn's `value` by sending it to the parent scope.
// But over here, we're also waiting for this fn's _value_ to settle _itself_ (it might be a promise) before
// continuing through the `pending` queue. Because we wait for it again here, it could potentially throw here,
// in which case we just need to catch it and throw the result away. We could probably use
// `Promise.allSettled([current()]).finally` to do this instead of the `current().catch(noop).finally`. /shrug
.catch(noop)
.finally(() => {
this.runningTasks--;
__classPrivateFieldGet(this, _RequestCoordinator_process, "f").call(this);
});
}
});
/**
* Insert a new function into the queue.
*/
this.queue = (fn, thisArgument, argumentsList) => {
return new Promise((resolve, reject) => {
// const execute is `async` to force the return value into a Promise.
const execute = async () => {
try {
const value = Reflect.apply(fn, thisArgument, argumentsList || []);
resolve({ value });
return value;
}
catch (e) {
reject(e);
}
};
this.pending.push({ execute, reject });
__classPrivateFieldGet(this, _RequestCoordinator_process, "f").call(this);
});
};
this.limit = limit;
}
/**
* Stop processing tasks - calls to queue(), and resume() will reject with an
* error indicating that Ganache is disconnected. This is an irreversible
* action. If you wish to be able to resume processing, use pause() instead.
*
* Note: this changes the references of this.resume and this.queue. Any code
* that maintains references to the values referenced by this.resume or
* this.queue, could have unintended consequences after calling this.stop().
*/
stop() {
this.pause();
this.resume = () => {
throw new Error("Cannot resume processing requests, Ganache is disconnected.");
};
this.queue = async () => {
throw new Error("Cannot process request, Ganache is disconnected.");
};
}
/**
* Finalise shutdown of the RequestCoordinator. Rejects all pending tasks in order. Should be
* called after all in-flight tasks have resolved in order to maintain overall FIFO order.
*/
end() {
while (this.pending.length > 0) {
this.pending
.shift()
.reject(new Error("Cannot process request, Ganache is disconnected."));
}
}
}
exports.RequestCoordinator = RequestCoordinator;
_RequestCoordinator_paused = new WeakMap(), _RequestCoordinator_process = new WeakMap();
//# sourceMappingURL=request-coordinator.js.map