// 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; /** * @param {string} host - The host to ping * @param {object} [options] - Options for the ping command * @param {array|string} [options.args] - Arguments to pass to the ping command * * Generated by Trelent */ 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, host ]; this._regmatch = /[><=]([0-9.]+?)ms/; } else if (util.LIN) { this._bin = "/bin/ping"; const defaultArgs = [ "-n", "-w", timeout, "-c", "1", 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", host ]; this._regmatch = /=([0-9.]+?) ms/; } else if (util.BSD) { this._bin = "/sbin/ping"; const defaultArgs = [ "-n", "-t", timeout, "-c", "1", 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; // SEND A PING // =========== 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); } }; // CALL Ping#send(callback) ON A TIMER // =================================== 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 data * @returns {string} */ function convertOutput(data) { if (util.WIN) { if (data) { return util.convertToUTF8(data); } } return data; }