-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
232 additions
and
77 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/* jshint esversion: 6, asi: true, worker: true */ | ||
// WebWorker that runs the ndt7 download test | ||
|
||
// When run by Node.js, we need to import the websocket libraries. | ||
if (typeof WebSocket === 'undefined') { | ||
global.WebSocket = require('isomorphic-ws'); | ||
} | ||
|
||
self.onmessage = function (ev) { | ||
'use strict' | ||
// TODO put the choce between secure and insecure here | ||
//let url = new URL(ev.data.href) | ||
//url.protocol = (url.protocol === 'https:') ? 'wss:' : 'ws:' | ||
//url.pathname = '/ndt/v7/download' | ||
const url = ev.data['ws:///ndt/v7/download'] | ||
const sock = new WebSocket(url, 'net.measurementlab.ndt.v7') | ||
|
||
sock.onclose = function () { | ||
postMessage({ | ||
MsgType: "complete" | ||
}) | ||
} | ||
|
||
sock.onerror = function (ev) { | ||
postMessage({ | ||
MsgType: 'error', | ||
Error: ev, | ||
}) | ||
} | ||
|
||
sock.onopen = function () { | ||
const start = new Date().getTime() | ||
let previous = start | ||
let total = 0 | ||
|
||
sock.onmessage = function (ev) { | ||
total += (ev.data.hasOwnProperty('size')) ? ev.data.size : ev.data.length | ||
// Perform a client-side measurement 4 times per second. | ||
let now = new Date().getTime() | ||
const every = 250 // ms | ||
if (now - previous > every) { | ||
postMessage({ | ||
MsgType: 'measurement', | ||
ClientData: { | ||
ElapsedTime: (now - start) * 1000, // us | ||
NumBytes: total, | ||
MeanClientMbps: total*8 / (now - start) / 1000 // Bytes * 8 bits/byte * 1/(duration in ms) * 1000ms/s * 1 Mb / 1000000 bits = Mb/s | ||
}, | ||
Source: 'client', | ||
}) | ||
previous = now | ||
} | ||
|
||
// Pass along every server-side measurement. | ||
if (typeof ev.data === 'string') { | ||
postMessage({ | ||
MsgType: 'measurement', | ||
ServerMessage: ev.data, | ||
Source: 'server', | ||
}) | ||
} | ||
} | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/** | ||
* @fileoverview A command-line NDT7 client for node.js that uses the official | ||
* NDT7 js libraries. | ||
*/ | ||
|
||
'use strict'; | ||
|
||
const ndt7 = require('./ndt7'); | ||
|
||
ndt7.test({ | ||
downloadMeasurement: function() {}, | ||
serverDiscovery: function() {}, | ||
serverChosen: function(server) { | ||
console.log("Testing to:", { | ||
machine: server.machine, | ||
locations: server.location, | ||
}); | ||
}, | ||
downloadComplete: function(data) { | ||
console.log("Download test is complete:\n\tInstantaneous server bandwidth: ", data.LastServerMeasurement.BBRInfo.BW * 8 / 1000000, "\n\tMean client bandwidth: ", data.LastClientMeasurement.MeanClientMbps) | ||
} | ||
}).then(code => { | ||
process.exit(code); | ||
}) |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
/* jshint esversion: 6, asi: true */ | ||
// ndt7 is a simple ndt7 client API. | ||
|
||
// Install workalikes for APIs that are defined in browsers but not in node.js | ||
if ('undefined' === typeof fetch) { | ||
global.fetch = require('node-fetch'); | ||
} | ||
if ('undefined' === typeof Worker) { | ||
global.Worker = require('workerjs'); | ||
} | ||
|
||
const ndt7 = (function() { | ||
|
||
// cb creates a default-empty callback function, allowing library users to only need to specify callback functions for the events they care about. | ||
var cb = function(name, callbacks) { | ||
if (typeof(callbacks) != "undefined" && name in callbacks) { | ||
return callbacks[name]; | ||
} | ||
return function(arg){ console.log(name, ": ", arg); }; | ||
}; | ||
|
||
var discoverServerURLs = async function(callbacks, config) { | ||
if (config && ('server' in config)) { | ||
return { | ||
'ws:///ndt/v7/download': 'ws://' + config.server + '/ndt/v7/download', | ||
'ws:///ndt/v7/upload': 'ws://' + config.server + '/ndt/v7/upload', | ||
'wss:///ndt/v7/download': 'wss://' + config.server + '/ndt/v7/download', | ||
'wss:///ndt/v7/upload': 'wss://' + config.server + '/ndt/v7/upload' | ||
}; | ||
} | ||
// If no server was specified then use a loadbalancer. If no loadbalancer is specified, use the locate service from Measurement Lab. | ||
const lbURL = (config && (loadbalancer in config)) ? config.loadbalancer : new URL('https://locate-dot-mlab-staging.appspot.com/v2beta1/query/ndt/ndt7'); | ||
callbacks.serverDiscovery({loadbalancer: lbURL}); | ||
const response = await fetch(lbURL); | ||
const js = await response.json(); | ||
if (! ('results' in js) ) { | ||
callbacks.error("Could not understand response from " + lbURL + ": " + js); | ||
return {}; | ||
} | ||
const choice = js.results[Math.floor(Math.random() * js.results.length)]; | ||
callbacks.serverChosen(choice); | ||
return choice.urls; | ||
}; | ||
|
||
return { | ||
test: async function(userCallbacks, config) { | ||
const callbacks = { | ||
error: cb('error', userCallbacks), | ||
serverDiscovery: cb('serverDiscovery', userCallbacks), | ||
serverChosen: cb('serverChosen', userCallbacks), | ||
downloadStart: cb('downloadStart', userCallbacks), | ||
downloadMeasurement: cb('downloadMeasurement', userCallbacks), | ||
downloadComplete: cb('downloadComplete', userCallbacks), | ||
//startingUpload: function(e){}, | ||
//finishingUpload: function(e){}, | ||
}; | ||
|
||
// Starts the asynchronous process of server discovery, allowing other stuff to proceed in the background. | ||
const urlPromise = discoverServerURLs(callbacks, config); | ||
var clientMeasurement, serverMeasurement; | ||
|
||
|
||
const downloadWorker = new Worker('./ndt7-download-worker.js'); | ||
const downloadWorkerPromise = new Promise(resolve => { downloadWorker.resolve = resolve; }); | ||
setTimeout(_ => {downloadWorker.terminate(); downloadWorker.resolve()}, 20000) // 20 seconds | ||
downloadWorker.onmessage = function (ev) { | ||
if (ev.data == null || ev.data.MsgType == 'error') { | ||
downloadWorker.terminate(); | ||
downloadWorker.resolve(); | ||
const errMsg = (ev.data == null) ? 'There was a download error' : ev.data.Error; | ||
callbacks.error(errMsg); | ||
} else if (ev.data.MsgType == 'measurement') { | ||
if (ev.data.Source == 'server') { | ||
serverMeasurement = JSON.parse(ev.data.ServerMessage); | ||
callbacks.downloadMeasurement({ | ||
Source: ev.data.Source, | ||
Data: serverMeasurement, | ||
}); | ||
} else { | ||
clientMeasurement = ev.data.ClientData; | ||
callbacks.downloadMeasurement({ | ||
Source: ev.data.Source, | ||
Data: ev.data.ClientData, | ||
}); | ||
} | ||
} else if (ev.data.MsgType == 'complete') { | ||
downloadWorker.terminate() | ||
downloadWorker.resolve() | ||
callbacks.downloadComplete({ | ||
LastClientMeasurement: clientMeasurement, | ||
LastServerMeasurement: serverMeasurement, | ||
}); | ||
}; | ||
}; | ||
|
||
const urls = await urlPromise; | ||
downloadWorker.postMessage(urls); | ||
|
||
// TODO: await the termination of the downloadWorker. | ||
await downloadWorkerPromise; | ||
// Liveness guarantee - once the promise is resolved, .terminate() has | ||
// been called. | ||
return 0; | ||
} | ||
/*, | ||
// run runs the specified test with the specified base URL and calls | ||
// callback to notify the caller of ndt7 events. | ||
run: function(baseURL, testName, callback) { | ||
callback('starting', {Origin: 'client', Test: testName}) | ||
let done = false | ||
let worker = new Worker('ndt7-' + testName + '.js') | ||
function finish() { | ||
if (!done) { | ||
done = true | ||
if (callback !== undefined) { | ||
callback('complete', {Origin: 'client', Test: testName}) | ||
} | ||
} | ||
} | ||
worker.onmessage = function (ev) { | ||
if (ev.data === null) { | ||
finish() | ||
return | ||
} | ||
callback('measurement', ev.data) | ||
} | ||
// Kill the worker after the timeout. This force the browser to | ||
// close the WebSockets and prevent too-long tests. | ||
setTimeout(function () { | ||
worker.terminate() | ||
finish() | ||
}, 10000) | ||
worker.postMessage({ | ||
href: baseURL, | ||
}) | ||
}*/ | ||
} | ||
}()); | ||
|
||
module.exports = ndt7; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters