UNPKG

domotz-remote-pawn

Version:

Domotz Agent

264 lines (218 loc) 10.3 kB
/** This file is part of Domotz Agent. * Copyright (C) 2016 Domotz UK LLP * * 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/>. **/ var protocolDiscoveryOrchestratorFactory = function (domotzApp, discoverySenderFactory) { "use strict"; /*** * console overrides * **/ var discoveryConsole = domotzApp.log.decorateLogs('DISCOVERY - '); var sortedHashTable = domotzApp.utils.dataStructure.sortedHashTable; var localDeviceMaps = { newDeviceIdByIp: {}, ipToId: {}, interfaceNumberByIp: {} }; var discoverySender = discoverySenderFactory(domotzApp, localDeviceMaps); var registeredProtocols = { bonjour: domotzApp.discovery.bonjour_discovery, upnp: domotzApp.discovery.upnp_device_discovery, snmp: domotzApp.discovery.snmp_basic_discovery }; // Driver discovery results indexed by protocol and device ID var response = { bonjour: {}, upnp: {}, snmp: {} }; var responseAccumulatingCache = { bonjour: {} }; var lastDriverSnapshot = { bonjour: {}, upnp: {}, snmp: {} }; var postDiscoveryHandler = { snmp: discoverySender.sendSnmpInterfaceNumber }; // // ************* MAIN LOOP (discover, map, post result) function discover(protocolName) { var protocolDriver = getProtocolDriver(protocolName); if (!protocolDriver) { discoveryConsole.error("Driver not found for protocol '%s'", protocolName); return; } discoveryConsole.info("(%s): Discovery Started", protocolDriver.getProtocolNameUpperCase()); var devicesMaps = domotzApp.discovery.utils.getDevicesMaps(); localDeviceMaps.ipToId = devicesMaps.ipToId; localDeviceMaps.interfaceNumberByIp = domotzApp.discovery.utils.getDetailsFieldsForDevices(['interface_number_snmp']); discoveryConsole.verbose("(%s): Got device maps, calling driver ...", protocolDriver.getProtocolNameUpperCase()); doProtocolDiscovery(protocolDriver); } function getProtocolDriver(protocolName) { return registeredProtocols[protocolName]; } function runPostDiscoveryHandler(protocolDriver) { discoveryConsole.debug("post discovery management"); var selectedPostDiscoveryHandler = postDiscoveryHandler[protocolDriver.getProtocolName()]; if (selectedPostDiscoveryHandler) { discoveryConsole.debug("post discovery handler call"); protocolDriver.applyFunctionToSnapshotEntries(selectedPostDiscoveryHandler); } } function doProtocolDiscovery(protocolDriver) { var pretty_protocol_name = protocolDriver.getProtocolNameUpperCase(); if (!protocolDriver.isDiscoveryInProgress()) { response[protocolDriver.getProtocolName()] = {}; discoveryConsole.debug("(%s): Starting actual discovery ...", pretty_protocol_name); protocolDriver.discover(function (result) { discoveryConsole.debug("(%s) Terminated, analysing results ...", pretty_protocol_name); discoveryConsole.verbose("(%s): Discovery Result is %s", pretty_protocol_name, JSON.stringify(result)); saveProtocolDiscoveryResult(result, protocolDriver); parseProtocolDiscoveryResult(result, protocolDriver); sendResultToEngine(protocolDriver); runPostDiscoveryHandler(protocolDriver); }); } else { discoveryConsole.debug("(%s): discovery already in progress ...", pretty_protocol_name); } } function getProtocolDataForNewDeviceId(protocolDriver, deviceIpAddress, deviceId) { var protocolName = protocolDriver.getProtocolName(); var last_discovery_result = lastDriverSnapshot[protocolName]; if (protocolName === 'bonjour') { response[protocolName] = {}; addBonjourResultToDevice(last_discovery_result, protocolDriver); if (response[protocolName][deviceId]) { discoveryConsole.debug("(%s): for new device (id %s, ip %s) found protocol driver cache, sending ...", protocolDriver.getProtocolNameUpperCase(), deviceId, deviceIpAddress); sendResultToEngine(protocolDriver); } else { discoveryConsole.debug("(%s): cannot find protocol driver cache for new device (id %s, ip %s), rescheduling discovery ...", protocolDriver.getProtocolNameUpperCase(), deviceId, deviceIpAddress); setTimeout(function () { doProtocolDiscovery(protocolDriver); }, 300); } } else { // upnp, etc. var entry = protocolDriver.searchEntryIntoSnapshot(deviceIpAddress); if (entry) { response[protocolName] = {}; parseProtocolDiscoveryResult(last_discovery_result, protocolDriver); sendResultToEngine(protocolDriver); } else { setTimeout(function () { doProtocolDiscovery(protocolDriver); }, 300); } } } // // **************** Protocol Result Parsing and Device Id Matching function saveProtocolDiscoveryResult(result, protocolDriver) { lastDriverSnapshot[protocolDriver.getProtocolName()] = result; } function parseProtocolDiscoveryResult(driver_snapshot, protocolDriver) { switch (protocolDriver.getProtocolName()) { case 'bonjour': addBonjourResultToDevice(driver_snapshot, protocolDriver); break; case 'upnp': case 'snmp': protocolDriver.applyFunctionToSnapshotEntries(addResultToDeviceById); break; } } function addBonjourResultToDevice(driver_snapshot, protocolDriver) { for (var i = 0; i < driver_snapshot.length; i++) { for (var j = 0; j < driver_snapshot[i].ip.length; j++) { var matchedId = localDeviceMaps.ipToId[driver_snapshot[i].ip[j]]; if (!matchedId) { matchedId = localDeviceMaps.newDeviceIdByIp[driver_snapshot[i].ip[j]]; } if (matchedId) { if (!response[protocolDriver.getProtocolName()][matchedId]) { response[protocolDriver.getProtocolName()][matchedId] = {}; } createBonjourResponsePayload(matchedId, driver_snapshot[i], protocolDriver); } } } } function createBonjourResponsePayload(matchedId, driver_snapshot_piece, protocolDriver) { response[protocolDriver.getProtocolName()][matchedId][driver_snapshot_piece.service] = { name: driver_snapshot_piece.name, txt: driver_snapshot_piece.txt, fqdn: driver_snapshot_piece.fqdn, host: driver_snapshot_piece.host }; if (responseAccumulatingCache[protocolDriver.getProtocolName()][matchedId] === undefined) { responseAccumulatingCache[protocolDriver.getProtocolName()][matchedId] = {}; } responseAccumulatingCache[protocolDriver.getProtocolName()][matchedId][driver_snapshot_piece.service] = JSON.parse(JSON.stringify(response[protocolDriver.getProtocolName()][matchedId][driver_snapshot_piece.service])); } function addResultToDeviceById(ip, result, protocolName) { var matchedId = localDeviceMaps.ipToId[ip]; if (!matchedId) { matchedId = localDeviceMaps.newDeviceIdByIp[ip]; } if (matchedId) { discoveryConsole.verbose("(%s): identified device id %s of result %s", protocolName.toUpperCase(), matchedId, JSON.stringify(result)); response[protocolName][matchedId] = result; } } function sendResultToEngine(protocolDriver) { var protocolName = protocolDriver.getProtocolName(); var selectedResponseStorage = (protocolName === 'bonjour') ? responseAccumulatingCache : response; for (var deviceId in selectedResponseStorage[protocolName]) { if (selectedResponseStorage[protocolName].hasOwnProperty(deviceId)) { discoverySender.sendAndCacheDiscoveryResult(deviceId, sortedHashTable(selectedResponseStorage[protocolName][deviceId]), protocolDriver); } } } // // *************** New Device Notification Handling function addDevice(deviceId, macAddress, deviceIpAddresses) { var deviceIpAddress = deviceIpAddresses[0]; localDeviceMaps.newDeviceIdByIp[deviceIpAddress] = deviceId; discoveryConsole.info("-- NEW DEVICE INFO ADDED -- id %s added with mac %s and ip %s", deviceId, macAddress, deviceIpAddress); for (var proto in registeredProtocols) { if (registeredProtocols.hasOwnProperty(proto)) { var myDriver = getProtocolDriver(proto); if (!myDriver.isDiscoveryInProgress()) { discoveryConsole.verbose(" Protocol cache for %s is %s", proto, JSON.stringify(lastDriverSnapshot[proto])); getProtocolDataForNewDeviceId(myDriver, deviceIpAddress, deviceId); } } } } return { discover: discover, addDevice: addDevice }; }; module.exports.factory = protocolDiscoveryOrchestratorFactory;