-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwebworker.js
224 lines (204 loc) · 8.39 KB
/
webworker.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
'use strict'
var fw
const pCache = 2000 // Wait 'x' miliseconds for TCP/IP window size increase and get cruise Speed
const compFactor= 1.13 // Compensation for HTTP+TCP+IP+ETH overhead. 925000 is how much data is actually carried over 1048576 (1mb) bytes downloaded/uploaded.
// This default value assumes HTTP+TCP+IPv4+ETH with typical MTUs over the Internet.
// You may want to change this if you're going through your local network with a different MTU or if you're going over IPv6
class SpeedTestFramework {
constructor (sharedMemoryBuffer, url) {
this.url = url,
this.pingsAndSeconds = 20,
this.testRun = new Uint8Array(sharedMemoryBuffer,0,1), // TestRun [0]Stop [1]Run [2]Finish [3]Cancel [4]Ping/Jitter [5]Download [6]Upload
this.pingJitt = new Uint8Array(sharedMemoryBuffer,1,1), // Work percentage done of Ping-Jitter
this.download = new Uint8Array(sharedMemoryBuffer,2,1), // Work percentage done of Download
this.upload = new Uint8Array(sharedMemoryBuffer,3,1), // Work percentage done of Upload
this.vPing = new Float32Array(sharedMemoryBuffer,4,1), // Ping value (float)
this.vJitter = new Float32Array(sharedMemoryBuffer,8,1), // Jitter value (float)
this.vDownload = new Float32Array(sharedMemoryBuffer,12,1), // Download value (float)
this.vDownloadCu= new Float32Array(sharedMemoryBuffer,16,1), // Download current value (float)
this.vDownloadMB= new Float32Array(sharedMemoryBuffer,20,1), // Downloaded MB value (float)
this.vUpload = new Float32Array(sharedMemoryBuffer,24,1), // Upload value (float)
this.vUploadCu = new Float32Array(sharedMemoryBuffer,28,1), // Upload current value (float)
this.vUploadMB = new Float32Array(sharedMemoryBuffer,32,1) // Uploaded MB value (float)
}
urlPing = _=> this.url + '?action=ping&rnd=' + Math.random()
urlDownload = _=> this.url + '?action=download&rnd=' + Math.random()
urlUpload = _=> this.url + '?action=upload&rnd=' + Math.random()
}
this.addEventListener('message', post=> {
if( post.data.action=='Start' ) {
fw = new SpeedTestFramework( post.data.memory, post.data.url )
ping()
}
if( post.data.action=='Stop' ) fw.testRun[0]=3
})
function ping() {
fw.testRun[0] = 4
fw.pingJitt[0] = 0
fw.vPing[0] = 0
fw.vJitter[0] = 0
let ping = []
let jitter = []
let missedPing = 0
function doPing() {
let start= performance.now()
fetch( fw.urlPing() ).then( response => {
if( fw.testRun==3 ) return
if( response.ok ) {
let roundtripMs= performance.now()-start
ping.push( roundtripMs )
if( ping.length > 2) jitter.push( Math.abs( ping[ping.length-2] - roundtripMs ) )
fw.pingJitt[0] = (ping.length+missedPing) / fw.pingsAndSeconds * 100
fw.vPing[0] = ping[ ping.length-1 ]
if( jitter.length ) fw.vJitter[0] = jitter.reduce( (ac,e)=> ac+=e ) / jitter.length
} else {
missedPing++
}
if( (ping.length + missedPing) == fw.pingsAndSeconds ) return download()
return doPing()
})
.catch( err => {
missedPing++
if( ( ping.length + missedPing) == fw.pingsAndSeconds ) return download()
return doPing()
})
}
doPing()
}
function download() {
fw.testRun[0] = 5
fw.download[0] = 0
fw.vDownload[0] = 0
fw.vDownloadCu[0] = 0
fw.vDownloadMB[0] = 0
let bytesReceived = 0
let bytesDiscarded = 0
let msDiscarded = 0
let start= performance.now()
function doDownload() {
fetch( fw.urlDownload() ).then( response => {
let reader= response.body.getReader()
reader.read().then( function keepDL(data) {
if( data.done ) return doDownload()
if( fw.testRun==3 ) return reader.cancel()
let elapsed = performance.now() - start
fw.download[0] = elapsed /10 /fw.pingsAndSeconds
bytesReceived += data.value.length
fw.vDownloadMB[0] = bytesReceived/1024/1024
if( elapsed >= pCache ) {
fw.vDownload[0] = ((bytesReceived-bytesDiscarded)/131072) /((elapsed-msDiscarded)/1000)
fw.vDownloadCu[0]= fw.vDownload/8
} else {
bytesDiscarded= bytesReceived
msDiscarded = elapsed
}
if( elapsed > fw.pingsAndSeconds*1000 ) { reader.cancel(); return upload() }
return reader.read().then(keepDL)
})
}).catch( e=>console.log(e) )
}
doDownload()
}
function upload() { // using XHR instead of Fetch API because "Progress" in 2020 still can't be observed with Fetch API
fw.testRun[0] = 6
fw.vUpload[0] = 0
fw.vUploadCu[0] = 0
fw.vUploadMB[0] = 0
let start
let bytesSent = 0
let bytesCurr = 0
let msDiscarded = 0
let bytesDiscarded = 0
let size = 430 // 8*1250*1000 = 3,4MB AWSZeitLimit (Float64Array==8bytes, 430 random float64 numbers, 1000 loops)
let bigbig = new Float64Array(size*1000)
for( let i=0; i<size; ++i) bigbig[i]=Math.random() // 1250*8 bytes of random garbage
for( let i=0; i<1000; ++i) bigbig.copyWithin( size*i , 0, size)
start= performance.now()
send()
function send() {
let xhr = new XMLHttpRequest()
xhr.upload.onprogress = onProgress
xhr.upload.onload = onProgressEnd
xhr.upload.onerror = onErr
xhr.open( 'POST', fw.urlUpload(), true )
xhr.send( bigbig )
function onErr (err) {
console.log('UploadError', err)
if( fw.testRun==3 || fw.testRun==2 ) return
return send()
}
function onProgressEnd(progress){
onProgress(progress)
bytesSent+= progress.total
bytesCurr = 0
if( fw.testRun==3 ) return xhr.abort()
if( fw.testRun==2 ) return
if( fw.upload>=100 ) { fw.upload[0]=100; fw.testRun[0]=2; return console.log('FINISH.') }
return send()
}
function onProgress(progress) {
let elapsed = performance.now() - start
bytesCurr = progress.loaded
fw.upload[0] = elapsed /10 /fw.pingsAndSeconds
fw.vUploadMB[0] = ( bytesSent+bytesCurr ) /1024 /1024
if( elapsed >= pCache ) {
fw.vUpload[0] = ( (bytesSent+bytesCurr-bytesDiscarded)/131072 ) / ( (elapsed-msDiscarded)/1000 )
fw.vUploadCu[0]= fw.vUpload /8
} else {
bytesDiscarded = bytesCurr
msDiscarded = elapsed
}
if( fw.testRun==3 ) return xhr.abort()
if( fw.upload>=100 ) { xhr.abort(); fw.upload[0]=100; fw.testRun[0]=2; return console.log('FINISH') }
}
}
}
function uploadUsingFetchAPI_OnHold() { // See comments on Fetch API status https://github.com/whatwg/fetch/issues/607
rDat.status[0]= 6
rDat.status[3]= 0
var startUL = performance.now()
var bytesSent = 0
var bytesCurr = 0
var msDiscarded = 0
var bytesDiscarded = 0
let size = 1250 // 8*1250*1000 = 10MB (Float64Array==8bytes, 1250 random float64 numbers, 1000 loops)
let bigbig = new Float64Array(size*1000)
for( let i=0; i<size; ++i) bigbig[i]=Math.random() // 1250*8 bytes of random garbage
for( let i=0; i<1000; ++i) bigbig.copyWithin( size*i , 0, size)
let gBlob = new Blob( bigbig ) // 10 MB upload file
let fData = new FormData()
fData.append( "gfile", gBlob )
var controller = new FetchController();
var signal = controller.signal;
function doUpload() {
fetch( fw.urlUpload(), { method:'POST',headers:{"Content-Type":"multipart/form-data" }, body:fData, signal, observer(o) {
o.onrequestprogress=e=> {
let elapsed= performance.now() - startUL
bytesCurr= e.total
rDat.status[5]= elapsed /10 /settings.tUpDown
rDat.floats[7]= (bytesSent+e.total)/1024/1024
if( elapsed >= settings.pCache ) {
rDat.floats[5]= ((bytesSent+e.total-bytesDiscarded)/131072) /((elapsed-msDiscarded)/1000)
rDat.floats[6]= rDat.floats[5]/8
} else {
bytesDiscarded= e.total
msDiscarded= elapsed
}
if( rDat.status[0] == 2 ) controller.abort()
if( elapsed > settings.tUpDown*1000 ) { controller.abort(); rDat.status[0]=1 }
}
o.onstatechange=e=> {
if( o.state=='complete' ) {
bytesSent+= bytesCurr
if( elapsed > settings.tUpDown*1000 ) {
rDat.status[0]=1
} else {
doUpload()
}
}
}
}
}).catch( e=>console.log("Error uploading: "+e.err) )
}
doUpload()
}