Source: middleware/speed.js

"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;
};