UNPKG

domotz-remote-pawn

Version:

Domotz Agent

166 lines (149 loc) 5.86 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, configuration) { var sockets = {}; var listenedIPs = {}; var credentials = configuration.credentials; var endpoint = configuration.engine.api_endpoints.hub; var me = { register: function (ip, port, report_to, filters) { if (sockets[port] === undefined) { console.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 + report_to, 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)) { console.verbose("Datagram does not match filters, dropping it"); return; } var current_datagram = hashMessage(msg, rinfo); if (current_datagram === deliveryInfo.last_datagram) { return; } var hex_message = msg.toString('hex').replace(/(..)/g, "$1 "); console.verbose("Server got " + hex_message + " from " + rinfo.address + ":" + rinfo.port); var my_payload = { meta_info: rinfo, payload: hex_message }; var options = createRequestOptions(deliveryInfo, my_payload); var callback = createHandleEngineHTTPReply(deliveryInfo, current_datagram); 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, my_payload) { var body = JSON.parse(JSON.stringify(my_payload)); 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); console.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) { console.warn("Cannot send UDP datagram report to " + deliveryInfo.report_to + " - error: " + error); } else if (response.statusCode < 200 || response.statusCode > 299) { console.warn("Cannot send UDP datagram report to " + deliveryInfo.report_to + " - http error code: " + response.statusCode); } else { console.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')) { console.verbose("Datagram matches filter #" + i); return true; } } return false; }; return me; }; module.exports.factory = factory;