Files
Void-Homelab/lib/jobs/workers/speedtest.js
root 359ae21d59 feat(speedtest): full speedtest-tracker-style automation (2.9.0)
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>
2026-06-09 22:55:04 +10:00

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;
}
}