/** * @summary middleware * @version 3.0.0 * @since 1.0.0 * @author Arian Khosravi <arian.khosravi@aofl.com> */ /** * @memberof module:@aofl/middleware */ class Middleware { /** * Creates an instance of Middleware. * * @param {Object} middleware */ constructor(...hooks) { this.middleware = {}; for (let i = 0; i < hooks.length; i++) { this.middleware[hooks[i]] = []; } } /** * @param {Function} callback * @param {String} hook */ use(callback, hook) { if (typeof callback !== 'function') { throw new Error('callback must be a function'); } if (typeof this.middleware[hook] === 'undefined') { throw new Error(`Only ${Object.keys(this.middleware)} hooks are supported.`); } this.middleware[hook].push({ callback, hook }); return this.createUnsubscribeFn(hook, callback); } /** * @param {String} hook * @return {Iterator} */ getMiddlewareIterator(hook) { const collection = this.middleware[hook]; let nextIndex = 0; return { next() { if (nextIndex < collection.length) { return { value: collection[nextIndex++], done: false }; } return { done: true }; } }; } /** * @param {*} request * @param {String} hook * @param {*} response * @return {Promise} */ iterateMiddleware(request, hook, response = null) { return new Promise((resolve) => { const iterator = this.getMiddlewareIterator(hook); let mw = null; const next = (/* istanbul ignore next */argResponse = null) => { mw = iterator.next(); if (mw.done !== true) { mw.value.callback(request, argResponse, next); } else { resolve(argResponse); } }; next(response); }); } /** * Creates an unsubscribe function * * @private * @param {String} hook * @param {function} callback */ createUnsubscribeFn(hook, callback) { const unsubscribe = () => { if (unsubscribe.executed) { return; } Object.defineProperty(unsubscribe, 'executed', { value: true }); for (let i = 0; i < this.middleware[hook].length; i++) { if (callback === this.middleware[hook][i].callback) { this.middleware[hook].splice(i, 1); break; } } }; return unsubscribe; } } export { Middleware };