UNPKG

domotz-remote-pawn

Version:

Domotz Agent

154 lines (139 loc) 5.46 kB
/** This file is part of Domotz Agent. * Copyright (C) 2025 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/>. **/ const SPEED_CONVERSION_FACTOR = 1e6; module.exports.factory = function (q, platform, path, procUtils, fileManager, log) { var myConsole = log.decorateLogs(); var commandPath = path.join(process.env.DOMOTZ_BIN_DIR, 'domotz_ndt7'); var command = 'domotz_ndt7'; /* Here we have the entire output of the executable * the output is formatted in the following line: * multiple dicts, each on a new line --> no array! * The function generates an array of multiple json dicts */ function parseOutput(data) { var deferred = q.defer(); try { const parseLine = function (line) { return JSON.parse(line); }; const parsedData = data .split('\n') .filter(function (line) { return line.trim() !== '' }) .map(parseLine) .filter(function (parsedLine) { return parsedLine !== null }); deferred.resolve(parsedData); } catch (error) { const errorMessage = 'Parsing error: ' + error.toString(); myConsole.error(errorMessage); deferred.reject(errorMessage); } myConsole.debug('Results ==> %s', data); return deferred.promise; } // The function receives the array of multiple json dicts produced by parseOutput function formatOutput(ndt7Result) { for (var i = 0; i < ndt7Result.length; i++) { var line = ndt7Result[i]; if (line && line.ServerFQDN) { return { raw: null, server: { url: line.ServerFQDN, sponsor: 'MLAB-NDT7', url2: line.ServerFQDN, }, 'speed.upload': line.Upload.Throughput.Value * SPEED_CONVERSION_FACTOR, 'speed.download': line.Download.Throughput.Value * SPEED_CONVERSION_FACTOR, MaxRTT: '0', MinRTT: '0', rttsec: (line.Upload.Latency.Value + line.Download.Latency.Value) / 2, }; } } return {}; } function isAvailable() { var execFilePath = commandPath; if (platform.isWindows()) { execFilePath += '.exe'; } if (!fileManager.getFileStats(execFilePath)) { myConsole.warn('cannot stat %s, ndt7_client is not available', execFilePath); return false; } return true; } return { performSpeedTest: function () { var execFile = command; if (platform.isWindows()) { execFile += '.exe'; } return procUtils .exec(execFile + ' -format=json', {onStdout: stdOutCallback}) .then(parseOutput) .catch(function (error) { myConsole.error('Error during NDT7 speed test execution %s', error.toString()); return {status: 500, message: error.message}; }); }, formatOutput: formatOutput, isAvailable: isAvailable, _parseOutput: parseOutput, _stdOutCallback: stdOutCallback, }; function stdOutCallback(data, deferred) { if (Buffer.isBuffer(data)) { try { data = data.toString('utf8'); } catch (error) { myConsole.error('Error converting buffer to string: %s', error.message); return; } } myConsole.verbose('JSON output string: %s', data); // It may happen that in stdout we found more than one JSON dict, not embedded in an array const parsedData = data .split('\n') .filter(function (line) { return line.trim() !== '' }) // Skip empty lines .map(function (line) { try { return JSON.parse(line); } catch (error) { myConsole.error('Error parsing line: %s', line, error); return null; } }) .filter(function (parsedLine) { return parsedLine !== null }); // Remove null entries parsedData.forEach(function (parsedLine) { if (parsedLine.Key === 'starting') { const testType = parsedLine.Value && parsedLine.Value.Test; if (testType === 'upload' || testType === 'download') { deferred.notify(testType); } } }); } };