domotz-remote-pawn
Version:
Domotz Agent
159 lines (139 loc) • 5.1 kB
JavaScript
/** 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/>.
**/
/**
* This module performs retries on stale bindings
* Created by Andrea Azzara <a.azzara@domotz.com> on 13/07/18.
*/
const RETRY_TRIALS = 5;
const RETRY_HOST_TIMEOUT = 10;
module.exports.factory = function (
q,
host,
log,
configuration,
blacklist,
interfacesBinding,
async,
lodash,
bindDiscovery,
nmapCommands,
ip,
ipUtils
) {
'use strict';
var iteration = 0;
var baseConsole = log.decorateLogs();
var myConsole = baseConsole;
function setIteration(i) {
iteration = i;
myConsole = baseConsole.decorate(String(iteration));
}
setIteration(0);
function getRetryInterval(conf) {
var discovery = conf.discovery;
return discovery && discovery.retry_interval ? discovery.retry_interval : 1000;
}
var retryInterval = getRetryInterval(configuration);
function _getNmapType(iface) {
if (!iface.custom) {
return nmapCommands.NMAP_TYPE.DEFAULT;
}
if (iface.netmask === 32) {
return nmapCommands.NMAP_TYPE.EXTERNAL_HOST;
}
return nmapCommands.NMAP_TYPE.EXTERNAL_SUBNET;
}
function retryOnStaleBindingsForAllInterfaces(callback) {
var interfaceList = host.getAllowedInterfacesList();
async.each(
interfaceList,
function (iface, cb) {
_retryOnStaleBindingsForSingleInterface(RETRY_TRIALS, iface, cb);
},
function () {
callback();
}
);
}
function _retryOnStaleBindingsForSingleInterface(count, iface, cb) {
function pingDevices(retryCallback) {
var staleDevices = _getStaleDevicesForInterface(iface);
if (staleDevices.length === 0) {
retryCallback();
return;
}
var nmapType = _getNmapType(iface);
if (count % 2 !== 0 && nmapType === nmapCommands.NMAP_TYPE.DEFAULT) {
nmapType = nmapCommands.NMAP_TYPE.DISABLE_ARP_PING;
}
myConsole.info('retryOnStaleBindingsAdvanced, there are %s stale devices, retry attempts left %s ', staleDevices.length, count);
count--;
bindDiscovery
.discover(staleDevices, nmapType, RETRY_HOST_TIMEOUT, iface)
.then(interfacesBinding.setFreshDiscoveredBindings)
.then(function () {
if (count === 0) {
myConsole.info('Exiting retry loop, devices still stale: %d', staleDevices.length);
retryCallback();
} else {
retryCallback('continue');
}
})
.catch(function (err) {
myConsole.error('Discovery error %s', err.toString());
retryCallback(err);
});
}
async.retry({ times: count, interval: retryInterval }, pingDevices, function (err) {
if (err) {
myConsole.error('Terminating retries due to error: %s', err.message);
} else {
myConsole.verbose('retryOnStaleBindingsAdvanced END');
}
cb();
});
}
function _isIpInRanges(ipRanges, ip) {
return (
ipRanges &&
lodash.some(ipRanges, function (ipRange) {
return ipUtils.isIpInRange(ipRange, ip);
})
);
}
function _deviceBelongsToInterface(device, iface) {
return ipUtils.isIpInList(iface.ipList, device.ip) || _isIpInRanges(iface.ipRange, device.ip);
}
function _getStaleDevicesForInterface(iface) {
var staleList = interfacesBinding.listStale();
var devicesToExclude = blacklist.getDeviceToExclude();
var filteredStaleDevices = staleList.filter(function (e) {
return devicesToExclude.indexOf(e.ip) < 0;
});
return lodash
.filter(filteredStaleDevices, function (device) {
return _deviceBelongsToInterface(device, iface);
})
.map(function (e) {
return e.ip;
});
}
return {
retryOnStaleBindingsForAllInterfaces: retryOnStaleBindingsForAllInterfaces,
setIteration: setIteration,
};
};