@harmonyhub/discover
Version:
Discover available Logitech Harmony Hubs in the current network.
124 lines (123 loc) • 4.77 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Ping = exports.PingOptions = void 0;
const autobind_decorator_1 = require("autobind-decorator");
const logger = require("debug");
const debug = logger('harmonyhub:discover:ping');
const dgram = require("dgram");
const os = require("os");
class PingOptions {
}
exports.PingOptions = PingOptions;
function generateBroadcastIp() {
if (!/^win/i.test(process.platform)) {
debug('We are running non windows so just broadcast');
return ['255.255.255.255'];
}
debug('We are running on windows so we try to find the local ip address to fix a windows broadcast protocol bug');
const ifaces = os.networkInterfaces(), possibleIps = [];
Object.keys(ifaces).forEach((ifname) => {
ifaces[ifname].forEach((iface) => {
// skip over internal (i.e. 127.0.0.1) and non-ipv4 addresses
if ('IPv4' !== iface.family || iface.internal !== false) {
return;
}
possibleIps.push(iface.address);
});
});
return possibleIps.filter((ip) => {
return ip.indexOf('192.') === 0;
}).map((ip) => {
const nums = ip.split('.');
nums[3] = 255;
debug('Fallback to local ip address -> ' + nums.join('.'));
return nums.join('.');
});
}
let Ping = class Ping {
constructor(portToAnnounce, options) {
// try to find an ip address that is in a local (home) network
options = options || {};
options.address = options.address || generateBroadcastIp();
if (typeof options.address === 'string') {
options.address = [options.address];
}
// merge default with user options
// default address is 255.255.255.255 from generateBroadcastIp()
this.options = Object.assign({
port: 5224,
interval: 2000
}, options);
debug(`Ping(${portToAnnounce}, ${JSON.stringify(this.options)})`);
this.portToAnnounce = portToAnnounce;
// init the welcome messages
this.message = `_logitech-reverse-bonjour._tcp.local.\n${portToAnnounce}`;
this.messageBuffer = Buffer.from(this.message);
}
/**
* emit a broadcast into the network.
*/
emit() {
debug('emit()');
// emit to all the addresses
this.options.address.forEach((address) => this.socket.send(this.messageBuffer, 0, this.message.length, this.options.port, address, (err) => {
if (err) {
debug(`error emitting ping. stopping now :( (${err})`);
this.stop();
}
}));
}
/**
* Start an interval emitting broadcasts into the network.
*/
start() {
debug('start()');
if (this.socket) {
debug('Ping is already running, call stop() first');
return;
}
// setup socket to broadcast messages from the incoming ping
// unref so that the app can close
this.socket = dgram.createSocket('udp4');
this.socket.bind(this.portToAnnounce, () => {
// this.options.port, -> forget this bind no need to care from which port the data was send??
this.socket.setBroadcast(true);
});
this.socket.unref();
// start the interval, do not unref to keep node js running
this.intervalToken = setInterval(this.emit, this.options.interval);
}
/**
* Stop broadcasting into the network.
*/
stop() {
debug('stop()');
if (this.intervalToken === undefined) {
debug('ping has already been stopped, call start() first');
return;
}
// stop the message emit
clearInterval(this.intervalToken);
this.intervalToken = undefined;
// close the socket
this.socket.close();
this.socket = undefined;
}
/**
* Return an indicator it this ping is currently running.
*/
isRunning() {
debug('isRunning()');
return (this.intervalToken !== undefined);
}
};
Ping = __decorate([
autobind_decorator_1.default
], Ping);
exports.Ping = Ping;