"use strict";
/**
* Middleware to manage responses speed.
*
* @module
*/
var U = require("glace-utils");
var MAX_PACKAGE_SIZE = 8192; // empirical value
var self = module.exports = function () {
self.__changeReqSpeed(this);
self.__changeResSpeed(this);
return false;
};
/**
* Helper to change requests speed.
*
* @ignore
* @function
* @arg {BaseProxy} ctx - Proxy instance.
*/
self.__changeReqSpeed = ctx => {
if (ctx.reqSpeed == null) return;
var req = ctx.req;
var timer = 1000;
var size = Math.ceil(ctx.reqSpeed * 128);
var prms = Promise.resolve();
[size, timer] = self.__balance(size, timer);
var promisify = self.__promisify(size, timer);
var emit = req.emit;
req.emit = function (ev, chunk) {
if (!["data", "end"].includes(ev)) {
return emit.apply(this, arguments);
};
if (size === 0) return; // reject requests if speed is zero
prms = promisify(prms, chunk, chk => {
return emit.call(this, "data", chk);
});
if (ev === "end") {
prms = prms.then(() => {
return emit.call(this, "end");
});
};
return prms;
};
};
/**
* Helper to change responses speed.
*
* @ignore
* @function
* @arg {BaseProxy} ctx - Proxy instance.
*/
self.__changeResSpeed = ctx => {
if (ctx.resSpeed == null) return;
var res = ctx.res;
var timer = 1000;
var size = Math.ceil(ctx.resSpeed * 128);
var prms = Promise.resolve();
[size, timer] = self.__balance(size, timer);
var promisify = self.__promisify(size, timer);
var write = res.write;
res.write = function () {
if (size === 0) return; // reject responses if speed is zero
var args = Array.from(arguments);
prms = promisify(prms, args[0], chk => {
args[0] = chk;
return write.apply(this, args);
});
return prms;
};
var end = res.end;
res.end = function () {
if (size === 0) return; // reject responses if speed is zero
var args = Array.from(arguments);
prms = promisify(prms, args[0], chk => {
args[0] = chk;
return write.apply(this, args);
});
return prms.then(() => {
args[0] = null;
return end.apply(res, args);
});
};
};
/**
* Helper to balance data size and throttle time.
*
* @ignore
* @function
* @arg {number} size - Data size, bytes.
* @arg {number} timer - Throttle time, ms.
* @return {number[]} Balanced size and timer.
*/
self.__balance = (size, timer) => {
while (size > MAX_PACKAGE_SIZE) {
size = Math.ceil(size / 2);
timer = Math.ceil(timer / 2);
};
return [size, timer];
};
/**
* Helper to promisify requests and responses with size and time.
*
* @ignore
* @function
* @arg {number} size - Data size, bytes.
* @arg {number} timer - Throttle time, ms.
* @return {function} Function to promisify request or response.
*/
self.__promisify = (size, timer) => (prms, chunk, cb) => {
if (!chunk) return prms;
for (var i = 0; i < chunk.length; i += size) {
prms = prms
.then(() => U.sleep(timer))
.then((idx => () => cb(chunk.slice(idx, idx + size)))(i));
};
return prms;
};