Vulture/VApp/node_modules/ping/lib/parser/base.js

193 lines
5.1 KiB
JavaScript
Raw Normal View History

'use strict';
/* eslint no-unused-vars: 0 */
/**
* Parsed response
* @typedef {object} PingResponse
* @param {string} inputHost - The input IP address or HOST
* @param {string} host - The input IP address or HOST
* @param {string} numeric_host - Target IP address
* @param {boolean} alive - True for existed host
* @param {string} output - Raw stdout from system ping
* @param {number} time - Time (float) in ms for first successful ping response
* @param {string} min - Minimum time for collection records
* @param {string} max - Maximum time for collection records
* @param {string} avg - Average time for collection records
* @param {number} packetLoss - Packet Losses in percent (number)
* @param {string} stddev - Standard deviation time for collected records
*/
/**
* @constructor
* @param {string} addr - Hostname or ip addres
* @param {PingConfig} config - Config object in probe()
*/
function parser(addr, config) {
// Initial state is 0
this._state = 0;
// Initial cache value
this._response = {
inputHost: addr,
host: 'unknown',
alive: false,
output: 'unknown',
time: 'unknown',
times: [],
min: 'unknown',
max: 'unknown',
avg: 'unknown',
stddev: 'unknown',
packetLoss: 'unknown',
};
// Initial times storage for ping time
this._times = [];
// Initial lines storage for ping output
this._lines = [];
// strip string regexp
this._stripRegex = /[ ]*\r?\n?$/g;
// Ping Config
this._pingConfig = config || {};
}
/**
* Enum for parser states
* @readonly
* @enum {number}
*/
parser.prototype.STATES = {
INIT: 0,
HEADER: 1,
BODY: 2,
FOOTER: 3,
END: 4,
};
/**
* Change state of this parser
* @param {number} state - parser.STATES
* @return {this} - This instance
*/
parser.prototype._changeState = function (state) {
// var states = Object.values(this.STATES); // If minimum engine version can be raised to >=7.0.0 in package.json
var states = Object.keys(this.STATES).map(function (key) { return this.STATES[key]; }, this);
if (states.indexOf(state) < 0) {
throw new Error('Unknown state');
}
this._state = state;
return this;
};
/**
* Process output's header
* @param {string} line - A line from system ping
*/
parser.prototype._processHeader = function (line) {
throw new Error('Subclass should implement this method');
};
/**
* Process output's body
* @param {string} line - A line from system ping
*/
parser.prototype._processBody = function (line) {
throw new Error('Subclass should implement this method');
};
/**
* Process output's footer
* @param {string} line - A line from system ping
*/
parser.prototype._processFooter = function (line) {
throw new Error('Subclass should implement this method');
};
/**
* Process a line from system ping
* @param {string} line - A line from system ping
* @return {this} - This instance
*/
parser.prototype.eat = function (line) {
var headerStates = [this.STATES.INIT, this.STATES.HEADER];
// Store lines
this._lines.push(line);
// Strip all space \r\n at the end
var _line = line.replace(this._stripRegex, '');
if (_line.length === 0) {
// Do nothing if this is an empty line
} else if (headerStates.indexOf(this._state) >= 0) {
this._processHeader(_line);
} else if (this._state === this.STATES.BODY) {
this._processBody(_line);
} else if (this._state === this.STATES.FOOTER) {
this._processFooter(_line);
} else if (this._state === this.STATES.END) {
// Do nothing
} else {
throw new Error('Unknown state');
}
return this;
};
/**
* Get results after parsing certain lines from system ping
* @return {PingResponse} - Response from parsing ping output
*/
parser.prototype.getResult = function () {
var ret = Object.assign({}, this._response);
// Concat output
ret.output = this._lines.join('\n');
// Determine alive
ret.alive = this._times.length > 0;
// Update time at first successful line
if (ret.alive) {
this._response.time = this._times[0];
ret.time = this._response.time;
this._response.times = this._times;
ret.times = this._response.times;
}
// Get stddev
if (ret.stddev === 'unknown' && ret.alive) {
var numberOfSamples = this._times.length;
var sumOfAllSquareDifferences = this._times.reduce(
function (memory, time) {
var differenceFromMean = time - ret.avg;
var squaredDifference = differenceFromMean * differenceFromMean;
return memory + squaredDifference;
},
0
);
var variances = sumOfAllSquareDifferences / numberOfSamples;
ret.stddev = Math.round(Math.sqrt(variances) * 1000) / 1000;
}
// Fix min, avg, max, stddev up to 3 decimal points
['min', 'avg', 'max', 'stddev', 'packetLoss'].forEach(function (key) {
var v = ret[key];
if (typeof v === 'number') {
ret[key] = v.toFixed(3);
}
});
return ret;
};
module.exports = parser;