UNPKG

domotz-remote-pawn

Version:

Domotz Agent

159 lines (141 loc) 5.82 kB
/** This file is part of Domotz Agent. * Copyright (C) 2016 Domotz Ltd * * Domotz Agent is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Domotz Agent is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Domotz Agent. If not, see <http://www.gnu.org/licenses/>. * Created by Iacopo Papalini <ipapalini@domotz.com> on 09/04/15. * */ var factory = function (crypto, dgram, request, resourceLocator) { var configuration = resourceLocator.configuration; var myConsole = resourceLocator.log.decorateLogs(); var sockets = {}; var listenedIPs = {}; var credentials = configuration.credentials; var endpoint = configuration.engine.api_endpoints.hub; var me = { register: function (ip, port, reportTo, filters) { if (sockets[port] === undefined) { myConsole.info('Socket not found for port ' + port + '. ' + 'Opening new socket'); sockets[port] = initializeSocket(port); } if (listenedIPs[ip] === undefined) { listenedIPs[ip] = {}; } listenedIPs[ip][port] = { report_to: endpoint + reportTo, last_datagram: '', filters: filters, }; }, handleDatagram: function (msg, rinfo) { if (listenedIPs[rinfo.address] === undefined || listenedIPs[rinfo.address][rinfo.port] === undefined) { return; } var deliveryInfo = listenedIPs[rinfo.address][rinfo.port]; if (deliveryInfo.filters && !matches(msg, deliveryInfo.filters)) { myConsole.verbose('Datagram does not match filters, dropping it'); return; } var currentDatagram = hashMessage(msg, rinfo); if (currentDatagram === deliveryInfo.last_datagram) { return; } var hexMessage = msg.toString('hex').replace(/(..)/g, '$1 '); myConsole.verbose('Server got ' + hexMessage + ' from ' + rinfo.address + ':' + rinfo.port); var myPayload = { meta_info: rinfo, payload: hexMessage, }; var options = createRequestOptions(deliveryInfo, myPayload); var callback = createHandleEngineHTTPReply(deliveryInfo, currentDatagram); request.post(options, callback); }, getDeliveryInfo: function (ip, port) { return listenedIPs[ip] && listenedIPs[ip][port] ? listenedIPs[ip][port] : null; }, debugInfo: function () { var dumped = []; var tmp = JSON.stringify(sockets, function (key, value) { if (typeof value === 'object' && value !== null) { if (dumped.indexOf(value) !== -1) { return '[RECURSION DETECTED]'; } // Store value in our collection dumped.push(value); } return value; }); tmp = JSON.parse(tmp); return { sockets: tmp }; }, }; // Private functions var createRequestOptions = function (deliveryInfo, myPayload) { var body = JSON.parse(JSON.stringify(myPayload)); body.meta_info.protocol = 'UDP'; return { uri: deliveryInfo.report_to, json: true, headers: { 'content-type': 'application/json', }, auth: { user: credentials.user, pass: credentials.password, }, body: body, }; }; var initializeSocket = function (port) { var socket = dgram.createSocket('udp4'); socket.on('message', me.handleDatagram); socket.bind(port); myConsole.info('Socket bound on port ' + port); return socket; }; var hashMessage = function (msg, rinfo) { var hash = crypto.createHash('md5'); hash.update(msg); hash.update(JSON.stringify(rinfo)); return hash.digest('base64'); }; var createHandleEngineHTTPReply = function (deliveryInfo, currentDatagram) { return function (error, response) { if (error) { myConsole.warn('Cannot send UDP datagram report to ' + deliveryInfo.report_to + ' - error: ' + error); } else if (response.statusCode < 200 || response.statusCode > 299) { myConsole.warn('Cannot send UDP datagram report to ' + deliveryInfo.report_to + ' - http error code: ' + response.statusCode); } else { myConsole.info('UDP report sent to ' + deliveryInfo.report_to); deliveryInfo.last_datagram = currentDatagram; } }; }; var matches = function (msg, filters) { for (var i = 0; i < filters.length; i++) { var filter = filters[i]; if (msg.length < filter.length) { continue; } var tmp = new Buffer(msg.slice(0, filter.length)); if (filter.toString('base64') === tmp.toString('base64')) { myConsole.verbose('Datagram matches filter #' + i); return true; } } return false; }; return me; }; module.exports.factory = factory;