domotz-remote-pawn
Version:
Domotz Agent
243 lines (217 loc) • 9.59 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/>.
*
* Created by Iacopo Papalini <ipapalini@domotz.com> on 10/09/15.
*/
const MODULE_NAME = 'SPEED_TEST';
var lockSeed = Math.random();
var speedTest = function (message, resourceLocator) {
const md5 = resourceLocator.utils.random.md5;
const time = resourceLocator.utils.time;
const mutex = resourceLocator.utils.mutex;
const engineClient = resourceLocator.engineRequest;
const settingsManager = resourceLocator.settingsManager;
const ndtServers = resourceLocator.networkTools.ndtServers;
const speedTest = resourceLocator.networkTools.speedTest;
const mlabTest = resourceLocator.networkTools.mlabSpeedTest;
const fast = resourceLocator.networkTools.fastSpeedTest;
const ooklaServers = resourceLocator.networkTools.ooklaServers;
const ooklaSpeedTest = resourceLocator.networkTools.ooklaSpeedTest;
const ndt7SpeedTest = resourceLocator.networkTools.ndt7SpeedTest;
const ndt7Enabled = settingsManager.isNdt7SuiteEnabled() && ndt7SpeedTest.isAvailable();
var myConsole = resourceLocator.log.decorateLogs();
const cid = message.correlationId || 'From API';
const serverId = message.payload.server_id;
const nonInteractive = message.non_interactive;
var getSpeedTestSuite = resourceLocator.networkTools.speedTest.getSpeedTestSuite;
var SPEED_TEST_SUITES = resourceLocator.networkTools.speedTest.SPEED_TEST_SUITES;
const speedTestLatency = resourceLocator.latencyMeasurement;
var lockId = md5(lockSeed.toString());
function lock() {
return mutex.lock(MODULE_NAME, lockId);
}
function unlock() {
mutex.unlock(MODULE_NAME, lockId);
}
var results = {
stats: {
start: new Date(),
end: null,
elapsed_milliseconds: null,
},
speedTest: {},
};
function copyResults(ndtInfo) {
myConsole.debug('NDT INFO %s', JSON.stringify(ndtInfo));
results.stats.end = new Date();
results.stats.elapsed_milliseconds = time.getDiff(results.stats);
results.speedTest = speedTest.ndtInfoIntoDTO(ndtInfo);
return speedTest.filterItems(ndtInfo);
}
function processOoklaResult(data, cb) {
function sendResults(result) {
var items = copyResults(result);
cb(results);
engineClient.sendWithPromise('/network/speed-test', 'POST', items);
}
if (data.blacklist && data.blacklist.length > 0) {
myConsole.warn('(%s): Blacklist servers => %s', cid, JSON.stringify(data.blacklist));
ooklaServers.blacklistServers(data.blacklist);
}
if (!data.error) {
if (data.server) {
/* store it as preferred server to perform the interactive speed test */
ooklaServers.setServerAsPreferred(data.server);
}
myConsole.debug('(%s): Speed test success', cid);
sendResults(data.result);
} else {
myConsole.debug('(%s): Speed test failure => %s', cid, data.error);
cb(data.error, data.error);
}
}
function callLegacyTest(msg, cb) {
ooklaSpeedTest.main(
msg,
function (data) {
speedTestLatency.reportData();
unlock();
processOoklaResult(data, cb);
},
function (currentStage) {
speedTestLatency.performPingForState(currentStage).catch(handleLatencyTestError);
}
);
}
function ndtTest(callback) {
ndtServers
.findById(serverId)
.then(speedTest.performSpeedTest)
.then(copyResults)
.then(function (items) {
myConsole.debug('%s NDT CB with results %s', JSON.stringify(results));
callback(results);
myConsole.debug('%s NDT Send with promise %s', JSON.stringify(items));
return engineClient.sendWithPromise('/network/speed-test', 'POST', items);
})
.catch(function (err) {
callback(null, err);
});
}
function interactiveLegacyTest(callback) {
myConsole.info('(%s): interactive mode, searching for %s', cid, serverId);
ooklaServers
.findById(serverId)
.then(function (server) {
myConsole.info('(%s): found server: %s', cid, JSON.stringify(server));
var msg = { bestServer: server, serverList: null };
callLegacyTest(msg, callback);
})
.catch(function () {
myConsole.error('Error finding server');
});
}
function nonInteractiveLegacyTest(callback) {
myConsole.info('%s (%s): Not interactive mode, selecting N closest servers', MODULE_NAME, cid);
ooklaServers
.getNearestServers()
.then(function (serverList) {
myConsole.info('(%s): Nearest Server: %s', cid, JSON.stringify(serverList));
var msg = {
bestServer: null,
serverList: serverList,
};
callLegacyTest(msg, callback);
})
.catch(function () {
myConsole.error('Error getting nearest server');
});
}
function handleLatencyTestError(error) {
myConsole.error('Latency test failed: %s', error.toString());
}
function reportSpeedTestData(items) {
return engineClient.sendWithPromise('/network/speed-test', 'POST', items);
}
return {
describe: function () {
return cid + ' - ' + MODULE_NAME;
},
execute: function (callback) {
if (!lock()) {
var msg = MODULE_NAME + ' - (' + cid + '): Another Speed test is currently running';
myConsole.warn(msg);
return callback(null, {
status: 409,
message: msg,
});
}
var speedTestSuite = getSpeedTestSuite(message);
if (speedTestSuite === SPEED_TEST_SUITES.NDT) {
ndtTest(callback);
} else if (speedTestSuite === SPEED_TEST_SUITES.MLAB) {
var suite = ndt7Enabled ? ndt7SpeedTest : mlabTest;
var suiteName = ndt7Enabled ? 'NDT7' : 'MLAB';
myConsole.debug('selected %s as speed test suite', suiteName);
suite
.performSpeedTest()
.progress(function (currentStage) {
if (currentStage === 'download' || currentStage === 'upload') {
speedTestLatency.performPingForState(currentStage).catch(handleLatencyTestError);
} else {
speedTestLatency.performPingForState(currentStage);
}
})
.then(suite.formatOutput)
.then(copyResults)
.then(function (items) {
speedTestLatency.reportData();
unlock();
myConsole.debug('%s CB with results %s', suiteName, JSON.stringify(results));
callback(results);
myConsole.debug('%s Send with promise %s', suiteName, JSON.stringify(items));
return reportSpeedTestData(items);
})
.catch(function (error) {
callback(null, error);
myConsole.error('Error performing speed test %s', error.toString());
unlock();
});
} else if (speedTestSuite === SPEED_TEST_SUITES.FAST) {
fast.performSpeedTest()
.progress(function (currentStage) {
speedTestLatency.performPingForState(currentStage).catch(handleLatencyTestError);
})
.then(fast.formatOutput)
.then(copyResults)
.then(function (items) {
speedTestLatency.reportData();
unlock();
callback(results);
return reportSpeedTestData(items);
})
.catch(function (error) {
myConsole.error('Error performing speed test %s', error.toString());
unlock();
});
} else if (speedTestSuite === SPEED_TEST_SUITES.OOKLA) {
nonInteractive ? nonInteractiveLegacyTest(callback) : interactiveLegacyTest(callback);
}
},
getSpeedTestSuite: getSpeedTestSuite,
};
};
module.exports.command = speedTest;