Initial commit
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
'use strict';
|
||||
|
||||
var dgram = require('dgram');
|
||||
var crypto = null;
|
||||
var port = 50005;
|
||||
var MULTICAST_ADDR = '239.255.255.250';
|
||||
|
||||
function MHClient(hostname, logger, config, info) {
|
||||
var id = 1;
|
||||
var server;
|
||||
var timer;
|
||||
|
||||
function getIPs() {
|
||||
var ifaces = require('os').networkInterfaces();
|
||||
var ipArr = [];
|
||||
for (var dev in ifaces) {
|
||||
if (!ifaces.hasOwnProperty(dev)) continue;
|
||||
|
||||
/*jshint loopfunc:true */
|
||||
ifaces[dev].forEach(function (details) {
|
||||
//noinspection JSUnresolvedVariable
|
||||
if (!details.internal) ipArr.push(details.address);
|
||||
});
|
||||
}
|
||||
|
||||
return ipArr;
|
||||
}
|
||||
|
||||
function stopServer() {
|
||||
if (server) {
|
||||
try {
|
||||
server.close();
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
server = null;
|
||||
}
|
||||
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function sha(secret, salt, callback) {
|
||||
// calculate sha256
|
||||
crypto = crypto || require('crypto');
|
||||
var hash = crypto.createHash('sha256');
|
||||
|
||||
hash.on('readable', function () {
|
||||
var data = hash.read();
|
||||
if (data) {
|
||||
callback(data.toString('hex'));
|
||||
}
|
||||
});
|
||||
|
||||
hash.write(secret + salt);
|
||||
hash.end();
|
||||
}
|
||||
|
||||
function startServer(isBroadcast, timeout, onReady, onMessage, onFinished) {
|
||||
if (server) {
|
||||
onFinished('Some operation still active');
|
||||
return;
|
||||
}
|
||||
server = dgram.createSocket('udp4');
|
||||
timeout = parseInt(timeout, 10) || 2000;
|
||||
|
||||
timer = setTimeout(function () {
|
||||
stopServer();
|
||||
|
||||
if (onFinished) {
|
||||
onFinished(null);
|
||||
onFinished = null;
|
||||
}
|
||||
|
||||
}, timeout);
|
||||
|
||||
server.on('error', function (err) {
|
||||
stopServer();
|
||||
|
||||
if (onFinished) {
|
||||
onFinished(err);
|
||||
onFinished = null;
|
||||
}
|
||||
});
|
||||
|
||||
server.on('message', function (msg, rinfo) {
|
||||
msg = msg.toString();
|
||||
try {
|
||||
msg = JSON.parse(msg);
|
||||
if (onMessage) {
|
||||
if (onMessage(server, msg, rinfo)) {
|
||||
stopServer();
|
||||
onFinished = null;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Invalid answer: ' + msg);
|
||||
}
|
||||
});
|
||||
|
||||
server.on('listening', function (msg, rinfo) {
|
||||
// var address = server.address();
|
||||
if (isBroadcast) server.setBroadcast(true);
|
||||
onReady && onReady(server);
|
||||
});
|
||||
|
||||
server.bind();
|
||||
}
|
||||
|
||||
this.browse = function (timeout, isDebug, callback) {
|
||||
var result = [];
|
||||
var ownIps = getIPs();
|
||||
|
||||
startServer(true, timeout,
|
||||
function onReady(srv) {
|
||||
var text = JSON.stringify({
|
||||
cmd: 'browse',
|
||||
id: ++id
|
||||
});
|
||||
server.send(text, 0, text.length, port, MULTICAST_ADDR);
|
||||
},
|
||||
function onMessage (srv, msg, rinfo) {
|
||||
// ignore own answers
|
||||
if (isDebug || rinfo.address !== '127.0.0.1' && ownIps.indexOf(rinfo.address) === -1) {
|
||||
if (msg.result === 'not authenticated') {
|
||||
result.push({ip: rinfo.address, hostname: rinfo.address, info: 'authentication required', auth: msg.auth});
|
||||
} else if (msg.result === 'ok') {
|
||||
result.push(msg);
|
||||
} else {
|
||||
console.log('Unknown answer: ' + JSON.stringify(msg));
|
||||
}
|
||||
}
|
||||
if (isDebug) {
|
||||
console.log(JSON.stringify(msg));
|
||||
}
|
||||
},
|
||||
function onFinished(err) {
|
||||
callback(err, result);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.connect = function (ip, password, callback) {
|
||||
startServer(false, 2000,
|
||||
function onReady(srv) {
|
||||
var text = JSON.stringify({
|
||||
cmd: 'browse',
|
||||
id: ++id
|
||||
});
|
||||
server.send(text, 0, text.length, port, ip);
|
||||
},
|
||||
function onMessage (srv, msg, rinfo) {
|
||||
if (msg.cmd === 'browse' && msg.id === id) {
|
||||
if (msg.result === 'ok') {
|
||||
if (callback) {
|
||||
if (!msg.objects) {
|
||||
if (callback) {
|
||||
callback('Invalid configuration received: ' + JSON.stringify(msg));
|
||||
callback = null;
|
||||
}
|
||||
} else if (!msg.states) {
|
||||
if (callback) {
|
||||
callback('Invalid configuration received: ' + JSON.stringify(msg));
|
||||
callback = null;
|
||||
}
|
||||
} else {
|
||||
callback && callback(null, msg.objects, msg.states, rinfo.address);
|
||||
}
|
||||
}
|
||||
} else if (msg.result === 'not authenticated') {
|
||||
if (!password) {
|
||||
if (callback) {
|
||||
callback('not authenticated' + msg);
|
||||
callback = null;
|
||||
}
|
||||
} else {
|
||||
sha(password, msg.salt, function (shaText) {
|
||||
// send password
|
||||
var text = JSON.stringify({
|
||||
cmd: 'browse',
|
||||
id: ++id,
|
||||
password: shaText
|
||||
});
|
||||
server.send(text, 0, text.length, port, ip);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
} else if (msg.result === 'invalid password') {
|
||||
if (callback) {
|
||||
callback('invalid password');
|
||||
callback = null;
|
||||
}
|
||||
} else {
|
||||
console.log(msg.result);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
console.warn('Unexpected message: ' + JSON.stringify(msg));
|
||||
}
|
||||
},
|
||||
function onFinished(err) {
|
||||
if (callback) {
|
||||
callback(err);
|
||||
callback = null;
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
module.exports = MHClient;
|
||||
Reference in New Issue
Block a user