Initial commit
This commit is contained in:
203
node_modules/ping/lib/parser/base.js
generated
vendored
Normal file
203
node_modules/ping/lib/parser/base.js
generated
vendored
Normal file
@ -0,0 +1,203 @@
|
||||
'use strict';
|
||||
|
||||
/* eslint no-unused-vars: 0 */
|
||||
|
||||
var __ = require('underscore');
|
||||
|
||||
/**
|
||||
* 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 = __.values(this.STATES);
|
||||
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 = __.extend({}, 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 = __.reduce(
|
||||
this._times,
|
||||
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
|
||||
__.each(['min', 'avg', 'max', 'stddev', 'packetLoss'], function (key) {
|
||||
var v = ret[key];
|
||||
if (__.isNumber(v)) {
|
||||
ret[key] = v.toFixed(3);
|
||||
}
|
||||
});
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
module.exports = parser;
|
44
node_modules/ping/lib/parser/factory.js
generated
vendored
Normal file
44
node_modules/ping/lib/parser/factory.js
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var builderFactory = require('../builder/factory');
|
||||
var WinParser = require('./win');
|
||||
var MacParser = require('./mac');
|
||||
var LinuxParser = require('./linux');
|
||||
|
||||
/**
|
||||
* A factory creates a parser for parsing output from system ping
|
||||
* @constructor
|
||||
*/
|
||||
function factory() {}
|
||||
|
||||
/**
|
||||
* Create a parser for a given platform
|
||||
* @param {string} addr - Hostname or ip addres
|
||||
* @param {string} platform - Name of the platform
|
||||
* @param {PingConfig} [config] - Config object in probe()
|
||||
* @return {object} - Parser
|
||||
* @throw if given platform is not supported
|
||||
*/
|
||||
factory.createParser = function (addr, platform, config) {
|
||||
// Avoid function reassignment
|
||||
var _config = config || {};
|
||||
|
||||
if (!builderFactory.isPlatformSupport(platform)) {
|
||||
throw new Error(util.format('Platform |%s| is not support', platform));
|
||||
}
|
||||
|
||||
var ret = null;
|
||||
if (builderFactory.isWindow(platform)) {
|
||||
ret = new WinParser(addr, _config);
|
||||
} else if (builderFactory.isMacOS(platform)) {
|
||||
ret = new MacParser(addr, _config);
|
||||
} else if (builderFactory.isLinux(platform)) {
|
||||
ret = new LinuxParser(addr, _config);
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
module.exports = factory;
|
59
node_modules/ping/lib/parser/linux.js
generated
vendored
Normal file
59
node_modules/ping/lib/parser/linux.js
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
var base = require('./base');
|
||||
var MacParser = require('./mac');
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*
|
||||
* @param {string} addr - Hostname or ip addres
|
||||
* @param {PingConfig} config - Config object in probe()
|
||||
*/
|
||||
function LinuxParser(addr, config) {
|
||||
base.call(this, addr, config);
|
||||
}
|
||||
|
||||
util.inherits(LinuxParser, base);
|
||||
|
||||
/**
|
||||
* Process output's body
|
||||
* @param {string} line - A line from system ping
|
||||
*/
|
||||
LinuxParser.prototype._processHeader = function (line) {
|
||||
// Get host and numeric_host
|
||||
var tokens = line.split(' ');
|
||||
var isProbablyIPv4 = tokens[1].indexOf('(') === -1;
|
||||
|
||||
if (isProbablyIPv4) {
|
||||
this._response.host = tokens[1];
|
||||
this._response.numeric_host = tokens[2].slice(1, -1);
|
||||
} else {
|
||||
// Normalise into either a 2 or 3 element array
|
||||
var foundAddresses = tokens.slice(1, -3).join('').match(/([^\s()]+)/g);
|
||||
this._response.host = foundAddresses.shift();
|
||||
this._response.numeric_host = foundAddresses.pop();
|
||||
}
|
||||
|
||||
this._changeState(this.STATES.BODY);
|
||||
};
|
||||
|
||||
/**
|
||||
* Process output's body
|
||||
* @param {string} line - A line from system ping
|
||||
*/
|
||||
LinuxParser.prototype._processBody = function (line) {
|
||||
// Reuse mac parser implementation
|
||||
MacParser.prototype._processBody.call(this, line);
|
||||
};
|
||||
|
||||
/**
|
||||
* Process output's footer
|
||||
* @param {string} line - A line from system ping
|
||||
*/
|
||||
LinuxParser.prototype._processFooter = function (line) {
|
||||
// Reuse mac parser implementation
|
||||
MacParser.prototype._processFooter.call(this, line);
|
||||
};
|
||||
|
||||
module.exports = LinuxParser;
|
85
node_modules/ping/lib/parser/mac.js
generated
vendored
Normal file
85
node_modules/ping/lib/parser/mac.js
generated
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
var __ = require('underscore');
|
||||
|
||||
var base = require('./base');
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*
|
||||
* @param {string} addr - Hostname or ip addres
|
||||
* @param {PingConfig} config - Config object in probe()
|
||||
*/
|
||||
function MacParser(addr, config) {
|
||||
base.call(this, addr, config);
|
||||
}
|
||||
|
||||
util.inherits(MacParser, base);
|
||||
|
||||
/**
|
||||
* Process output's header
|
||||
* @param {string} line - A line from system ping
|
||||
*/
|
||||
MacParser.prototype._processHeader = function (line) {
|
||||
// Get host and numeric_host
|
||||
var tokens = line.split(' ');
|
||||
|
||||
this._response.host = tokens[1];
|
||||
this._response.numeric_host = tokens[2].slice(1, -2);
|
||||
|
||||
this._changeState(this.STATES.BODY);
|
||||
};
|
||||
|
||||
/**
|
||||
* Process output's body
|
||||
* @param {string} line - A line from system ping
|
||||
*/
|
||||
MacParser.prototype._processBody = function (line) {
|
||||
// XXX: Assume there is at least 3 '=' can be found
|
||||
var count = (line.match(/=/g) || []).length;
|
||||
if (count >= 3) {
|
||||
var regExp = /([0-9.]+)[ ]*ms/;
|
||||
var match = regExp.exec(line);
|
||||
this._times.push(parseFloat(match[1], 10));
|
||||
}
|
||||
|
||||
// Change state if it see a '---'
|
||||
if (line.indexOf('---') >= 0) {
|
||||
this._changeState(this.STATES.FOOTER);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Process output's footer
|
||||
* @param {string} line - A line from system ping
|
||||
*/
|
||||
MacParser.prototype._processFooter = function (line) {
|
||||
var packetLoss = line.match(/ ([\d.]+)%/);
|
||||
if (packetLoss) {
|
||||
this._response.packetLoss = parseFloat(packetLoss[1], 10);
|
||||
}
|
||||
|
||||
// XXX: Assume number of keywords '/' more than 3
|
||||
var count = (line.match(/[/]/g) || []).length;
|
||||
if (count >= 3) {
|
||||
var regExp = /([0-9.]+)/g;
|
||||
// XXX: Assume min avg max stddev
|
||||
var m1 = regExp.exec(line);
|
||||
var m2 = regExp.exec(line);
|
||||
var m3 = regExp.exec(line);
|
||||
var m4 = regExp.exec(line);
|
||||
|
||||
if (__.all([m1, m2, m3, m4])) {
|
||||
this._response.min = parseFloat(m1[1], 10);
|
||||
this._response.avg = parseFloat(m2[1], 10);
|
||||
this._response.max = parseFloat(m3[1], 10);
|
||||
this._response.stddev = parseFloat(m4[1], 10);
|
||||
this._changeState(this.STATES.END);
|
||||
}
|
||||
|
||||
this._changeState(this.STATES.END);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = MacParser;
|
179
node_modules/ping/lib/parser/win.js
generated
vendored
Normal file
179
node_modules/ping/lib/parser/win.js
generated
vendored
Normal file
@ -0,0 +1,179 @@
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
var __ = require('underscore');
|
||||
|
||||
var base = require('./base');
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*
|
||||
* @param {string} addr - Hostname or ip addres
|
||||
* @param {PingConfig} config - Config object in probe()
|
||||
*/
|
||||
function WinParser(addr, config) {
|
||||
base.call(this, addr, config);
|
||||
this._ipv4Regex = /^([0-9]{1,3}\.){3}[0-9]{1,3}$/;
|
||||
}
|
||||
|
||||
util.inherits(WinParser, base);
|
||||
|
||||
/**
|
||||
* Process output's header
|
||||
* @param {string} line - A line from system ping
|
||||
*/
|
||||
WinParser.prototype._processHeader = function (line) {
|
||||
// XXX: Expect to find [****] when pinging domain like google.com
|
||||
// Read fixture/win/**/* for the detail
|
||||
var isPingNumeric = line.indexOf('[') === -1;
|
||||
|
||||
// Get host and numeric_host
|
||||
var tokens = line.split(' ');
|
||||
|
||||
if (isPingNumeric) {
|
||||
// For those missing [***], get the first token which match IPV4 regex
|
||||
this._response.host = __.find(tokens, function (t) {
|
||||
return this._ipv4Regex.test(t);
|
||||
}, this);
|
||||
this._response.numeric_host = this._response.host;
|
||||
} else {
|
||||
// For those has [***], anchor with such token
|
||||
var numericHost = __.find(tokens, function (t) {
|
||||
return t.indexOf('[') !== -1;
|
||||
}, this);
|
||||
var numericHostIndex = tokens.indexOf(numericHost);
|
||||
var match = /\[(.*)\]/.exec(numericHost);
|
||||
|
||||
if (match) {
|
||||
// Capture IP inside [] only. refs #71
|
||||
this._response.numeric_host = match[1];
|
||||
} else {
|
||||
// Otherwise, just mark as NA to indicate an error
|
||||
this._response.numeric_host = 'NA';
|
||||
}
|
||||
this._response.host = tokens[numericHostIndex - 1];
|
||||
}
|
||||
|
||||
this._changeState(this.STATES.BODY);
|
||||
};
|
||||
|
||||
/**
|
||||
* Process ipv6 output's body
|
||||
* @param {string} line - A line from system ping
|
||||
*/
|
||||
WinParser.prototype._processIPV6Body = function (line) {
|
||||
var tokens = line.split(' ');
|
||||
var dataFields = __.filter(tokens, function (token) {
|
||||
var isDataField = token.indexOf('=') >= 0 || token.indexOf('<') >= 0;
|
||||
return isDataField;
|
||||
});
|
||||
|
||||
// refs #65: Support system like french which has an extra space
|
||||
dataFields = __.map(dataFields, function (dataField) {
|
||||
var ret = dataField;
|
||||
var dataFieldIndex = tokens.indexOf(dataField);
|
||||
var nextIndex = dataFieldIndex + 1;
|
||||
|
||||
// Append the missing *ms*
|
||||
if (nextIndex < tokens.length) {
|
||||
if (tokens[nextIndex] === 'ms') {
|
||||
ret += 'ms';
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
});
|
||||
|
||||
var expectDataFieldInReplyLine = 1;
|
||||
if (dataFields.length >= expectDataFieldInReplyLine) {
|
||||
// XXX: Assume time will alaways get keyword ms for all language
|
||||
var timeKVP = __.find(dataFields, function (dataField) {
|
||||
return dataField.search(/(ms|мс)/i) >= 0;
|
||||
});
|
||||
var regExp = /([0-9.]+)/;
|
||||
var match = regExp.exec(timeKVP);
|
||||
|
||||
this._times.push(parseFloat(match[1], 10));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Process ipv4 output's body
|
||||
* @param {string} line - A line from system ping
|
||||
*/
|
||||
WinParser.prototype._processIPV4Body = function (line) {
|
||||
var tokens = line.split(' ');
|
||||
var byteTimeTTLFields = __.filter(tokens, function (token) {
|
||||
var isDataField = token.indexOf('=') >= 0 || token.indexOf('<') >= 0;
|
||||
return isDataField;
|
||||
});
|
||||
|
||||
var expectDataFieldInReplyLine = 3;
|
||||
var isReplyLine = byteTimeTTLFields.length >= expectDataFieldInReplyLine;
|
||||
if (isReplyLine) {
|
||||
var packetSize = this._pingConfig.packetSize;
|
||||
var byteField = __.find(byteTimeTTLFields, function (dataField) {
|
||||
var packetSizeToken = util.format('=%d', packetSize);
|
||||
var isByteField = dataField.indexOf(packetSizeToken) >= 0;
|
||||
return isByteField;
|
||||
});
|
||||
|
||||
// XXX: Assume time field will always be next of byte field
|
||||
var byteFieldIndex = byteTimeTTLFields.indexOf(byteField);
|
||||
var timeFieldIndex = byteFieldIndex + 1;
|
||||
var timeKVP = byteTimeTTLFields[timeFieldIndex];
|
||||
|
||||
var regExp = /([0-9.]+)/;
|
||||
var match = regExp.exec(timeKVP);
|
||||
|
||||
this._times.push(parseFloat(match[1], 10));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Process output's body
|
||||
* @param {string} line - A line from system ping
|
||||
*/
|
||||
WinParser.prototype._processBody = function (line) {
|
||||
var isPingSummaryLineShown = line.slice(-1) === ':';
|
||||
if (isPingSummaryLineShown) {
|
||||
this._changeState(this.STATES.FOOTER);
|
||||
return;
|
||||
}
|
||||
|
||||
var isIPV6 = this._pingConfig.v6;
|
||||
if (isIPV6) {
|
||||
this._processIPV6Body(line);
|
||||
} else {
|
||||
this._processIPV4Body(line);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Process output's footer
|
||||
* @param {string} line - A line from system ping
|
||||
*/
|
||||
WinParser.prototype._processFooter = function (line) {
|
||||
var packetLoss = line.match(/([\d.]+)%/);
|
||||
if (packetLoss) {
|
||||
this._response.packetLoss = parseFloat(packetLoss[1], 10);
|
||||
}
|
||||
|
||||
// XXX: Assume there is a keyword ms
|
||||
if (line.search(/(ms|мсек)/i) >= 0) {
|
||||
// XXX: Assume the ordering is Min Max Avg
|
||||
var regExp = /([0-9.]+)/g;
|
||||
var m1 = regExp.exec(line);
|
||||
var m2 = regExp.exec(line);
|
||||
var m3 = regExp.exec(line);
|
||||
|
||||
if (__.all([m1, m2, m3])) {
|
||||
this._response.min = parseFloat(m1[1], 10);
|
||||
this._response.max = parseFloat(m2[1], 10);
|
||||
this._response.avg = parseFloat(m3[1], 10);
|
||||
this._changeState(this.STATES.END);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = WinParser;
|
Reference in New Issue
Block a user