UNPKG

domotz-remote-pawn

Version:

Domotz Agent

145 lines (130 loc) 5.14 kB
/** This file is part of Domotz Agent. * Copyright (C) 2021 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/>. * * * Singleton that stores device discovery data, indexed by MAC address (uppercase) * and protocol (e.g. dhcp, snmp...). * * The usage is to collect data, store in the DiscoveryAccumulator and send to * the Domotz Cloud in piggy-back in the fast discovery payload. **/ const DiscoveryAccumulator = {}; function factory(resourceLocator) { const _buffer = {}; const myConsole = resourceLocator.log.decorateLogs(); var lodash = resourceLocator.lodash; var dhcpRequestsCounters = resourceLocator.DHCPRequestCounters; function _normalizedHash(data) { var normalisedStrPayload = resourceLocator.stringify(data); return resourceLocator.crypto.createHash('md5').update(normalisedStrPayload).digest('hex'); } function DeviceAccumulator(mac) { const _discoveryData = {}; return { add: function (protocol, data) { const candidate = { data: data, hash: _normalizedHash(data) }; const old = _discoveryData[protocol] || { data: null, hash: null }; if (old.hash === candidate.hash) { myConsole.info('Ignoring duplicate discovery data for device %s and protocol %s', mac, protocol); } else { _discoveryData[protocol] = candidate; } if (old.data !== null && old.hash !== candidate.hash) { myConsole.warn('Overwriting discovery data for device %s and protocol %s', mac, protocol); } }, fetch: function () { const ret = {}; var empty = true; for (var protocol in _discoveryData) { if (_discoveryData[protocol].data !== null) { ret[protocol] = _discoveryData[protocol].data; empty = false; } } return empty ? null : ret; }, flush: function () { for (var protocol in _discoveryData) { _discoveryData[protocol].data = null; } }, get: function () { return _discoveryData; }, }; } DiscoveryAccumulator.store = function (mac, protocol, data) { mac = mac.toUpperCase(); myConsole.info('Storing sample of protocol %s for device %s', protocol, mac); myConsole.debug('%s protocol data for mac %s: %s', protocol, mac, JSON.stringify(data)); if (protocol === 'dhcp') { myConsole.debug('Updating counter for DHCP requests, %s', mac); dhcpRequestsCounters.registerDHCPRequest(mac); } if (_buffer[mac] === undefined) { _buffer[mac] = DeviceAccumulator(mac); } const accumulator = _buffer[mac]; accumulator.add(protocol, data); }; DiscoveryAccumulator.fetch = function (macList) { const returnedData = {}; macList.forEach(function (mac) { mac = mac.toUpperCase(); var tmp = null; if (_buffer[mac] && (tmp = _buffer[mac].fetch()) !== null) { returnedData[mac] = tmp; } }); return returnedData; }; DiscoveryAccumulator.fetchAllByProtocol = function (protocol) { const returnedData = {}; for (var mac in _buffer) { if (_buffer.hasOwnProperty(mac)) { var data = _buffer[mac].fetch(); if (data !== null && protocol in data) { data = lodash.pickBy(data, function (value, key) { return key === protocol; }); returnedData[mac] = data; } } } return returnedData; }; DiscoveryAccumulator.flush = function (macList) { macList.forEach(function (mac) { mac = mac.toUpperCase(); if (_buffer[mac]) { _buffer[mac].flush(); } }); }; DiscoveryAccumulator.dump = function () { var _ = require('lodash'); var ret = {}; _(_buffer) .toPairs() .forEach(function (pair) { ret[pair[0]] = pair[1].get(); }); return ret; }; return DiscoveryAccumulator; } module.exports.factory = factory;