pinus-robot
Version:
pinus-robot is a simple tool to benchmark the socket.io server's performance.
208 lines • 17.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.HTTP_SERVER = exports.HttpServer = void 0;
// ------------------------------------
// HTTP Server
// ------------------------------------
//
// This file defines HttpServer and the singleton HTTP_SERVER.
//
// This file defines a generic HTTP server that serves static files and that can be configured
// with new routes. It also starts the nodeload HTTP server unless require('nodeload/config')
// .disableServer() was called.
//
const http = require("http");
const fs = require("fs");
let qputs = console.log;
const events_1 = require("events");
const __ = require("underscore");
const monitor_1 = require("../monitor/monitor");
/** By default, HttpServer knows how to return static files from the current directory. Add new route
regexs using HttpServer.on(). */
class HttpServer extends events_1.EventEmitter {
constructor() {
super(...arguments);
this.routes = [];
this.running = false;
}
/** Start the server listening on the given port */
start(robotMasterUrl, port, hostname) {
if (this.running) {
return;
}
this.running = true;
this.robotMasterUrl = robotMasterUrl;
let self = this;
port = port || 8000;
self.hostname = hostname || 'localhost';
self.port = port;
self.connections = [];
self.server = http.createServer(function (req, res) { self.route_(req, res); });
self.server.on('connection', function (c) {
// We need to track incoming connections, beause Server.close() won't terminate active
// connections by default.
c.on('close', function () {
let idx = self.connections.indexOf(c);
if (idx !== -1) {
self.connections.splice(idx, 1);
}
});
self.connections.push(c);
});
self.server.listen(this.port, this.hostname);
self.emit('start', self.hostname, self.port);
return self;
}
/** Terminate the server */
stop() {
if (!this.running) {
return;
}
this.running = false;
this.connections.forEach(function (c) { c.destroy(); });
this.server.close();
this.server = null;
this.emit('end');
}
/** When an incoming request matches a given regex, route it to the provided handler:
function(url, ServerRequest, ServerResponse) */
addRoute(regex, handler) {
this.routes.unshift({ regex: regex, handler: handler });
return this;
}
removeRoute(regex, handler) {
this.routes = this.routes.filter(function (r) {
return !((regex === r.regex) && (!handler || handler === r.handler));
});
return this;
}
route_(req, res) {
for (let i = 0; i < this.routes.length; i++) {
if (req.url.match(this.routes[i].regex)) {
this.routes[i].handler(req.url, req, res);
return;
}
}
if (req.method === 'GET') {
this.serveFile_('.' + req.url, res);
}
else {
res.writeHead(405, { 'Content-Length': '0' });
res.end();
}
}
doReport(response) {
let pdata = (0, monitor_1.getData)();
// console.log('pdata %j',pdata);
let mdata = [];
let _show = false;
__.each(pdata, function (val, key) {
let single = {};
_show = true;
single['name'] = key;
single['uid'] = key;
let keycolumns = [];
let maxId = 0;
__.each(val, function (kval, akey) {
let _length = __.size(kval);
if (_length > maxId)
maxId = _length;
if (_length > 0)
keycolumns.push(akey);
});
let gcolumns = [];
gcolumns.push('users');
let glastkeyData = {};
__.each(keycolumns, function (dkey) { gcolumns.push(dkey); });
let grows = [];
for (let i = 0; i < maxId; i++) {
let rows = [];
rows.push(i + 1);
__.each(keycolumns, function (dkey) {
// console.log('dkey' + dkey + ' ' +i + JSON.stringify(val[dkey]))
rows.push(val[dkey][i] || 0);
// _vaild = true;
});
grows.push(rows);
}
let gsummary = {};
__.each(keycolumns, function (dkey) {
let summary = {};
let kdata = val[dkey];
let min = Number.MAX_VALUE, max = 0;
let sindex = 0, sum = 0;
__.each(kdata, function (time) {
if (time > max)
max = time;
if (time < min)
min = time;
sum += time;
++sindex;
});
let avg = Math.round(sum / sindex);
summary = { 'max': max, 'min': min, 'avg': avg, 'qs': Math.round(sindex * 1000 / avg) };
gsummary[dkey] = (summary);
});
single['summary'] = gsummary;
single['charts'] = { 'latency': { 'name': 'robot', 'uid': single['uid'], 'columns': gcolumns, 'rows': grows } };
if (grows.length > 0)
mdata.push(single);
});
if (_show) {
let data = JSON.stringify(mdata);
// response.writeHead(200, { 'Content-Length': pdata.length });
response.write(data, 'binary');
}
response.end();
}
serveFile_(basefile, response) {
if (basefile.lastIndexOf('report') !== -1) {
this.doReport(response);
return;
}
if (basefile === './')
basefile = 'index.html';
let file = __dirname + '/' + basefile;
fs.stat(file, (err, stat) => {
if (err) {
response.writeHead(404, { 'Content-Type': 'text/plain' });
response.write('Cannot find file: ' + file);
response.end();
return;
}
fs.readFile(file, 'binary', (err, data) => {
if (err) {
response.writeHead(500, { 'Content-Type': 'text/plain' });
response.write('Error opening file ' + file + ': ' + err);
}
else {
if (file.lastIndexOf('.html') === -1) {
if (basefile === './js/webclient.js') {
data = data.replace('${robotMasterUrl}', this.robotMasterUrl);
}
response.writeHead(200, { 'Content-Length': data.length });
response.write(data, 'binary');
}
else {
response.writeHead(200, { 'Content-Length': data.length, 'Content-Type': 'text/html; charset=utf-8' });
response.write(data, 'binary');
}
}
response.end();
});
});
}
}
exports.HttpServer = HttpServer;
// =================
// Singletons
// =================
/** The global HTTP server used by nodeload */
exports.HTTP_SERVER = new HttpServer();
exports.HTTP_SERVER.on('start', function (hostname, port) {
console.log(`Started Robot Master Http server on : http://${hostname}:${port}`);
});
exports.HTTP_SERVER.on('end', function () {
qputs('Shutdown Robot Master Http server.');
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2xpYi9jb25zb2xlL2h0dHAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsdUNBQXVDO0FBQ3ZDLGNBQWM7QUFDZCx1Q0FBdUM7QUFDdkMsRUFBRTtBQUNGLDhEQUE4RDtBQUM5RCxFQUFFO0FBQ0YsOEZBQThGO0FBQzlGLDZGQUE2RjtBQUM3RiwrQkFBK0I7QUFDL0IsRUFBRTtBQUNGLDZCQUE2QjtBQUM3Qix5QkFBeUI7QUFHekIsSUFBSSxLQUFLLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQztBQUN4QixtQ0FBc0M7QUFFdEMsaUNBQWlDO0FBQ2pDLGdEQUE2QztBQUM3QztnQ0FDZ0M7QUFFaEMsTUFBYSxVQUFXLFNBQVEscUJBQVk7SUFBNUM7O1FBS0ksV0FBTSxHQUF3QyxFQUFFLENBQUM7UUFDakQsWUFBTyxHQUFHLEtBQUssQ0FBQztJQW9LcEIsQ0FBQztJQWxLRyxtREFBbUQ7SUFDbkQsS0FBSyxDQUFDLGNBQXNCLEVBQUcsSUFBYSxFQUFFLFFBQWlCO1FBQzNELElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRTtZQUFFLE9BQU87U0FBRTtRQUM3QixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQztRQUNwQixJQUFJLENBQUMsY0FBYyxHQUFHLGNBQWMsQ0FBQztRQUVyQyxJQUFJLElBQUksR0FBRyxJQUFJLENBQUM7UUFDaEIsSUFBSSxHQUFHLElBQUksSUFBSSxJQUFJLENBQUM7UUFDcEIsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLElBQUksV0FBVyxDQUFDO1FBQ3hDLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO1FBQ2pCLElBQUksQ0FBQyxXQUFXLEdBQUcsRUFBRSxDQUFDO1FBRXRCLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxVQUFVLEdBQUcsRUFBRSxHQUFHLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxH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