domotz-remote-pawn
Version:
Domotz Agent
139 lines (120 loc) • 5.12 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 has the responsibility to coordinate both the delta and the full IP devices
* discovery.
* It calls the InterfacesBindingStorage to update the interfaces binding discovered by the
* BindingDiscoverer. Then it sends the results to the engine.
*
* Created by Iacopo Papalini <iacopo@domotz.com> on 18/05/16.
*/
const MODULE_NAME = 'IP_DISCOVERY';
const RETRY_TRIALS = 5;
function getRetryInterval(configuration) {
var discovery = configuration.discovery;
var retryInterval = (discovery && discovery.retry_interval) ? discovery.retry_interval : 1000;
return retryInterval;
}
module.exports.factory = function (q,
configuration,
event,
bindingDiscoverer,
interfacesBindingStorage,
engineReportingStrategy) {
"use strict";
var retryInterval = getRetryInterval(configuration);
var performing = false;
var iteration = 0;
function performDiscovery() {
if (performing) {
console.warn("%s - (%d): Avoiding double run of IP network devices discovery",
MODULE_NAME, iteration);
return;
}
iteration++;
performing = true;
console.verbose("%s - (%d): Performing IP network devices discovery",
MODULE_NAME, iteration);
return interfacesBindingStorage.assureInitialized().
then(interfacesBindingStorage.staleAll).
then(setIteration).
then(bindingDiscoverer.discoverAll).
then(setFreshDiscoveredBindings).
then(retryOnStaleBindings(RETRY_TRIALS)).
then(engineReportingStrategy.reportDiscovery).
then(interfacesBindingStorage.purgeStale).
then(event.endFastDeviceDiscovery).
catch(errorHandler).
finally(function () {
performing = false;
});
}
function setIteration() {
bindingDiscoverer.setIteration(iteration);
}
function retryOnStaleBindings(count) {
return function () {
var deferred = q.defer();
function _retry() {
var stale = interfacesBindingStorage.listStale();
if (count === 0 || stale.length === 0) {
console.info("%s - (%d): : Exiting retry loop, devices still stale: %d",
MODULE_NAME, iteration, stale.length);
return deferred.resolve();
}
count--;
var ips = stale.map(function(e) {return e.ip;});
var arpPingRetryPromise = bindingDiscoverer.discover(ips, false)
.then(setFreshDiscoveredBindings);
var pingRetryPromise = q.delay(retryInterval) //delay 1s
.then(function () {
return bindingDiscoverer.discover(ips, true);
})
.then(setFreshDiscoveredBindings);
console.info('%s - (%d): Retry Loop: %d. IPs: %s', MODULE_NAME,
iteration, RETRY_TRIALS - count, JSON.stringify(ips));
return q.all([pingRetryPromise, arpPingRetryPromise])
.then(_retry);
}
q.nextTick(_retry);
return deferred.promise;
};
}
function setFreshDiscoveredBindings(bindings) {
for (var interface_index in bindings) {
if (bindings.hasOwnProperty(interface_index)) {
var interface_info = bindings[interface_index];
for (var mac in interface_info) {
if (interface_info.hasOwnProperty(mac)) {
var addresses = interface_info[mac];
for (var i = 0; i < addresses.length; i++) {
var entry = addresses[i];
interfacesBindingStorage.setFresh(mac, entry.ip, entry.host_name);
}
}
}
}
}
}
function errorHandler(err) {
console.error("%s - (%d): Discovery error: %s", MODULE_NAME, iteration, err.message);
console.error(err.stack);
}
return {
performDiscovery: performDiscovery
};
};