mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-11-28 01:04:05 +00:00
a54e58b4d6
This should fully implement #1891 by adding an extra field to the edit monitor page and an extra column to the database. The user can now set the size of the packet to send, it defaults to 56. A maximum limit of 65500 was chosen to ensure that the total size of the packet does not exceed the IPv4 maximum packet size and to comply with the limit imposed by Windows. Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
199 lines
5 KiB
JavaScript
199 lines
5 KiB
JavaScript
// https://github.com/ben-bradley/ping-lite/blob/master/ping-lite.js
|
|
// Fixed on Windows
|
|
const net = require("net");
|
|
const spawn = require("child_process").spawn;
|
|
const events = require("events");
|
|
const fs = require("fs");
|
|
const util = require("./util-server");
|
|
|
|
module.exports = Ping;
|
|
|
|
/**
|
|
* Constructor for ping class
|
|
* @param {string} host Host to ping
|
|
* @param {object} [options] Options for the ping command
|
|
* @param {array|string} [options.args] - Arguments to pass to the ping command
|
|
*/
|
|
function Ping(host, options) {
|
|
if (!host) {
|
|
throw new Error("You must specify a host to ping!");
|
|
}
|
|
|
|
this._host = host;
|
|
this._options = options = (options || {});
|
|
|
|
events.EventEmitter.call(this);
|
|
|
|
const timeout = 10;
|
|
|
|
if (util.WIN) {
|
|
this._bin = "c:/windows/system32/ping.exe";
|
|
this._args = (options.args) ? options.args : [ "-n", "1", "-w", timeout * 1000, "-l", this._options.size, host ];
|
|
this._regmatch = /[><=]([0-9.]+?)ms/;
|
|
|
|
} else if (util.LIN) {
|
|
this._bin = "/bin/ping";
|
|
|
|
const defaultArgs = [ "-n", "-w", timeout, "-c", "1", "-s", this._options.size, host ];
|
|
|
|
if (net.isIPv6(host) || options.ipv6) {
|
|
defaultArgs.unshift("-6");
|
|
}
|
|
|
|
this._args = (options.args) ? options.args : defaultArgs;
|
|
this._regmatch = /=([0-9.]+?) ms/;
|
|
|
|
} else if (util.MAC) {
|
|
|
|
if (net.isIPv6(host) || options.ipv6) {
|
|
this._bin = "/sbin/ping6";
|
|
} else {
|
|
this._bin = "/sbin/ping";
|
|
}
|
|
|
|
this._args = (options.args) ? options.args : [ "-n", "-t", timeout, "-c", "1", "-s", this._options.size, host ];
|
|
this._regmatch = /=([0-9.]+?) ms/;
|
|
|
|
} else if (util.BSD) {
|
|
this._bin = "/sbin/ping";
|
|
|
|
const defaultArgs = [ "-n", "-t", timeout, "-c", "1", "-s", this._options.size, host ];
|
|
|
|
if (net.isIPv6(host) || options.ipv6) {
|
|
defaultArgs.unshift("-6");
|
|
}
|
|
|
|
this._args = (options.args) ? options.args : defaultArgs;
|
|
this._regmatch = /=([0-9.]+?) ms/;
|
|
|
|
} else {
|
|
throw new Error("Could not detect your ping binary.");
|
|
}
|
|
|
|
if (!fs.existsSync(this._bin)) {
|
|
throw new Error("Could not detect " + this._bin + " on your system");
|
|
}
|
|
|
|
this._i = 0;
|
|
|
|
return this;
|
|
}
|
|
|
|
Ping.prototype.__proto__ = events.EventEmitter.prototype;
|
|
|
|
/**
|
|
* Callback for send
|
|
* @callback pingCB
|
|
* @param {any} err Any error encountered
|
|
* @param {number} ms Ping time in ms
|
|
*/
|
|
|
|
/**
|
|
* Send a ping
|
|
* @param {pingCB} callback Callback to call with results
|
|
*/
|
|
Ping.prototype.send = function (callback) {
|
|
let self = this;
|
|
callback = callback || function (err, ms) {
|
|
if (err) {
|
|
return self.emit("error", err);
|
|
}
|
|
return self.emit("result", ms);
|
|
};
|
|
|
|
let _ended;
|
|
let _exited;
|
|
let _errored;
|
|
|
|
this._ping = spawn(this._bin, this._args); // spawn the binary
|
|
|
|
this._ping.on("error", function (err) { // handle binary errors
|
|
_errored = true;
|
|
callback(err);
|
|
});
|
|
|
|
this._ping.stdout.on("data", function (data) { // log stdout
|
|
if (util.WIN) {
|
|
data = convertOutput(data);
|
|
}
|
|
this._stdout = (this._stdout || "") + data;
|
|
});
|
|
|
|
this._ping.stdout.on("end", function () {
|
|
_ended = true;
|
|
if (_exited && !_errored) {
|
|
onEnd.call(self._ping);
|
|
}
|
|
});
|
|
|
|
this._ping.stderr.on("data", function (data) { // log stderr
|
|
if (util.WIN) {
|
|
data = convertOutput(data);
|
|
}
|
|
this._stderr = (this._stderr || "") + data;
|
|
});
|
|
|
|
this._ping.on("exit", function (code) { // handle complete
|
|
_exited = true;
|
|
if (_ended && !_errored) {
|
|
onEnd.call(self._ping);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* @param {Function} callback
|
|
*
|
|
* Generated by Trelent
|
|
*/
|
|
function onEnd() {
|
|
let stdout = this.stdout._stdout;
|
|
let stderr = this.stderr._stderr;
|
|
let ms;
|
|
|
|
if (stderr) {
|
|
return callback(new Error(stderr));
|
|
}
|
|
|
|
if (!stdout) {
|
|
return callback(new Error("No stdout detected"));
|
|
}
|
|
|
|
ms = stdout.match(self._regmatch); // parse out the ##ms response
|
|
ms = (ms && ms[1]) ? Number(ms[1]) : ms;
|
|
|
|
callback(null, ms, stdout);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Ping every interval
|
|
* @param {pingCB} callback Callback to call with results
|
|
*/
|
|
Ping.prototype.start = function (callback) {
|
|
let self = this;
|
|
this._i = setInterval(function () {
|
|
self.send(callback);
|
|
}, (self._options.interval || 5000));
|
|
self.send(callback);
|
|
};
|
|
|
|
/** Stop sending pings */
|
|
Ping.prototype.stop = function () {
|
|
clearInterval(this._i);
|
|
};
|
|
|
|
/**
|
|
* Try to convert to UTF-8 for Windows, as the ping's output on Windows is not UTF-8 and could be in other languages
|
|
* Thank @pemassi
|
|
* https://github.com/louislam/uptime-kuma/issues/570#issuecomment-941984094
|
|
* @param {any} data
|
|
* @returns {string}
|
|
*/
|
|
function convertOutput(data) {
|
|
if (util.WIN) {
|
|
if (data) {
|
|
return util.convertToUTF8(data);
|
|
}
|
|
}
|
|
return data;
|
|
}
|