1import speedTest from '../util/speedtest.js';
2import * as tests from '../controller/speedtests.js';
3import * as config from '../controller/config.js';
4import * as controller from "../controller/recommendations.js";
5import * as parseData from '../util/providers/parseData.js';
6import { setState, sendRunning, sendError, sendFinished } from "./integrations.js";
7import * as serverController from "../controller/servers.js";
8
9let _isRunning = false;
10
11const setRunning = (running, sendRequest = true) => {
12 _isRunning = running;
13
14 if (running) {
15 setState("running");
16 if (sendRequest) sendRunning().then(undefined);
17 } else {
18 setState("ping");
19 }
20}
21
22const createRecommendations = async () => {
23 let list = (await tests.listTests()).filter((entry) => !entry.error);
24 if (list.length >= 10) {
25 let recommendations = {ping: 1000, down: 0, up: 0};
26 for (let i = 0; i < 10; i++) {
27 if (list[i].ping < recommendations["ping"]) recommendations["ping"] = list[i].ping;
28 if (list[i].download > recommendations["down"]) recommendations["down"] = list[i].download;
29 if (list[i].upload > recommendations["up"]) recommendations["up"] = list[i].upload;
30 }
31
32 await controller.update(recommendations["ping"], recommendations["down"], recommendations["up"]);
33 }
34}
35
36export const run = async (retryAuto = false) => {
37 setRunning(true);
38 let mode = await config.getValue("provider");
39
40 if (mode === "none") {
41 setRunning(false);
42 throw {message: "No provider selected"};
43 }
44
45 let serverId = mode === "cloudflare" ? 0 : await config.getValue(mode + "Id");
46 let serverUrl = mode === "libre" ? await config.getValue("libreUrl") : undefined;
47
48 if (serverId === "none")
49 serverId = undefined;
50
51 if (serverUrl === "none")
52 serverUrl = undefined;
53
54 if (mode === "libre" && serverUrl)
55 serverId = undefined;
56
57 let speedtest = await (retryAuto ? speedTest(mode) : speedTest(mode, serverId, serverUrl));
58
59 if (mode === "ookla" && speedtest.server) {
60 if (serverId === undefined) await config.updateValue("ooklaId", speedtest.server?.id);
61 serverId = speedtest.server?.id;
62 }
63
64 if (mode === "libre" && speedtest.server && !serverUrl) {
65 let serverEntry = Object.entries(serverController.getLibreServers())
66 .filter(([, value]) => value === speedtest.server.name)[0];
67
68 if (serverEntry) {
69 if (serverId === undefined) await config.updateValue("libreId", serverEntry[0]);
70 serverId = parseInt(serverEntry[0]);
71 }
72 }
73
74 if (Object.keys(speedtest).length <= 1) throw {message: "No response, even after trying again, test timed out."};
75
76 return {...speedtest, serverId}
77}
78
79export const create = async (type = "auto", retried = false) => {
80 const mode = await config.getValue("provider");
81 if (mode === "none") return 400;
82 if (_isRunning && !retried) return 500;
83
84 try {
85 let test;
86 if (process.env.PREVIEW_MODE === "true") {
87 await new Promise(resolve => setTimeout(resolve, 5000));
88 test = {
89 ping: {latency: Math.floor(Math.random() * 25) + 5, jitter: Math.random() * 5 + 0.5},
90 download: {bandwidth: 125 * 100000 * (Math.random() + 0.5), elapsed: 10000},
91 upload: {bandwidth: 125 * 100000 * (Math.random() + 0.5), elapsed: 10000},
92 }
93 } else {
94 test = await run(retried);
95 }
96
97 let {ping, jitter, download, upload, time, resultId, serverName, serverHost} = await parseData.parseData(process.env.PREVIEW_MODE === "true" ?
98 "ookla" : mode, test);
99
100 let testResult = await tests.create(ping, download, upload, time, test.serverId, type, resultId, null, jitter, serverName, serverHost);
101 console.log(`Test #${testResult} was executed successfully in ${time}s. 🏓 ${ping} (±${jitter || 'N/A'}) ⬇ ${download}️ ⬆ ${upload}️`);
102 createRecommendations().then(() => "");
103 setRunning(false);
104 sendFinished({ping, jitter, download, upload, time}).then(() => "");
105 } catch (e) {
106 console.log(e)
107 if (!retried) return create(type, true);
108 let testResult = await tests.create(-1, -1, -1, null, 0, type, null, e.message);
109 await sendError(e.message);
110 setRunning(false, false);
111 console.log(`Test #${testResult} was not executed successfully. Please try reconnecting to the internet or restarting the software: ` + e.message);
112 }
113}
114
115export const isRunning = () => _isRunning;
116
117export const removeOld = async () => {
118 await tests.removeOld();
119};