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>
This commit is contained in:
@@ -1,11 +1,39 @@
|
||||
import { Router } from 'express';
|
||||
import { z } from 'zod';
|
||||
import { asyncWrap } from '../errors.js';
|
||||
import { requireOwner } from '../cap.js';
|
||||
import { validate } from '../validate.js';
|
||||
import * as repo from '../../db/repos/speedtest.js';
|
||||
import * as settings from '../../db/repos/app_settings.js';
|
||||
import { enqueue } from '../../jobs/queue.js';
|
||||
import { setSpeedtestSchedule } from '../../cron/index.js';
|
||||
export const router = Router();
|
||||
router.get('/history', asyncWrap(async (_req, res) => res.json(await repo.history(30))));
|
||||
router.post('/run', requireOwner, asyncWrap(async (_req, res) => {
|
||||
const id = await enqueue('speedtest', {});
|
||||
res.status(202).json({ enqueued: id });
|
||||
|
||||
const DEFAULT_CFG = { interval_min: 60, threshold_down_mbps: 0 };
|
||||
async function getCfg() { return { ...DEFAULT_CFG, ...(await settings.get('speedtest', {})) }; }
|
||||
|
||||
router.get('/history', asyncWrap(async (req, res) =>
|
||||
res.json(await repo.history(Math.min(500, Number(req.query.limit) || 30)))));
|
||||
|
||||
router.get('/results', asyncWrap(async (req, res) =>
|
||||
res.json(await repo.range(Math.min(2160, Number(req.query.hours) || 168), 2000))));
|
||||
|
||||
router.get('/latest', asyncWrap(async (_req, res) => res.json(await repo.latest())));
|
||||
|
||||
router.get('/stats', asyncWrap(async (req, res) =>
|
||||
res.json(await repo.stats(Math.min(2160, Number(req.query.hours) || 24)))));
|
||||
|
||||
router.get('/config', asyncWrap(async (_req, res) => res.json(await getCfg())));
|
||||
|
||||
const cfgBody = z.object({
|
||||
interval_min: z.number().int().min(5).max(1440),
|
||||
threshold_down_mbps: z.number().min(0).max(100000).default(0)
|
||||
});
|
||||
router.put('/config', requireOwner, validate({ body: cfgBody }), asyncWrap(async (req, res) => {
|
||||
const cfg = await settings.set('speedtest', req.body);
|
||||
setSpeedtestSchedule(cfg.interval_min);
|
||||
res.json(cfg);
|
||||
}));
|
||||
|
||||
router.post('/run', requireOwner, asyncWrap(async (_req, res) =>
|
||||
res.status(202).json({ enqueued: await enqueue('speedtest', {}) })));
|
||||
|
||||
Reference in New Issue
Block a user