Files
myspeed/server/util/speedtest.js
2026-01-22 14:54:02 +01:00

106 lines
3.8 KiB
JavaScript

import { spawn } from 'node:child_process';
import * as interfacesModule from '../util/loadInterfaces.js';
import * as config from '../controller/config.js';
import fs from 'node:fs';
import path from 'node:path';
export default async (mode, serverId, serverUrl) => {
const binaryPath = mode === "ookla" ? './bin/speedtest' + (process.platform === "win32" ? ".exe" : "")
: mode === "libre" ? './bin/librespeed-cli' + (process.platform === "win32" ? ".exe" : "")
: './bin/cfspeedtest' + (process.platform === "win32" ? ".exe" : "");
if (!interfacesModule.interfaces) throw new Error("No interfaces found");
const currentInterface = await config.getValue("interface");
const interfaceIp = interfacesModule.interfaces[currentInterface];
const startTime = new Date().getTime();
let args;
if (mode === "ookla") {
args = ['--accept-license', '--accept-gdpr', '--format=json'];
if (process.platform === "win32") {
args.push('--ip=' + interfaceIp);
} else {
args.push('--interface=' + currentInterface);
}
if (serverId) args.push(`--server-id=${serverId}`);
} else if (mode === "libre") {
args = ['--json', '--duration=5', '--source=' + interfaceIp];
if (serverUrl) {
const customServerConfig = [{
id: 1,
name: "Custom Server",
server: serverUrl,
dlURL: "garbage.php",
ulURL: "empty.php",
pingURL: "empty.php",
getIpURL: "getIP.php"
}];
const tempJsonPath = path.join('data', 'servers', 'libre_custom.json');
fs.writeFileSync(tempJsonPath, JSON.stringify(customServerConfig));
args.push(`--local-json=${tempJsonPath}`);
args.push('--server=1');
} else if (serverId) {
args.push(`--server=${serverId}`);
}
} else if (mode === "cloudflare") {
args = ['--output-format=json'];
if (interfaceIp.includes(':')) {
args.push('--ipv6=' + interfaceIp);
} else {
args.push('--ipv4=' + interfaceIp);
}
}
let result = {};
let stdout = '';
const testProcess = spawn(binaryPath, args, {windowsHide: true});
testProcess.stderr.on('data', (buffer) => {
result.error = buffer.toString();
if (buffer.toString().includes("Too many requests")) {
result.error = "Too many requests. Please try again later";
}
});
testProcess.stdout.on('data', (buffer) => {
stdout += buffer.toString();
});
await new Promise((resolve, reject) => {
testProcess.on('error', e => reject({message: e}));
testProcess.on('exit', () => {
if (stdout.trim()) {
const lines = stdout.trim().split('\n');
for (const line of lines) {
if (!(line.startsWith("{") || line.startsWith("["))) continue;
let data = {};
try {
data = JSON.parse(line);
if (line.startsWith("[") && mode !== "cloudflare") data = data[0];
} catch (e) {
data.error = e.message;
console.error("JSON parse error:", e.message, "Line:", line);
continue;
}
if (data.error) result.error = data.error;
if ((mode === "ookla" && data.type === "result") || mode === "libre" || mode === "cloudflare") {
result = data;
}
}
}
resolve();
});
});
if (result.error) throw new Error(result.error);
return {...result, elapsed: new Date().getTime() - startTime};
}