Skip to content

Commit 551db60

Browse files
committed
Added the cloudflare.js task
1 parent fb95f35 commit 551db60

File tree

1 file changed

+210
-0
lines changed

1 file changed

+210
-0
lines changed

server/tasks/cloudflare.js

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
/**
2+
*
3+
* This file is part of speed-cloudflare-cli (https://github.com/KNawm/speed-cloudflare-cli),
4+
* which is released under the MIT License.
5+
*
6+
* This file has been modified to be used inside MySpeed.
7+
*
8+
* Copyright (c) 2020 Tomás Arias
9+
*
10+
* Permission is hereby granted, free of charge, to any person obtaining a copy
11+
* of this software and associated documentation files (the "Software"), to deal
12+
* in the Software without restriction, including without limitation the rights
13+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14+
* copies of the Software, and to permit persons to whom the Software is
15+
* furnished to do so, subject to the following conditions:
16+
*
17+
* The above copyright notice and this permission notice shall be included in all
18+
* copies or substantial portions of the Software.
19+
*
20+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26+
* SOFTWARE.
27+
*/
28+
const { performance } = require("perf_hooks");
29+
const https = require("https");
30+
31+
function average(values) {
32+
let total = 0;
33+
34+
for (let i = 0; i < values.length; i += 1) {
35+
total += values[i];
36+
}
37+
38+
return total / values.length;
39+
}
40+
41+
function median(values) {
42+
const half = Math.floor(values.length / 2);
43+
44+
values.sort((a, b) => a - b);
45+
46+
if (values.length % 2) return values[half];
47+
48+
return (values[half - 1] + values[half]) / 2;
49+
}
50+
51+
function quartile(values, percentile) {
52+
values.sort((a, b) => a - b);
53+
const pos = (values.length - 1) * percentile;
54+
const base = Math.floor(pos);
55+
const rest = pos - base;
56+
57+
if (values[base + 1] !== undefined) {
58+
return values[base] + rest * (values[base + 1] - values[base]);
59+
}
60+
61+
return values[base];
62+
}
63+
64+
function request(options, data = "") {
65+
let started;
66+
let dnsLookup;
67+
let tcpHandshake;
68+
let sslHandshake;
69+
let ttfb;
70+
let ended;
71+
72+
options.agent = new https.Agent(options);
73+
74+
return new Promise((resolve, reject) => {
75+
started = performance.now();
76+
const req = https.request(options, (res) => {
77+
res.once("readable", () => {
78+
ttfb = performance.now();
79+
});
80+
res.on("data", () => {});
81+
res.on("end", () => {
82+
ended = performance.now();
83+
resolve([started, dnsLookup, tcpHandshake, sslHandshake, ttfb, ended, parseFloat(res.headers["server-timing"].slice(22))]);
84+
});
85+
});
86+
87+
req.on("socket", (socket) => {
88+
socket.on("lookup", () => {
89+
dnsLookup = performance.now();
90+
});
91+
socket.on("connect", () => {
92+
tcpHandshake = performance.now();
93+
});
94+
socket.on("secureConnect", () => {
95+
sslHandshake = performance.now();
96+
});
97+
});
98+
99+
req.on("error", (error) => {
100+
reject(error);
101+
});
102+
103+
req.write(data);
104+
req.end();
105+
});
106+
}
107+
108+
function download(bytes) {
109+
const options = {
110+
hostname: "speed.cloudflare.com",
111+
path: `/__down?bytes=${bytes}`,
112+
method: "GET",
113+
};
114+
115+
return request(options);
116+
}
117+
118+
function upload(bytes) {
119+
const data = "0".repeat(bytes);
120+
const options = {
121+
hostname: "speed.cloudflare.com",
122+
path: "/__up",
123+
method: "POST",
124+
headers: {
125+
"Content-Length": Buffer.byteLength(data),
126+
},
127+
};
128+
129+
return request(options, data);
130+
}
131+
132+
function measureSpeed(bytes, duration) {
133+
return (bytes * 8) / (duration / 1000) / 1e6;
134+
}
135+
136+
async function measureLatency() {
137+
const measurements = [];
138+
139+
for (let i = 0; i < 20; i += 1) {
140+
await download(1000).then(
141+
(response) => {
142+
// TTFB - Server processing time
143+
measurements.push(response[4] - response[0] - response[6]);
144+
},
145+
(error) => {
146+
console.log(`Error: ${error}`);
147+
},
148+
);
149+
}
150+
151+
return [Math.min(...measurements), Math.max(...measurements), average(measurements), median(measurements)];
152+
}
153+
154+
async function measureDownload(bytes, iterations) {
155+
const measurements = [];
156+
157+
for (let i = 0; i < iterations; i += 1) {
158+
await download(bytes).then(
159+
(response) => {
160+
const transferTime = response[5] - response[4];
161+
measurements.push(measureSpeed(bytes, transferTime));
162+
},
163+
(error) => {
164+
console.log(`Error: ${error}`);
165+
},
166+
);
167+
}
168+
169+
return measurements;
170+
}
171+
172+
async function measureUpload(bytes, iterations) {
173+
const measurements = [];
174+
175+
for (let i = 0; i < iterations; i += 1) {
176+
await upload(bytes).then(
177+
(response) => {
178+
const transferTime = response[6];
179+
measurements.push(measureSpeed(bytes, transferTime));
180+
},
181+
(error) => {
182+
console.log(`Error: ${error}`);
183+
},
184+
);
185+
}
186+
187+
return measurements;
188+
}
189+
190+
module.exports = async function speedTest() {
191+
let result = {};
192+
try {
193+
result["ping"] = Math.round((await measureLatency())[3]);
194+
195+
const testDown1 = await measureDownload(101000, 10);
196+
const testDown2 = await measureDownload(25001000, 2);
197+
const testDown3 = await measureDownload(100001000, 1);
198+
result["download"] = quartile([...testDown1, ...testDown2, ...testDown3], 0.9).toFixed(2);
199+
200+
const testUp1 = await measureUpload(11000, 10);
201+
const testUp2 = await measureUpload(101000, 5);
202+
const testUp3 = await measureUpload(1001000, 4);
203+
result["upload"] = quartile([...testUp1, ...testUp2, ...testUp3], 0.9).toFixed(2);
204+
} catch (error) {
205+
console.error("Error while using cloudflare speedtest");
206+
result = {error: error.message};
207+
}
208+
209+
return result;
210+
}

0 commit comments

Comments
 (0)