Switch worker to the Ookla CLI (jitter, packet loss, server, ISP, shareable result URL, bytes). Migration 028 enriches speedtest_results + adds a generic app_settings store. New /speedtest page: KPIs, throughput + latency charts, window stats, configurable schedule (reschedulable cron) & low-speed alert threshold, history table. SV card gains ping/jitter + a link through to the page. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
48 lines
1.7 KiB
JavaScript
48 lines
1.7 KiB
JavaScript
import { execFile } from 'node:child_process';
|
|
import { promisify } from 'node:util';
|
|
import * as repo from '../../db/repos/speedtest.js';
|
|
import { log } from '../../log.js';
|
|
const pexec = promisify(execFile);
|
|
|
|
export const NAME = 'speedtest';
|
|
|
|
// Ookla CLI gives the full metric set (jitter, packet loss, server, ISP,
|
|
// shareable result URL). Override the binary via SPEEDTEST_BIN if needed.
|
|
const OOKLA_BIN = process.env.SPEEDTEST_BIN || 'ookla-speedtest';
|
|
|
|
async function ooklaRunner() {
|
|
const { stdout } = await pexec(OOKLA_BIN,
|
|
['-f', 'json', '--accept-license', '--accept-gdpr'], { timeout: 120000 });
|
|
const j = JSON.parse(stdout);
|
|
const mbps = bw => (Number(bw) || 0) * 8 / 1e6; // Ookla bandwidth is bytes/s
|
|
return {
|
|
down_mbps: mbps(j.download?.bandwidth),
|
|
up_mbps: mbps(j.upload?.bandwidth),
|
|
ping_ms: j.ping?.latency ?? null,
|
|
jitter_ms: j.ping?.jitter ?? null,
|
|
packet_loss: j.packetLoss ?? null,
|
|
server_name: j.server ? [j.server.name, j.server.location].filter(Boolean).join(' · ') : null,
|
|
server_id: j.server?.id != null ? String(j.server.id) : null,
|
|
isp: j.isp ?? null,
|
|
result_url: j.result?.url ?? null,
|
|
down_bytes: j.download?.bytes ?? null,
|
|
up_bytes: j.upload?.bytes ?? null,
|
|
ok: true
|
|
};
|
|
}
|
|
let runner = ooklaRunner;
|
|
export function _setRunner(fn) { runner = fn; }
|
|
|
|
export async function handler(_job) {
|
|
try {
|
|
const r = await runner();
|
|
const saved = await repo.record(r);
|
|
log.info({ down: r.down_mbps, up: r.up_mbps, ping: r.ping_ms }, 'speedtest recorded');
|
|
return saved;
|
|
} catch (e) {
|
|
await repo.record({ ok: false, error: String(e?.message || e).slice(0, 300) });
|
|
log.error({ err: e }, 'speedtest failed');
|
|
throw e;
|
|
}
|
|
}
|