-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
532 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
'use strict'; | ||
|
||
var __ = require('underscore'); | ||
var util = require('util'); | ||
|
||
// Our library | ||
var linuxBuilder = require('./linux'); | ||
var macBuilder = require('./mac'); | ||
var winBuilder = require('./win'); | ||
|
||
/** | ||
* A factory creates argument builders for different platform | ||
* @constructor | ||
*/ | ||
function factory() {} | ||
|
||
/** | ||
* Check out linux platform | ||
*/ | ||
factory.isLinux = function (p) { | ||
var platforms = [ | ||
'aix', | ||
'linux', | ||
]; | ||
|
||
return platforms.indexOf(p) >= 0; | ||
}; | ||
|
||
/** | ||
* Check out macos platform | ||
*/ | ||
factory.isMacOS = function (p) { | ||
var platforms = [ | ||
'darwin', | ||
'freebsd', | ||
]; | ||
|
||
return platforms.indexOf(p) >= 0; | ||
}; | ||
|
||
/** | ||
* Check out window platform | ||
*/ | ||
factory.isWindow = function (p) { | ||
return p && p.match(/^win/) !== null; | ||
}; | ||
|
||
/** | ||
* Check whether given platform is supported | ||
* @param {string} p - Name of the platform | ||
* @return {bool} - True or False | ||
*/ | ||
factory.isPlatformSupport = function (p) { | ||
return __.some([ | ||
this.isWindow(p), | ||
this.isLinux(p), | ||
this.isMacOS(p), | ||
]); | ||
}; | ||
|
||
/** | ||
* Return a path to the ping executable in the system | ||
* @param {string} platform - Name of the platform | ||
* @return {object} - Argument builder | ||
* @throw if given platform is not supported | ||
*/ | ||
factory.getExecutablePath = function (platform) { | ||
if (!this.isPlatformSupport(platform)) { | ||
throw new Error(util.format('Platform |%s| is not support', platform)); | ||
} | ||
|
||
var ret = null; | ||
|
||
if (platform === 'aix') { | ||
ret = '/usr/sbin/ping'; | ||
} else if (factory.isLinux(platform)) { | ||
ret = '/bin/ping'; | ||
} else if (factory.isWindow(platform)) { | ||
ret = process.env.SystemRoot + '/system32/ping.exe'; | ||
} else if (factory.isMacOS(platform)) { | ||
ret = '/sbin/ping'; | ||
} | ||
|
||
return ret; | ||
}; | ||
|
||
/** | ||
* Create a builder | ||
* @param {string} platform - Name of the platform | ||
* @return {object} - Argument builder | ||
* @throw if given platform is not supported | ||
*/ | ||
factory.createBuilder = function (platform) { | ||
if (!this.isPlatformSupport(platform)) { | ||
throw new Error(util.format('Platform |%s| is not support', platform)); | ||
} | ||
|
||
var ret = null; | ||
|
||
if (factory.isLinux(platform)) { | ||
ret = linuxBuilder; | ||
} else if (factory.isWindow(platform)) { | ||
ret = winBuilder; | ||
} else if (factory.isMacOS(platform)) { | ||
ret = macBuilder; | ||
} | ||
|
||
return ret; | ||
}; | ||
|
||
module.exports = factory; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
'use strict'; | ||
/* eslint no-unused-vars: 0 */ | ||
|
||
var __ = require('underscore'); | ||
|
||
/** | ||
* Parsed response | ||
* @typedef {object} PingResponse | ||
* @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 {string} stddev - Standard deviation time for collected records | ||
*/ | ||
|
||
/** | ||
* @constructor | ||
*/ | ||
function parser() { | ||
// Initial state is 0 | ||
this._state = 0; | ||
|
||
// Initial cache value | ||
this._response = { | ||
host: 'unknown', | ||
alive: false, | ||
output: 'unknown', | ||
time: 'unknown', | ||
min: 'unknown', | ||
max: 'unknown', | ||
avg: 'unknown', | ||
stddev: 'unknown', | ||
}; | ||
|
||
// Initial times storage for ping time | ||
this._times = []; | ||
|
||
// Initial lines storage for ping output | ||
this._lines = []; | ||
} | ||
|
||
/** | ||
* 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); | ||
|
||
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) { | ||
ret.time = this._response.time = this._times[0]; | ||
} | ||
|
||
// Get stddev | ||
if ( | ||
ret.stddev === 'unknown' && ret.alive | ||
) { | ||
var N = this._times.length; | ||
|
||
var variances = __.reduce(this._times, function (m, time) { | ||
return m + Math.pow((time - ret.avg), 2); | ||
}, 0) / N; | ||
|
||
ret.stddev = Math.round( | ||
Math.sqrt(variances) * 1000 | ||
) / 1000; | ||
} | ||
|
||
// Fix min, avg, max, stddev up to 3 decimal points | ||
__.each(['min', 'avg', 'max', 'stddev'], function (key) { | ||
var v = ret[key]; | ||
if (__.isNumber(v)) { | ||
ret[key] = v.toFixed(3); | ||
} | ||
}); | ||
|
||
return ret; | ||
}; | ||
|
||
module.exports = parser; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
'use strict'; | ||
|
||
var util = require('util'); | ||
|
||
var builderFactory = require('../builder/factory'); | ||
var WinParser = require('./win'); | ||
var MacParser = require('./mac'); | ||
|
||
/** | ||
* A factory creates a parser for parsing output from system ping | ||
* @constructor | ||
*/ | ||
function factory() {} | ||
|
||
/** | ||
* Create a parser for a given platform | ||
* @param {string} platform - Name of the platform | ||
* @return {object} - Parser | ||
* @throw if given platform is not supported | ||
*/ | ||
factory.createParser = function (platform) { | ||
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(); | ||
} else if (builderFactory.isMacOS(platform)) { | ||
ret = new MacParser(); | ||
} | ||
|
||
return ret; | ||
}; | ||
|
||
module.exports = factory; |
Empty file.
Oops, something went wrong.