domotz-remote-pawn
Version:
Domotz Agent
145 lines (130 loc) • 5.14 kB
JavaScript
/** 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;