domotz-remote-pawn
Version:
Domotz Agent
192 lines (162 loc) • 6.01 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/>.
*
*
* Created by Fausto Lelli <fausto@domotz.com>
*/
var path = require('path');
var os = require('os');
const OID_DB_REMOTE_ENDPOINT = '/overlay/catalog';
const OVERLAY_DB_SEMAPHORE = 'SNMP_OVERLAY_DB_SEMAPHORE';
const OID_DB_FILE = path.join(os.tmpdir(), 'overlay_db.json');
var snmpOverlayDBFactory = function (resourceLocator) {
'use strict';
var fileUtils = resourceLocator.utils.file;
var crypto = resourceLocator.crypto;
var mutex = resourceLocator.utils.mutex;
var engineRequest = resourceLocator.engineRequest;
var myConsole = resourceLocator.log.decorateLogs();
// the following variables must be invalidated
var currentMD5 = null;
var overlayMap = {};
var lockDiscovery = function () {
return mutex.lock(OVERLAY_DB_SEMAPHORE, 1);
};
var unlockDiscovery = function () {
mutex.safeUnlock(OVERLAY_DB_SEMAPHORE, 1);
};
function getOverlay(overlayId) {
if (overlayMap.hasOwnProperty(overlayId)) {
return overlayMap[overlayId];
}
var content = getOverlayDB();
if (content && content.hasOwnProperty('overlays')) {
var overlays = content.overlays;
var min = 0;
var max = overlays.length - 1;
var guess;
while (min <= max) {
guess = Math.floor((max + min) / 2);
if (overlays[guess].id === overlayId) {
overlayMap[overlayId] = overlays[guess];
return overlays[guess];
} else if (overlays[guess].id < overlayId) {
min = guess + 1;
} else {
max = guess - 1;
}
}
return null;
} else {
return null;
}
}
function getOverlayDB() {
var content = fileUtils.readFile(OID_DB_FILE);
if (content) {
try {
return JSON.parse(content);
} catch (e) {
myConsole.info('Can not parse db file: %s', e);
}
}
return null;
}
function saveOverlayDB(db) {
fileUtils.writeFileSafe(OID_DB_FILE, db);
currentMD5 = null;
overlayMap = {};
getOverlayMD5();
}
function computeSingleOverlayMD5(overlay) {
var overlayContent = overlay.id;
var oidScalar = Object.keys(overlay.oid_scalar);
if (oidScalar && oidScalar.length > 0) {
oidScalar.sort();
for (var iScalar = 0; iScalar < oidScalar.length; iScalar++) {
overlayContent += oidScalar[iScalar];
}
}
var oidColumn = Object.keys(overlay.oid_column);
if (oidColumn && oidColumn.length > 0) {
oidColumn.sort();
for (var iColumn = 0; iColumn < oidColumn.length; iColumn++) {
overlayContent += oidColumn[iColumn];
}
}
return crypto.createHash('md5').update(overlayContent).digest('hex');
}
function getOverlayMD5() {
if (currentMD5) {
return currentMD5;
}
var content = getOverlayDB();
if (content && content.hasOwnProperty('overlays')) {
var overlays = content.overlays;
var contentMD5 = '';
for (var i = 0; i < overlays.length; i++) {
contentMD5 += computeSingleOverlayMD5(overlays[i]);
}
currentMD5 = crypto.createHash('md5').update(contentMD5).digest('hex');
myConsole.info('New MD5 computed: %s', currentMD5);
return currentMD5;
} else {
return null;
}
}
function invalidate() {
myConsole.info('Force check of Overlay DB cache');
currentMD5 = null;
checkOverlayDB();
}
function checkOverlayDB() {
if (!lockDiscovery()) {
myConsole.warn('WARNING: SNMP Overlay DB Check already in progress, ignoring the call');
return;
}
var currentMD5 = getOverlayMD5();
var url = OID_DB_REMOTE_ENDPOINT;
if (currentMD5 !== null) {
url = OID_DB_REMOTE_ENDPOINT + '?md5=' + currentMD5;
}
myConsole.info('Check MIB Overlay DB, url: %s', url);
engineRequest
.sendWithPromise(url, 'GET', null, function (response) {
myConsole.debug('Received response code : %s', response.statusCode);
if (response.statusCode === 304) {
myConsole.info('MIB Overlay DB is unchanged, using cached info ');
} else {
myConsole.info('Writing MIB Overlay DB to filesystem');
saveOverlayDB(response.body);
}
})
.catch(function (err) {
myConsole.error('Can not retrieve MIB Overlay DB %s', err);
})
.finally(function () {
unlockDiscovery();
});
}
return {
getOverlay: function (overlayId) {
return getOverlay(overlayId);
},
getOverlayMD5: getOverlayMD5,
checkOverlayDB: checkOverlayDB,
invalidate: invalidate,
};
};
module.exports.factory = snmpOverlayDBFactory;