/** * This program 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; under version 2 * of the License (non-upgradable). * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (c) 2016-2021 (original work) Open Assessment Technologies SA ; */ define([ 'jquery', 'lodash', 'i18n', 'async', 'util/url', 'taoClientDiagnostic/tools/getConfig', 'taoClientDiagnostic/tools/getLabels', 'taoClientDiagnostic/tools/getStatus' ], function($, _, __, async, urlHelper, getConfig, getLabels, getStatus) { 'use strict'; /** * A binary kilo bytes (KiB) * @type {number} * @private */ const _kilo = 1024; /** * A binary mega bytes (MiB) * @type {number} * @private */ const _mega = _kilo * _kilo; /** * Result of diagnostic * @type {Array} * @private */ let data = []; /** * Default values for the upload speed tester * @type {object} * @private */ const _defaults = { id: 'upload', // Size of data to sent to server during speed test in bytes size: _mega, // Optimal speed in bytes per second optimal: _mega }; /** * A list of thresholds for bandwidth check * @type {Array} * @private */ const _thresholds = [ { threshold: 0, message: __('Low upload speed'), type: 'error' }, { threshold: 33, message: __('Average upload speed'), type: 'warning' }, { threshold: 66, message: __('Good upload speed'), type: 'success' } ]; /** * List of translated texts per level. * The level is provided through the config as a numeric value, starting from 1. * @type {object} * @private */ const _messages = [ // level 1 { title: __('Upload speed'), status: __('Checking upload speed...'), uploadAvg: __('Average upload speed'), uploadMax: __('Max upload speed') } ]; /** * Generate random string of given length * @param {number} length */ function generateStr(length) { let text = ''; const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; for (let i = 0; i < length; i++) { text += possible.charAt(Math.floor(Math.random() * possible.length)); } return text; } /** * Upload generated string to check upload speed. * @param {number} size of string to upload in bytes * @return {object} jqXHR */ function upload(size) { const url = urlHelper.route('upload', 'CompatibilityChecker', 'taoClientDiagnostic', { cache: Date.now() }); const str = generateStr(size); data = []; return $.ajax({ url: url, type: 'POST', data: { upload: str }, xhr: () => { const xhr = new window.XMLHttpRequest(); const startTime = Date.now(); // Upload progress xhr.upload.addEventListener( 'progress', evt => { if (evt.lengthComputable) { const passedTime = Date.now() - startTime; data.push({ time: passedTime, loaded: evt.loaded, speed: (evt.loaded * 8) / _mega / (passedTime / 1000) }); } }, false ); return xhr; } }); } /** * Performs a upload speed test * @param {object} config - Some optional configs * @param {string} [config.id] - The identifier of the test * @param {number} [config.size] - Size of data to sent to server during speed test in bytes * @param {number} [config.optimal] - Optimal speed in bytes per second * @param {string} [config.level] - The intensity level of the test. It will aim which messages list to use. * @returns {object} */ return function uploadTester(config) { const initConfig = getConfig(config, _defaults); const labels = getLabels(_messages, initConfig.level); return { /** * Performs upload speed test, then call a function to provide the result * @param {Function} done */ start(done) { upload(parseInt(initConfig.size, 10)).then(() => { let totalSpeed = 0; let maxSpeed = 0; _.forEach(data, val => { totalSpeed += val.speed; if (maxSpeed < val.speed) { maxSpeed = Math.round(val.speed * 100) / 100; } }); const avgSpeed = Math.round((totalSpeed / data.length) * 100) / 100; const results = { max: maxSpeed, avg: avgSpeed, type: 'upload' }; const status = this.getFeedback(avgSpeed); const summary = this.getSummary(results); done(status, summary, results); }); }, /** * Gets the labels loaded for the tester * @returns {object} */ get labels() { return labels; }, /** * Builds the results summary * @param {object} results * @returns {object} */ getSummary(results) { return { uploadAvg: { message: labels.uploadAvg, value: `${results.avg} Mbps` }, uploadMax: { message: labels.uploadMax, value: `${results.max} Mbps` } }; }, /** * Gets the feedback status for the provided result value * @param {number} result * @returns {object} */ getFeedback(result) { const optimal = initConfig.optimal / _mega; const status = getStatus((100 / optimal) * result, _thresholds); status.id = initConfig.id; status.title = labels.title; return status; } }; }; });