Merge branch 'master' into docker
This commit is contained in:
commit
69501e633d
|
@ -1,18 +0,0 @@
|
|||
# EditorConfig is awesome: http://EditorConfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
charset = utf-8
|
||||
|
||||
[*.js]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
|
@ -6,21 +6,34 @@
|
|||
*/
|
||||
|
||||
// data reported to main thread
|
||||
var testStatus = -1 // -1=not started, 0=starting, 1=download test, 2=ping+jitter test, 3=upload test, 4=finished, 5=abort/error
|
||||
var dlStatus = '' // download speed in megabit/s with 2 decimal digits
|
||||
var ulStatus = '' // upload speed in megabit/s with 2 decimal digits
|
||||
var pingStatus = '' // ping in milliseconds with 2 decimal digits
|
||||
var jitterStatus = '' // jitter in milliseconds with 2 decimal digits
|
||||
var clientIp = '' // client's IP address as reported by getIP.php
|
||||
var dlProgress = 0 //progress of download test 0-1
|
||||
var ulProgress = 0 //progress of upload test 0-1
|
||||
var pingProgress = 0 //progress of ping+jitter test 0-1
|
||||
var testId = 'noID' //test ID (sent back by telemetry if used, the string 'noID' otherwise)
|
||||
var testStatus = -1; // -1=not started, 0=starting, 1=download test, 2=ping+jitter test, 3=upload test, 4=finished, 5=abort/error
|
||||
var dlStatus = ""; // download speed in megabit/s with 2 decimal digits
|
||||
var ulStatus = ""; // upload speed in megabit/s with 2 decimal digits
|
||||
var pingStatus = ""; // ping in milliseconds with 2 decimal digits
|
||||
var jitterStatus = ""; // jitter in milliseconds with 2 decimal digits
|
||||
var clientIp = ""; // client's IP address as reported by getIP.php
|
||||
var dlProgress = 0; //progress of download test 0-1
|
||||
var ulProgress = 0; //progress of upload test 0-1
|
||||
var pingProgress = 0; //progress of ping+jitter test 0-1
|
||||
var testId = "noID"; //test ID (sent back by telemetry if used, the string 'noID' otherwise)
|
||||
|
||||
var log='' //telemetry log
|
||||
function tlog(s){if(settings.telemetry_level>=2){log+=Date.now()+': '+s+'\n'}}
|
||||
function tverb(s){if(settings.telemetry_level>=3){log+=Date.now()+': '+s+'\n'}}
|
||||
function twarn(s){if(settings.telemetry_level>=2){log+=Date.now()+' WARN: '+s+'\n';} console.warn(s)}
|
||||
var log = ""; //telemetry log
|
||||
function tlog(s) {
|
||||
if (settings.telemetry_level >= 2) {
|
||||
log += Date.now() + ": " + s + "\n";
|
||||
}
|
||||
}
|
||||
function tverb(s) {
|
||||
if (settings.telemetry_level >= 3) {
|
||||
log += Date.now() + ": " + s + "\n";
|
||||
}
|
||||
}
|
||||
function twarn(s) {
|
||||
if (settings.telemetry_level >= 2) {
|
||||
log += Date.now() + " WARN: " + s + "\n";
|
||||
}
|
||||
console.warn(s);
|
||||
}
|
||||
|
||||
// test settings. can be overridden by sending specific values with the start command
|
||||
var settings = {
|
||||
|
@ -31,12 +44,12 @@ var settings = {
|
|||
time_ulGraceTime: 3, //time to wait in seconds before actually measuring ul speed (wait for buffers to fill)
|
||||
time_dlGraceTime: 1.5, //time to wait in seconds before actually measuring dl speed (wait for TCP window to increase)
|
||||
count_ping: 10, // number of pings to perform in ping test
|
||||
url_dl: 'garbage.php', // path to a large file or garbage.php, used for download test. must be relative to this js file
|
||||
url_ul: 'empty.php', // path to an empty file, used for upload test. must be relative to this js file
|
||||
url_ping: 'empty.php', // path to an empty file, used for ping test. must be relative to this js file
|
||||
url_getIp: 'getIP.php', // path to getIP.php relative to this js file, or a similar thing that outputs the client's ip
|
||||
url_dl: "garbage.php", // path to a large file or garbage.php, used for download test. must be relative to this js file
|
||||
url_ul: "empty.php", // path to an empty file, used for upload test. must be relative to this js file
|
||||
url_ping: "empty.php", // path to an empty file, used for ping test. must be relative to this js file
|
||||
url_getIp: "getIP.php", // path to getIP.php relative to this js file, or a similar thing that outputs the client's ip
|
||||
getIp_ispInfo: true, //if set to true, the server will include ISP info with the IP address
|
||||
getIp_ispInfo_distance: 'km', //km or mi=estimate distance from server in km/mi; set to false to disable distance estimation. getIp_ispInfo must be enabled in order for this to work
|
||||
getIp_ispInfo_distance: "km", //km or mi=estimate distance from server in km/mi; set to false to disable distance estimation. getIp_ispInfo must be enabled in order for this to work
|
||||
xhr_dlMultistream: 10, // number of download streams to use (can be different if enable_quirks is active)
|
||||
xhr_ulMultistream: 3, // number of upload streams to use (can be different if enable_quirks is active)
|
||||
xhr_multistreamDelay: 300, //how much concurrent requests should be delayed
|
||||
|
@ -49,18 +62,20 @@ var settings = {
|
|||
overheadCompensationFactor: 1.06, //can be changed to compensatie for transport overhead. (see doc.md for some other values)
|
||||
useMebibits: false, //if set to true, speed will be reported in mebibits/s instead of megabits/s
|
||||
telemetry_level: 0, // 0=disabled, 1=basic (results only), 2=full (results and timing) 3=debug (results+log)
|
||||
url_telemetry: 'telemetry/telemetry.php', // path to the script that adds telemetry data to the database
|
||||
telemetry_extra: '' //extra data that can be passed to the telemetry through the settings
|
||||
}
|
||||
url_telemetry: "telemetry/telemetry.php", // path to the script that adds telemetry data to the database
|
||||
telemetry_extra: "" //extra data that can be passed to the telemetry through the settings
|
||||
};
|
||||
|
||||
var xhr = null // array of currently active xhr requests
|
||||
var interval = null // timer used in tests
|
||||
var test_pointer = 0 //pointer to the next test to run inside settings.test_order
|
||||
var xhr = null; // array of currently active xhr requests
|
||||
var interval = null; // timer used in tests
|
||||
var test_pointer = 0; //pointer to the next test to run inside settings.test_order
|
||||
|
||||
/*
|
||||
this function is used on URLs passed in the settings to determine whether we need a ? or an & as a separator
|
||||
*/
|
||||
function url_sep (url) { return url.match(/\?/) ? '&' : '?'; }
|
||||
function url_sep(url) {
|
||||
return url.match(/\?/) ? "&" : "?";
|
||||
}
|
||||
|
||||
/*
|
||||
listener for commands from main thread to this worker.
|
||||
|
@ -70,10 +85,12 @@ function url_sep (url) { return url.match(/\?/) ? '&' : '?'; }
|
|||
-start: starts the test. optionally, settings can be passed as JSON.
|
||||
example: start {"time_ul_max":"10", "time_dl_max":"10", "count_ping":"50"}
|
||||
*/
|
||||
this.addEventListener('message', function (e) {
|
||||
var params = e.data.split(' ')
|
||||
if (params[0] === 'status') { // return status
|
||||
postMessage(JSON.stringify({
|
||||
this.addEventListener("message", function(e) {
|
||||
var params = e.data.split(" ");
|
||||
if (params[0] === "status") {
|
||||
// return status
|
||||
postMessage(
|
||||
JSON.stringify({
|
||||
testState: testStatus,
|
||||
dlStatus: dlStatus,
|
||||
ulStatus: ulStatus,
|
||||
|
@ -84,466 +101,600 @@ this.addEventListener('message', function (e) {
|
|||
ulProgress: ulProgress,
|
||||
pingProgress: pingProgress,
|
||||
testId: testId
|
||||
}))
|
||||
})
|
||||
);
|
||||
}
|
||||
if (params[0] === 'start' && testStatus === -1) { // start new test
|
||||
testStatus = 0
|
||||
if (params[0] === "start" && testStatus === -1) {
|
||||
// start new test
|
||||
testStatus = 0;
|
||||
try {
|
||||
// parse settings, if present
|
||||
var s = {}
|
||||
var s = {};
|
||||
try {
|
||||
var ss = e.data.substring(5)
|
||||
if (ss) s = JSON.parse(ss)
|
||||
}catch(e){ twarn('Error parsing custom settings JSON. Please check your syntax') }
|
||||
var ss = e.data.substring(5);
|
||||
if (ss) s = JSON.parse(ss);
|
||||
} catch (e) {
|
||||
twarn("Error parsing custom settings JSON. Please check your syntax");
|
||||
}
|
||||
//copy custom settings
|
||||
for (var key in s) {
|
||||
if(typeof settings[key] !== 'undefined') settings[key]=s[key]; else twarn("Unknown setting ignored: "+key);
|
||||
if (typeof settings[key] !== "undefined") settings[key] = s[key];
|
||||
else twarn("Unknown setting ignored: " + key);
|
||||
}
|
||||
// quirks for specific browsers. apply only if not overridden. more may be added in future releases
|
||||
if (settings.enable_quirks||(typeof s.enable_quirks !== 'undefined' && s.enable_quirks)) {
|
||||
var ua = navigator.userAgent
|
||||
if (settings.enable_quirks || (typeof s.enable_quirks !== "undefined" && s.enable_quirks)) {
|
||||
var ua = navigator.userAgent;
|
||||
if (/Firefox.(\d+\.\d+)/i.test(ua)) {
|
||||
if(typeof s.xhr_ulMultistream === 'undefined'){
|
||||
if (typeof s.xhr_ulMultistream === "undefined") {
|
||||
// ff more precise with 1 upload stream
|
||||
settings.xhr_ulMultistream = 1
|
||||
settings.xhr_ulMultistream = 1;
|
||||
}
|
||||
}
|
||||
if (/Edge.(\d+\.\d+)/i.test(ua)) {
|
||||
if(typeof s.xhr_dlMultistream === 'undefined'){
|
||||
if (typeof s.xhr_dlMultistream === "undefined") {
|
||||
// edge more precise with 3 download streams
|
||||
settings.xhr_dlMultistream = 3
|
||||
settings.xhr_dlMultistream = 3;
|
||||
}
|
||||
}
|
||||
if (/Chrome.(\d+)/i.test(ua) && (!!self.fetch)) {
|
||||
if(typeof s.xhr_dlMultistream === 'undefined'){
|
||||
if (/Chrome.(\d+)/i.test(ua) && !!self.fetch) {
|
||||
if (typeof s.xhr_dlMultistream === "undefined") {
|
||||
// chrome more precise with 5 streams
|
||||
settings.xhr_dlMultistream = 5
|
||||
settings.xhr_dlMultistream = 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (/Edge.(\d+\.\d+)/i.test(ua)) {
|
||||
//Edge 15 introduced a bug that causes onprogress events to not get fired, we have to use the "small chunks" workaround that reduces accuracy
|
||||
settings.forceIE11Workaround = true
|
||||
settings.forceIE11Workaround = true;
|
||||
}
|
||||
if (/Chrome.(\d+)/i.test(ua)&&/Android|iPhone|iPad|iPod|Windows Phone/i.test(ua)){ //cheap af
|
||||
if (/Chrome.(\d+)/i.test(ua) && /Android|iPhone|iPad|iPod|Windows Phone/i.test(ua)) {
|
||||
//cheap af
|
||||
//Chrome mobile introduced a limitation somewhere around version 65, we have to limit XHR upload size to 4 megabytes
|
||||
settings.xhr_ul_blob_megabytes = 4;
|
||||
}
|
||||
//telemetry_level has to be parsed and not just copied
|
||||
if(typeof s.telemetry_level !== 'undefined') settings.telemetry_level = s.telemetry_level === 'basic' ? 1 : s.telemetry_level === 'full' ? 2 : s.telemetry_level === 'debug' ? 3 : 0; // telemetry level
|
||||
if (typeof s.telemetry_level !== "undefined") settings.telemetry_level = s.telemetry_level === "basic" ? 1 : s.telemetry_level === "full" ? 2 : s.telemetry_level === "debug" ? 3 : 0; // telemetry level
|
||||
//transform test_order to uppercase, just in case
|
||||
settings.test_order = settings.test_order.toUpperCase();
|
||||
} catch (e) { twarn('Possible error in custom test settings. Some settings may not be applied. Exception: '+e) }
|
||||
} catch (e) {
|
||||
twarn("Possible error in custom test settings. Some settings may not be applied. Exception: " + e);
|
||||
}
|
||||
// run the tests
|
||||
tverb(JSON.stringify(settings))
|
||||
tverb(JSON.stringify(settings));
|
||||
test_pointer = 0;
|
||||
var iRun=false,dRun=false,uRun=false,pRun=false;
|
||||
var iRun = false,
|
||||
dRun = false,
|
||||
uRun = false,
|
||||
pRun = false;
|
||||
var runNextTest = function() {
|
||||
if (testStatus == 5) return;
|
||||
if(test_pointer>=settings.test_order.length){ //test is finished
|
||||
if (test_pointer >= settings.test_order.length) {
|
||||
//test is finished
|
||||
if (settings.telemetry_level > 0)
|
||||
sendTelemetry(function(id){testStatus=4; if(id!=-1)testId=id})
|
||||
else testStatus=4
|
||||
sendTelemetry(function(id) {
|
||||
testStatus = 4;
|
||||
if (id != -1) testId = id;
|
||||
});
|
||||
else testStatus = 4;
|
||||
return;
|
||||
}
|
||||
switch (settings.test_order.charAt(test_pointer)) {
|
||||
case 'I':{test_pointer++; if(iRun) {runNextTest(); return;} else iRun=true; getIp(runNextTest);} break;
|
||||
case 'D':{test_pointer++; if(dRun) {runNextTest(); return;} else dRun=true; testStatus=1; dlTest(runNextTest);} break;
|
||||
case 'U':{test_pointer++; if(uRun) {runNextTest(); return;} else uRun=true; testStatus=3; ulTest(runNextTest);} break;
|
||||
case 'P':{test_pointer++; if(pRun) {runNextTest(); return;} else pRun=true; testStatus=2; pingTest(runNextTest);} break;
|
||||
case '_':{test_pointer++; setTimeout(runNextTest,1000);} break;
|
||||
default: test_pointer++;
|
||||
case "I":
|
||||
{
|
||||
test_pointer++;
|
||||
if (iRun) {
|
||||
runNextTest();
|
||||
return;
|
||||
} else iRun = true;
|
||||
getIp(runNextTest);
|
||||
}
|
||||
break;
|
||||
case "D":
|
||||
{
|
||||
test_pointer++;
|
||||
if (dRun) {
|
||||
runNextTest();
|
||||
return;
|
||||
} else dRun = true;
|
||||
testStatus = 1;
|
||||
dlTest(runNextTest);
|
||||
}
|
||||
runNextTest()
|
||||
break;
|
||||
case "U":
|
||||
{
|
||||
test_pointer++;
|
||||
if (uRun) {
|
||||
runNextTest();
|
||||
return;
|
||||
} else uRun = true;
|
||||
testStatus = 3;
|
||||
ulTest(runNextTest);
|
||||
}
|
||||
if (params[0] === 'abort') { // abort command
|
||||
tlog('manually aborted')
|
||||
clearRequests() // stop all xhr activity
|
||||
break;
|
||||
case "P":
|
||||
{
|
||||
test_pointer++;
|
||||
if (pRun) {
|
||||
runNextTest();
|
||||
return;
|
||||
} else pRun = true;
|
||||
testStatus = 2;
|
||||
pingTest(runNextTest);
|
||||
}
|
||||
break;
|
||||
case "_":
|
||||
{
|
||||
test_pointer++;
|
||||
setTimeout(runNextTest, 1000);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
test_pointer++;
|
||||
}
|
||||
};
|
||||
runNextTest();
|
||||
}
|
||||
if (params[0] === "abort") {
|
||||
// abort command
|
||||
tlog("manually aborted");
|
||||
clearRequests(); // stop all xhr activity
|
||||
runNextTest = null;
|
||||
if (interval) clearInterval(interval) // clear timer if present
|
||||
if (settings.telemetry_level > 1) sendTelemetry(function(){})
|
||||
testStatus = 5; dlStatus = ''; ulStatus = ''; pingStatus = ''; jitterStatus = '' // set test as aborted
|
||||
if (interval) clearInterval(interval); // clear timer if present
|
||||
if (settings.telemetry_level > 1) sendTelemetry(function() {});
|
||||
testStatus = 5;
|
||||
dlStatus = "";
|
||||
ulStatus = "";
|
||||
pingStatus = "";
|
||||
jitterStatus = ""; // set test as aborted
|
||||
}
|
||||
})
|
||||
});
|
||||
// stops all XHR activity, aggressively
|
||||
function clearRequests() {
|
||||
tverb('stopping pending XHRs')
|
||||
tverb("stopping pending XHRs");
|
||||
if (xhr) {
|
||||
for (var i = 0; i < xhr.length; i++) {
|
||||
try { xhr[i].onprogress = null; xhr[i].onload = null; xhr[i].onerror = null } catch (e) { }
|
||||
try { xhr[i].upload.onprogress = null; xhr[i].upload.onload = null; xhr[i].upload.onerror = null } catch (e) { }
|
||||
try { xhr[i].abort() } catch (e) { }
|
||||
try { delete (xhr[i]) } catch (e) { }
|
||||
try {
|
||||
xhr[i].onprogress = null;
|
||||
xhr[i].onload = null;
|
||||
xhr[i].onerror = null;
|
||||
} catch (e) {}
|
||||
try {
|
||||
xhr[i].upload.onprogress = null;
|
||||
xhr[i].upload.onload = null;
|
||||
xhr[i].upload.onerror = null;
|
||||
} catch (e) {}
|
||||
try {
|
||||
xhr[i].abort();
|
||||
} catch (e) {}
|
||||
try {
|
||||
delete xhr[i];
|
||||
} catch (e) {}
|
||||
}
|
||||
xhr = null
|
||||
xhr = null;
|
||||
}
|
||||
}
|
||||
// gets client's IP using url_getIp, then calls the done function
|
||||
var ipCalled = false // used to prevent multiple accidental calls to getIp
|
||||
var ipCalled = false; // used to prevent multiple accidental calls to getIp
|
||||
var ispInfo = ""; //used for telemetry
|
||||
function getIp(done) {
|
||||
tverb('getIp')
|
||||
if (ipCalled) return; else ipCalled = true // getIp already called?
|
||||
tverb("getIp");
|
||||
if (ipCalled) return;
|
||||
else ipCalled = true; // getIp already called?
|
||||
var startT = new Date().getTime();
|
||||
xhr = new XMLHttpRequest()
|
||||
xhr = new XMLHttpRequest();
|
||||
xhr.onload = function() {
|
||||
tlog('IP: '+xhr.responseText+', took '+(new Date().getTime()-startT)+'ms')
|
||||
tlog("IP: " + xhr.responseText + ", took " + (new Date().getTime() - startT) + "ms");
|
||||
try {
|
||||
var data=JSON.parse(xhr.responseText)
|
||||
clientIp=data.processedString
|
||||
ispInfo=data.rawIspInfo
|
||||
var data = JSON.parse(xhr.responseText);
|
||||
clientIp = data.processedString;
|
||||
ispInfo = data.rawIspInfo;
|
||||
} catch (e) {
|
||||
clientIp = xhr.responseText
|
||||
ispInfo=''
|
||||
}
|
||||
done()
|
||||
clientIp = xhr.responseText;
|
||||
ispInfo = "";
|
||||
}
|
||||
done();
|
||||
};
|
||||
xhr.onerror = function() {
|
||||
tlog('getIp failed, took '+(new Date().getTime()-startT)+'ms')
|
||||
done()
|
||||
}
|
||||
xhr.open('GET', settings.url_getIp + url_sep(settings.url_getIp) + (settings.getIp_ispInfo?("isp=true"+(settings.getIp_ispInfo_distance?("&distance="+settings.getIp_ispInfo_distance+"&"):"&")):"&") + 'r=' + Math.random(), true)
|
||||
xhr.send()
|
||||
tlog("getIp failed, took " + (new Date().getTime() - startT) + "ms");
|
||||
done();
|
||||
};
|
||||
xhr.open("GET", settings.url_getIp + url_sep(settings.url_getIp) + (settings.getIp_ispInfo ? "isp=true" + (settings.getIp_ispInfo_distance ? "&distance=" + settings.getIp_ispInfo_distance + "&" : "&") : "&") + "r=" + Math.random(), true);
|
||||
xhr.send();
|
||||
}
|
||||
// download test, calls done function when it's over
|
||||
var dlCalled = false // used to prevent multiple accidental calls to dlTest
|
||||
var dlCalled = false; // used to prevent multiple accidental calls to dlTest
|
||||
function dlTest(done) {
|
||||
tverb('dlTest')
|
||||
if (dlCalled) return; else dlCalled = true // dlTest already called?
|
||||
tverb("dlTest");
|
||||
if (dlCalled) return;
|
||||
else dlCalled = true; // dlTest already called?
|
||||
var totLoaded = 0.0, // total number of loaded bytes
|
||||
startT = new Date().getTime(), // timestamp when test was started
|
||||
bonusT = 0, //how many milliseconds the test has been shortened by (higher on faster connections)
|
||||
graceTimeDone = false, //set to true after the grace time is past
|
||||
failed = false // set to true if a stream fails
|
||||
xhr = []
|
||||
failed = false; // set to true if a stream fails
|
||||
xhr = [];
|
||||
// function to create a download stream. streams are slightly delayed so that they will not end at the same time
|
||||
var testStream = function(i, delay) {
|
||||
setTimeout(function () {
|
||||
if (testStatus !== 1) return // delayed stream ended up starting after the end of the download test
|
||||
tverb('dl test stream started '+i+' '+delay)
|
||||
var prevLoaded = 0 // number of bytes loaded last time onprogress was called
|
||||
var x = new XMLHttpRequest()
|
||||
xhr[i] = x
|
||||
setTimeout(
|
||||
function() {
|
||||
if (testStatus !== 1) return; // delayed stream ended up starting after the end of the download test
|
||||
tverb("dl test stream started " + i + " " + delay);
|
||||
var prevLoaded = 0; // number of bytes loaded last time onprogress was called
|
||||
var x = new XMLHttpRequest();
|
||||
xhr[i] = x;
|
||||
xhr[i].onprogress = function(event) {
|
||||
tverb('dl stream progress event '+i+' '+event.loaded)
|
||||
if (testStatus !== 1) { try { x.abort() } catch (e) { } } // just in case this XHR is still running after the download test
|
||||
tverb("dl stream progress event " + i + " " + event.loaded);
|
||||
if (testStatus !== 1) {
|
||||
try {
|
||||
x.abort();
|
||||
} catch (e) {}
|
||||
} // just in case this XHR is still running after the download test
|
||||
// progress event, add number of new loaded bytes to totLoaded
|
||||
var loadDiff = event.loaded <= 0 ? 0 : (event.loaded - prevLoaded)
|
||||
if (isNaN(loadDiff) || !isFinite(loadDiff) || loadDiff < 0) return // just in case
|
||||
totLoaded += loadDiff
|
||||
prevLoaded = event.loaded
|
||||
}.bind(this)
|
||||
var loadDiff = event.loaded <= 0 ? 0 : event.loaded - prevLoaded;
|
||||
if (isNaN(loadDiff) || !isFinite(loadDiff) || loadDiff < 0) return; // just in case
|
||||
totLoaded += loadDiff;
|
||||
prevLoaded = event.loaded;
|
||||
}.bind(this);
|
||||
xhr[i].onload = function() {
|
||||
// the large file has been loaded entirely, start again
|
||||
tverb('dl stream finished '+i)
|
||||
try { xhr[i].abort() } catch (e) { } // reset the stream data to empty ram
|
||||
testStream(i, 0)
|
||||
}.bind(this)
|
||||
tverb("dl stream finished " + i);
|
||||
try {
|
||||
xhr[i].abort();
|
||||
} catch (e) {} // reset the stream data to empty ram
|
||||
testStream(i, 0);
|
||||
}.bind(this);
|
||||
xhr[i].onerror = function() {
|
||||
// error
|
||||
tverb('dl stream failed '+i)
|
||||
if (settings.xhr_ignoreErrors === 0) failed=true //abort
|
||||
try { xhr[i].abort() } catch (e) { }
|
||||
delete (xhr[i])
|
||||
if (settings.xhr_ignoreErrors === 1) testStream(i, 0) //restart stream
|
||||
}.bind(this)
|
||||
tverb("dl stream failed " + i);
|
||||
if (settings.xhr_ignoreErrors === 0) failed = true; //abort
|
||||
try {
|
||||
xhr[i].abort();
|
||||
} catch (e) {}
|
||||
delete xhr[i];
|
||||
if (settings.xhr_ignoreErrors === 1) testStream(i, 0); //restart stream
|
||||
}.bind(this);
|
||||
// send xhr
|
||||
try { if (settings.xhr_dlUseBlob) xhr[i].responseType = 'blob'; else xhr[i].responseType = 'arraybuffer' } catch (e) { }
|
||||
xhr[i].open('GET', settings.url_dl + url_sep(settings.url_dl) + 'r=' + Math.random() + '&ckSize=' + settings.garbagePhp_chunkSize, true) // random string to prevent caching
|
||||
xhr[i].send()
|
||||
}.bind(this), 1 + delay)
|
||||
}.bind(this)
|
||||
try {
|
||||
if (settings.xhr_dlUseBlob) xhr[i].responseType = "blob";
|
||||
else xhr[i].responseType = "arraybuffer";
|
||||
} catch (e) {}
|
||||
xhr[i].open("GET", settings.url_dl + url_sep(settings.url_dl) + "r=" + Math.random() + "&ckSize=" + settings.garbagePhp_chunkSize, true); // random string to prevent caching
|
||||
xhr[i].send();
|
||||
}.bind(this),
|
||||
1 + delay
|
||||
);
|
||||
}.bind(this);
|
||||
// open streams
|
||||
for (var i = 0; i < settings.xhr_dlMultistream; i++) {
|
||||
testStream(i, settings.xhr_multistreamDelay * i)
|
||||
testStream(i, settings.xhr_multistreamDelay * i);
|
||||
}
|
||||
// every 200ms, update dlStatus
|
||||
interval = setInterval(function () {
|
||||
tverb('DL: '+dlStatus+(graceTimeDone?'':' (in grace time)'))
|
||||
var t = new Date().getTime() - startT
|
||||
if (graceTimeDone) dlProgress = (t + bonusT) / (settings.time_dl_max * 1000)
|
||||
if (t < 200) return
|
||||
interval = setInterval(
|
||||
function() {
|
||||
tverb("DL: " + dlStatus + (graceTimeDone ? "" : " (in grace time)"));
|
||||
var t = new Date().getTime() - startT;
|
||||
if (graceTimeDone) dlProgress = (t + bonusT) / (settings.time_dl_max * 1000);
|
||||
if (t < 200) return;
|
||||
if (!graceTimeDone) {
|
||||
if (t > 1000 * settings.time_dlGraceTime) {
|
||||
if (totLoaded > 0){ // if the connection is so slow that we didn't get a single chunk yet, do not reset
|
||||
startT = new Date().getTime()
|
||||
bonusT = 0
|
||||
totLoaded = 0.0
|
||||
if (totLoaded > 0) {
|
||||
// if the connection is so slow that we didn't get a single chunk yet, do not reset
|
||||
startT = new Date().getTime();
|
||||
bonusT = 0;
|
||||
totLoaded = 0.0;
|
||||
}
|
||||
graceTimeDone = true;
|
||||
}
|
||||
} else {
|
||||
var speed = totLoaded / (t / 1000.0)
|
||||
var speed = totLoaded / (t / 1000.0);
|
||||
if (settings.time_auto) {
|
||||
//decide how much to shorten the test. Every 200ms, the test is shortened by the bonusT calculated here
|
||||
var bonus=6.4*speed/100000
|
||||
bonusT+=bonus>800?800:bonus
|
||||
var bonus = (6.4 * speed) / 100000;
|
||||
bonusT += bonus > 800 ? 800 : bonus;
|
||||
}
|
||||
//update status
|
||||
dlStatus = ((speed * 8 * settings.overheadCompensationFactor)/(settings.useMebibits?1048576:1000000)).toFixed(2) // speed is multiplied by 8 to go from bytes to bits, overhead compensation is applied, then everything is divided by 1048576 or 1000000 to go to megabits/mebibits
|
||||
if ((((t+ bonusT) / 1000.0) > settings.time_dl_max) || failed) { // test is over, stop streams and timer
|
||||
if (failed || isNaN(dlStatus)) dlStatus = 'Fail'
|
||||
clearRequests()
|
||||
clearInterval(interval)
|
||||
dlProgress = 1
|
||||
tlog('dlTest: '+dlStatus+', took '+(new Date().getTime() - startT)+'ms')
|
||||
done()
|
||||
dlStatus = ((speed * 8 * settings.overheadCompensationFactor) / (settings.useMebibits ? 1048576 : 1000000)).toFixed(2); // speed is multiplied by 8 to go from bytes to bits, overhead compensation is applied, then everything is divided by 1048576 or 1000000 to go to megabits/mebibits
|
||||
if ((t + bonusT) / 1000.0 > settings.time_dl_max || failed) {
|
||||
// test is over, stop streams and timer
|
||||
if (failed || isNaN(dlStatus)) dlStatus = "Fail";
|
||||
clearRequests();
|
||||
clearInterval(interval);
|
||||
dlProgress = 1;
|
||||
tlog("dlTest: " + dlStatus + ", took " + (new Date().getTime() - startT) + "ms");
|
||||
done();
|
||||
}
|
||||
}
|
||||
}.bind(this), 200)
|
||||
}.bind(this),
|
||||
200
|
||||
);
|
||||
}
|
||||
|
||||
// upload test, calls done function whent it's over
|
||||
var ulCalled = false // used to prevent multiple accidental calls to ulTest
|
||||
var ulCalled = false; // used to prevent multiple accidental calls to ulTest
|
||||
function ulTest(done) {
|
||||
tverb('ulTest')
|
||||
if (ulCalled) return; else ulCalled = true // ulTest already called?
|
||||
tverb("ulTest");
|
||||
if (ulCalled) return;
|
||||
else ulCalled = true; // ulTest already called?
|
||||
// garbage data for upload test
|
||||
var r = new ArrayBuffer(1048576)
|
||||
var r = new ArrayBuffer(1048576);
|
||||
var maxInt = Math.pow(2, 32) - 1;
|
||||
try { r = new Uint32Array(r); for (var i = 0; i < r.length; i++)r[i] = Math.random()*maxInt } catch (e) { }
|
||||
var req = []
|
||||
var reqsmall = []
|
||||
for (var i = 0; i < settings.xhr_ul_blob_megabytes; i++) req.push(r)
|
||||
req = new Blob(req)
|
||||
r = new ArrayBuffer(262144)
|
||||
try { r = new Uint32Array(r); for (var i = 0; i < r.length; i++)r[i] = Math.random()*maxInt } catch (e) { }
|
||||
reqsmall.push(r)
|
||||
reqsmall = new Blob(reqsmall)
|
||||
try {
|
||||
r = new Uint32Array(r);
|
||||
for (var i = 0; i < r.length; i++) r[i] = Math.random() * maxInt;
|
||||
} catch (e) {}
|
||||
var req = [];
|
||||
var reqsmall = [];
|
||||
for (var i = 0; i < settings.xhr_ul_blob_megabytes; i++) req.push(r);
|
||||
req = new Blob(req);
|
||||
r = new ArrayBuffer(262144);
|
||||
try {
|
||||
r = new Uint32Array(r);
|
||||
for (var i = 0; i < r.length; i++) r[i] = Math.random() * maxInt;
|
||||
} catch (e) {}
|
||||
reqsmall.push(r);
|
||||
reqsmall = new Blob(reqsmall);
|
||||
var totLoaded = 0.0, // total number of transmitted bytes
|
||||
startT = new Date().getTime(), // timestamp when test was started
|
||||
bonusT = 0, //how many milliseconds the test has been shortened by (higher on faster connections)
|
||||
graceTimeDone = false, //set to true after the grace time is past
|
||||
failed = false // set to true if a stream fails
|
||||
xhr = []
|
||||
failed = false; // set to true if a stream fails
|
||||
xhr = [];
|
||||
// function to create an upload stream. streams are slightly delayed so that they will not end at the same time
|
||||
var testStream = function(i, delay) {
|
||||
setTimeout(function () {
|
||||
if (testStatus !== 3) return // delayed stream ended up starting after the end of the upload test
|
||||
tverb('ul test stream started '+i+' '+delay)
|
||||
var prevLoaded = 0 // number of bytes transmitted last time onprogress was called
|
||||
var x = new XMLHttpRequest()
|
||||
xhr[i] = x
|
||||
var ie11workaround
|
||||
if (settings.forceIE11Workaround) ie11workaround = true; else {
|
||||
setTimeout(
|
||||
function() {
|
||||
if (testStatus !== 3) return; // delayed stream ended up starting after the end of the upload test
|
||||
tverb("ul test stream started " + i + " " + delay);
|
||||
var prevLoaded = 0; // number of bytes transmitted last time onprogress was called
|
||||
var x = new XMLHttpRequest();
|
||||
xhr[i] = x;
|
||||
var ie11workaround;
|
||||
if (settings.forceIE11Workaround) ie11workaround = true;
|
||||
else {
|
||||
try {
|
||||
xhr[i].upload.onprogress
|
||||
ie11workaround = false
|
||||
xhr[i].upload.onprogress;
|
||||
ie11workaround = false;
|
||||
} catch (e) {
|
||||
ie11workaround = true
|
||||
ie11workaround = true;
|
||||
}
|
||||
}
|
||||
if (ie11workaround) {
|
||||
// IE11 workarond: xhr.upload does not work properly, therefore we send a bunch of small 256k requests and use the onload event as progress. This is not precise, especially on fast connections
|
||||
xhr[i].onload = function() {
|
||||
tverb('ul stream progress event (ie11wa)')
|
||||
tverb("ul stream progress event (ie11wa)");
|
||||
totLoaded += reqsmall.size;
|
||||
testStream(i, 0)
|
||||
}
|
||||
testStream(i, 0);
|
||||
};
|
||||
xhr[i].onerror = function() {
|
||||
// error, abort
|
||||
tverb('ul stream failed (ie11wa)')
|
||||
if (settings.xhr_ignoreErrors === 0) failed = true //abort
|
||||
try { xhr[i].abort() } catch (e) { }
|
||||
delete (xhr[i])
|
||||
tverb("ul stream failed (ie11wa)");
|
||||
if (settings.xhr_ignoreErrors === 0) failed = true; //abort
|
||||
try {
|
||||
xhr[i].abort();
|
||||
} catch (e) {}
|
||||
delete xhr[i];
|
||||
if (settings.xhr_ignoreErrors === 1) testStream(i, 0); //restart stream
|
||||
}
|
||||
xhr[i].open('POST', settings.url_ul + url_sep(settings.url_ul) + 'r=' + Math.random(), true) // random string to prevent caching
|
||||
xhr[i].setRequestHeader('Content-Encoding', 'identity') // disable compression (some browsers may refuse it, but data is incompressible anyway)
|
||||
xhr[i].send(reqsmall)
|
||||
};
|
||||
xhr[i].open("POST", settings.url_ul + url_sep(settings.url_ul) + "r=" + Math.random(), true); // random string to prevent caching
|
||||
xhr[i].setRequestHeader("Content-Encoding", "identity"); // disable compression (some browsers may refuse it, but data is incompressible anyway)
|
||||
xhr[i].send(reqsmall);
|
||||
} else {
|
||||
// REGULAR version, no workaround
|
||||
xhr[i].upload.onprogress = function(event) {
|
||||
tverb('ul stream progress event '+i+' '+event.loaded)
|
||||
if (testStatus !== 3) { try { x.abort() } catch (e) { } } // just in case this XHR is still running after the upload test
|
||||
tverb("ul stream progress event " + i + " " + event.loaded);
|
||||
if (testStatus !== 3) {
|
||||
try {
|
||||
x.abort();
|
||||
} catch (e) {}
|
||||
} // just in case this XHR is still running after the upload test
|
||||
// progress event, add number of new loaded bytes to totLoaded
|
||||
var loadDiff = event.loaded <= 0 ? 0 : (event.loaded - prevLoaded)
|
||||
if (isNaN(loadDiff) || !isFinite(loadDiff) || loadDiff < 0) return // just in case
|
||||
totLoaded += loadDiff
|
||||
prevLoaded = event.loaded
|
||||
}.bind(this)
|
||||
var loadDiff = event.loaded <= 0 ? 0 : event.loaded - prevLoaded;
|
||||
if (isNaN(loadDiff) || !isFinite(loadDiff) || loadDiff < 0) return; // just in case
|
||||
totLoaded += loadDiff;
|
||||
prevLoaded = event.loaded;
|
||||
}.bind(this);
|
||||
xhr[i].upload.onload = function() {
|
||||
// this stream sent all the garbage data, start again
|
||||
tverb('ul stream finished '+i)
|
||||
testStream(i, 0)
|
||||
}.bind(this)
|
||||
tverb("ul stream finished " + i);
|
||||
testStream(i, 0);
|
||||
}.bind(this);
|
||||
xhr[i].upload.onerror = function() {
|
||||
tverb('ul stream failed '+i)
|
||||
if (settings.xhr_ignoreErrors === 0) failed=true //abort
|
||||
try { xhr[i].abort() } catch (e) { }
|
||||
delete (xhr[i])
|
||||
if (settings.xhr_ignoreErrors === 1) testStream(i, 0) //restart stream
|
||||
}.bind(this)
|
||||
tverb("ul stream failed " + i);
|
||||
if (settings.xhr_ignoreErrors === 0) failed = true; //abort
|
||||
try {
|
||||
xhr[i].abort();
|
||||
} catch (e) {}
|
||||
delete xhr[i];
|
||||
if (settings.xhr_ignoreErrors === 1) testStream(i, 0); //restart stream
|
||||
}.bind(this);
|
||||
// send xhr
|
||||
xhr[i].open('POST', settings.url_ul + url_sep(settings.url_ul) + 'r=' + Math.random(), true) // random string to prevent caching
|
||||
xhr[i].setRequestHeader('Content-Encoding', 'identity') // disable compression (some browsers may refuse it, but data is incompressible anyway)
|
||||
xhr[i].send(req)
|
||||
xhr[i].open("POST", settings.url_ul + url_sep(settings.url_ul) + "r=" + Math.random(), true); // random string to prevent caching
|
||||
xhr[i].setRequestHeader("Content-Encoding", "identity"); // disable compression (some browsers may refuse it, but data is incompressible anyway)
|
||||
xhr[i].send(req);
|
||||
}
|
||||
}.bind(this), 1)
|
||||
}.bind(this)
|
||||
}.bind(this),
|
||||
1
|
||||
);
|
||||
}.bind(this);
|
||||
// open streams
|
||||
for (var i = 0; i < settings.xhr_ulMultistream; i++) {
|
||||
testStream(i, settings.xhr_multistreamDelay * i)
|
||||
testStream(i, settings.xhr_multistreamDelay * i);
|
||||
}
|
||||
// every 200ms, update ulStatus
|
||||
interval = setInterval(function () {
|
||||
tverb('UL: '+ulStatus+(graceTimeDone?'':' (in grace time)'))
|
||||
var t = new Date().getTime() - startT
|
||||
if (graceTimeDone) ulProgress = (t + bonusT) / (settings.time_ul_max * 1000)
|
||||
if (t < 200) return
|
||||
interval = setInterval(
|
||||
function() {
|
||||
tverb("UL: " + ulStatus + (graceTimeDone ? "" : " (in grace time)"));
|
||||
var t = new Date().getTime() - startT;
|
||||
if (graceTimeDone) ulProgress = (t + bonusT) / (settings.time_ul_max * 1000);
|
||||
if (t < 200) return;
|
||||
if (!graceTimeDone) {
|
||||
if (t > 1000 * settings.time_ulGraceTime) {
|
||||
if (totLoaded > 0){ // if the connection is so slow that we didn't get a single chunk yet, do not reset
|
||||
startT = new Date().getTime()
|
||||
bonusT = 0
|
||||
totLoaded = 0.0
|
||||
if (totLoaded > 0) {
|
||||
// if the connection is so slow that we didn't get a single chunk yet, do not reset
|
||||
startT = new Date().getTime();
|
||||
bonusT = 0;
|
||||
totLoaded = 0.0;
|
||||
}
|
||||
graceTimeDone = true;
|
||||
}
|
||||
} else {
|
||||
var speed = totLoaded / (t / 1000.0)
|
||||
var speed = totLoaded / (t / 1000.0);
|
||||
if (settings.time_auto) {
|
||||
//decide how much to shorten the test. Every 200ms, the test is shortened by the bonusT calculated here
|
||||
var bonus=6.4*speed/100000
|
||||
bonusT+=bonus>800?800:bonus
|
||||
var bonus = (6.4 * speed) / 100000;
|
||||
bonusT += bonus > 800 ? 800 : bonus;
|
||||
}
|
||||
//update status
|
||||
ulStatus = ((speed * 8 * settings.overheadCompensationFactor)/(settings.useMebibits?1048576:1000000)).toFixed(2) // speed is multiplied by 8 to go from bytes to bits, overhead compensation is applied, then everything is divided by 1048576 or 1000000 to go to megabits/mebibits
|
||||
if ((((t + bonusT) / 1000.0) > settings.time_ul_max) || failed) { // test is over, stop streams and timer
|
||||
if (failed || isNaN(ulStatus)) ulStatus = 'Fail'
|
||||
clearRequests()
|
||||
clearInterval(interval)
|
||||
ulProgress = 1
|
||||
tlog('ulTest: '+ulStatus+', took '+(new Date().getTime() - startT)+'ms')
|
||||
done()
|
||||
ulStatus = ((speed * 8 * settings.overheadCompensationFactor) / (settings.useMebibits ? 1048576 : 1000000)).toFixed(2); // speed is multiplied by 8 to go from bytes to bits, overhead compensation is applied, then everything is divided by 1048576 or 1000000 to go to megabits/mebibits
|
||||
if ((t + bonusT) / 1000.0 > settings.time_ul_max || failed) {
|
||||
// test is over, stop streams and timer
|
||||
if (failed || isNaN(ulStatus)) ulStatus = "Fail";
|
||||
clearRequests();
|
||||
clearInterval(interval);
|
||||
ulProgress = 1;
|
||||
tlog("ulTest: " + ulStatus + ", took " + (new Date().getTime() - startT) + "ms");
|
||||
done();
|
||||
}
|
||||
}
|
||||
}.bind(this), 200)
|
||||
}.bind(this),
|
||||
200
|
||||
);
|
||||
}
|
||||
// ping+jitter test, function done is called when it's over
|
||||
var ptCalled = false // used to prevent multiple accidental calls to pingTest
|
||||
var ptCalled = false; // used to prevent multiple accidental calls to pingTest
|
||||
function pingTest(done) {
|
||||
tverb('pingTest')
|
||||
if (ptCalled) return; else ptCalled = true // pingTest already called?
|
||||
tverb("pingTest");
|
||||
if (ptCalled) return;
|
||||
else ptCalled = true; // pingTest already called?
|
||||
var startT = new Date().getTime(); //when the test was started
|
||||
var prevT = null // last time a pong was received
|
||||
var ping = 0.0 // current ping value
|
||||
var jitter = 0.0 // current jitter value
|
||||
var i = 0 // counter of pongs received
|
||||
var prevInstspd = 0 // last ping time, used for jitter calculation
|
||||
xhr = []
|
||||
var prevT = null; // last time a pong was received
|
||||
var ping = 0.0; // current ping value
|
||||
var jitter = 0.0; // current jitter value
|
||||
var i = 0; // counter of pongs received
|
||||
var prevInstspd = 0; // last ping time, used for jitter calculation
|
||||
xhr = [];
|
||||
// ping function
|
||||
var doPing = function() {
|
||||
tverb('ping')
|
||||
pingProgress = i / settings.count_ping
|
||||
prevT = new Date().getTime()
|
||||
xhr[0] = new XMLHttpRequest()
|
||||
tverb("ping");
|
||||
pingProgress = i / settings.count_ping;
|
||||
prevT = new Date().getTime();
|
||||
xhr[0] = new XMLHttpRequest();
|
||||
xhr[0].onload = function() {
|
||||
// pong
|
||||
tverb('pong')
|
||||
tverb("pong");
|
||||
if (i === 0) {
|
||||
prevT = new Date().getTime() // first pong
|
||||
prevT = new Date().getTime(); // first pong
|
||||
} else {
|
||||
var instspd = new Date().getTime() - prevT
|
||||
var instspd = new Date().getTime() - prevT;
|
||||
if (settings.ping_allowPerformanceApi) {
|
||||
try {
|
||||
//try to get accurate performance timing using performance api
|
||||
var p=performance.getEntries()
|
||||
p=p[p.length-1]
|
||||
var d = p.responseStart - p.requestStart //best precision: chromium-based
|
||||
if (d<=0) d=p.duration //edge: not so good precision because it also considers the overhead and there is no way to avoid it
|
||||
if (d>0&&d<instspd) instspd=d
|
||||
var p = performance.getEntries();
|
||||
p = p[p.length - 1];
|
||||
var d = p.responseStart - p.requestStart; //best precision: chromium-based
|
||||
if (d <= 0) d = p.duration; //edge: not so good precision because it also considers the overhead and there is no way to avoid it
|
||||
if (d > 0 && d < instspd) instspd = d;
|
||||
} catch (e) {
|
||||
//if not possible, keep the estimate
|
||||
//firefox can't access performance api from worker: worst precision
|
||||
tverb('Performance API not supported, using estimate')
|
||||
tverb("Performance API not supported, using estimate");
|
||||
}
|
||||
}
|
||||
var instjitter = Math.abs(instspd - prevInstspd)
|
||||
if (i === 1) ping = instspd; /* first ping, can't tell jitter yet*/ else {
|
||||
ping = instspd < ping ? instspd : ping * 0.8 + instspd * 0.2 // update ping, weighted average. if the instant ping is lower than the current average, it is set to that value instead of averaging
|
||||
if(i === 2) jitter=instjitter //discard the first jitter measurement because it might be much higher than it should be
|
||||
else
|
||||
jitter = instjitter > jitter ? (jitter * 0.3 + instjitter * 0.7) : (jitter * 0.8 + instjitter * 0.2) // update jitter, weighted average. spikes in ping values are given more weight.
|
||||
var instjitter = Math.abs(instspd - prevInstspd);
|
||||
if (i === 1) ping = instspd;
|
||||
/* first ping, can't tell jitter yet*/ else {
|
||||
ping = instspd < ping ? instspd : ping * 0.8 + instspd * 0.2; // update ping, weighted average. if the instant ping is lower than the current average, it is set to that value instead of averaging
|
||||
if (i === 2) jitter = instjitter;
|
||||
//discard the first jitter measurement because it might be much higher than it should be
|
||||
else jitter = instjitter > jitter ? jitter * 0.3 + instjitter * 0.7 : jitter * 0.8 + instjitter * 0.2; // update jitter, weighted average. spikes in ping values are given more weight.
|
||||
}
|
||||
prevInstspd = instspd
|
||||
prevInstspd = instspd;
|
||||
}
|
||||
pingStatus = ping.toFixed(2)
|
||||
jitterStatus = jitter.toFixed(2)
|
||||
i++
|
||||
tverb('ping: '+pingStatus+' jitter: '+jitterStatus)
|
||||
if (i < settings.count_ping) doPing(); else { // more pings to do?
|
||||
pingProgress = 1
|
||||
tlog('ping: '+pingStatus+' jitter: '+jitterStatus+', took '+(new Date().getTime()-startT)+'ms')
|
||||
done()
|
||||
pingStatus = ping.toFixed(2);
|
||||
jitterStatus = jitter.toFixed(2);
|
||||
i++;
|
||||
tverb("ping: " + pingStatus + " jitter: " + jitterStatus);
|
||||
if (i < settings.count_ping) doPing();
|
||||
else {
|
||||
// more pings to do?
|
||||
pingProgress = 1;
|
||||
tlog("ping: " + pingStatus + " jitter: " + jitterStatus + ", took " + (new Date().getTime() - startT) + "ms");
|
||||
done();
|
||||
}
|
||||
}.bind(this)
|
||||
}.bind(this);
|
||||
xhr[0].onerror = function() {
|
||||
// a ping failed, cancel test
|
||||
tverb('ping failed')
|
||||
if (settings.xhr_ignoreErrors === 0) { //abort
|
||||
pingStatus = 'Fail'
|
||||
jitterStatus = 'Fail'
|
||||
clearRequests()
|
||||
tlog('ping test failed, took '+(new Date().getTime()-startT)+'ms')
|
||||
pingProgress = 1
|
||||
done()
|
||||
tverb("ping failed");
|
||||
if (settings.xhr_ignoreErrors === 0) {
|
||||
//abort
|
||||
pingStatus = "Fail";
|
||||
jitterStatus = "Fail";
|
||||
clearRequests();
|
||||
tlog("ping test failed, took " + (new Date().getTime() - startT) + "ms");
|
||||
pingProgress = 1;
|
||||
done();
|
||||
}
|
||||
if (settings.xhr_ignoreErrors === 1) doPing() //retry ping
|
||||
if (settings.xhr_ignoreErrors === 2){ //ignore failed ping
|
||||
i++
|
||||
if (i < settings.count_ping) doPing(); else { // more pings to do?
|
||||
pingProgress = 1
|
||||
tlog('ping: '+pingStatus+' jitter: '+jitterStatus+', took '+(new Date().getTime()-startT)+'ms')
|
||||
done()
|
||||
if (settings.xhr_ignoreErrors === 1) doPing(); //retry ping
|
||||
if (settings.xhr_ignoreErrors === 2) {
|
||||
//ignore failed ping
|
||||
i++;
|
||||
if (i < settings.count_ping) doPing();
|
||||
else {
|
||||
// more pings to do?
|
||||
pingProgress = 1;
|
||||
tlog("ping: " + pingStatus + " jitter: " + jitterStatus + ", took " + (new Date().getTime() - startT) + "ms");
|
||||
done();
|
||||
}
|
||||
}
|
||||
}.bind(this)
|
||||
}.bind(this);
|
||||
// send xhr
|
||||
xhr[0].open('GET', settings.url_ping + url_sep(settings.url_ping) + 'r=' + Math.random(), true) // random string to prevent caching
|
||||
xhr[0].send()
|
||||
}.bind(this)
|
||||
doPing() // start first ping
|
||||
xhr[0].open("GET", settings.url_ping + url_sep(settings.url_ping) + "r=" + Math.random(), true); // random string to prevent caching
|
||||
xhr[0].send();
|
||||
}.bind(this);
|
||||
doPing(); // start first ping
|
||||
}
|
||||
// telemetry
|
||||
function sendTelemetry(done) {
|
||||
if (settings.telemetry_level < 1) return
|
||||
xhr = new XMLHttpRequest()
|
||||
if (settings.telemetry_level < 1) return;
|
||||
xhr = new XMLHttpRequest();
|
||||
xhr.onload = function() {
|
||||
try {
|
||||
var parts=xhr.responseText.split(' ')
|
||||
if(parts[0]=='id'){
|
||||
var parts = xhr.responseText.split(" ");
|
||||
if (parts[0] == "id") {
|
||||
try {
|
||||
var id=Number(parts[1])
|
||||
if(!isNaN(id)) done(id); else done(-1);
|
||||
}catch(e){done(-1)}
|
||||
var id = Number(parts[1]);
|
||||
if (!isNaN(id)) done(id);
|
||||
else done(-1);
|
||||
} catch (e) {
|
||||
done(-1);
|
||||
}
|
||||
} else done(-1);
|
||||
} catch (e) {
|
||||
done(-1)
|
||||
done(-1);
|
||||
}
|
||||
}
|
||||
xhr.onerror = function () { console.log('TELEMETRY ERROR '+xhr.status); done(-1) }
|
||||
xhr.open('POST', settings.url_telemetry+url_sep(settings.url_telemetry)+"r="+Math.random(), true);
|
||||
};
|
||||
xhr.onerror = function() {
|
||||
console.log("TELEMETRY ERROR " + xhr.status);
|
||||
done(-1);
|
||||
};
|
||||
xhr.open("POST", settings.url_telemetry + url_sep(settings.url_telemetry) + "r=" + Math.random(), true);
|
||||
var telemetryIspInfo = {
|
||||
processedString: clientIp,
|
||||
rawIspInfo: (typeof ispInfo === "object")?ispInfo:""
|
||||
}
|
||||
rawIspInfo: typeof ispInfo === "object" ? ispInfo : ""
|
||||
};
|
||||
try {
|
||||
var fd = new FormData()
|
||||
fd.append('ispinfo', JSON.stringify(telemetryIspInfo));
|
||||
fd.append('dl', dlStatus)
|
||||
fd.append('ul', ulStatus)
|
||||
fd.append('ping', pingStatus)
|
||||
fd.append('jitter', jitterStatus)
|
||||
fd.append('log', settings.telemetry_level>1?log:"")
|
||||
fd.append('extra', settings.telemetry_extra);
|
||||
xhr.send(fd)
|
||||
var fd = new FormData();
|
||||
fd.append("ispinfo", JSON.stringify(telemetryIspInfo));
|
||||
fd.append("dl", dlStatus);
|
||||
fd.append("ul", ulStatus);
|
||||
fd.append("ping", pingStatus);
|
||||
fd.append("jitter", jitterStatus);
|
||||
fd.append("log", settings.telemetry_level > 1 ? log : "");
|
||||
fd.append("extra", settings.telemetry_extra);
|
||||
xhr.send(fd);
|
||||
} catch (ex) {
|
||||
var postData = 'extra='+encodeURIComponent(settings.telemetry_extra)+'&ispinfo='+encodeURIComponent(JSON.stringify(telemetryIspInfo))+'&dl='+encodeURIComponent(dlStatus)+'&ul='+encodeURIComponent(ulStatus)+'&ping='+encodeURIComponent(pingStatus)+'&jitter='+encodeURIComponent(jitterStatus)+'&log='+encodeURIComponent(settings.telemetry_level>1?log:'')
|
||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
|
||||
xhr.send(postData)
|
||||
var postData = "extra=" + encodeURIComponent(settings.telemetry_extra) + "&ispinfo=" + encodeURIComponent(JSON.stringify(telemetryIspInfo)) + "&dl=" + encodeURIComponent(dlStatus) + "&ul=" + encodeURIComponent(ulStatus) + "&ping=" + encodeURIComponent(pingStatus) + "&jitter=" + encodeURIComponent(jitterStatus) + "&log=" + encodeURIComponent(settings.telemetry_level > 1 ? log : "");
|
||||
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
xhr.send(postData);
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in a new issue