31 lines
1.5 KiB
TypeScript
31 lines
1.5 KiB
TypeScript
/** RouterOS rates are bits/s unless a decimal SI prefix is present. */
|
|
export function parseBandwidthRateMbps(raw: unknown): number | null {
|
|
if (typeof raw !== "string" && typeof raw !== "number") return null
|
|
const match = String(raw).trim().toLowerCase().match(/^(\d+(?:\.\d+)?|\.\d+)\s*(g|m|k)?(?:bps|bit\/s|bits\/s)?$/)
|
|
if (!match) return null
|
|
const factor = match[2] === "g" ? 1000 : match[2] === "m" ? 1 : match[2] === "k" ? 0.001 : 0.000001
|
|
const value = Number(match[1]) * factor
|
|
return Number.isFinite(value) && value >= 0 ? value : null
|
|
}
|
|
|
|
export function readBandwidthTestRates(rows: readonly Record<string, unknown>[]) {
|
|
function rate(row: Record<string, unknown>, keys: string[]) {
|
|
for (const key of keys) {
|
|
const value = parseBandwidthRateMbps(row[key])
|
|
if (value !== null) return value
|
|
}
|
|
return null
|
|
}
|
|
function series(side: "tx" | "rx") {
|
|
return rows.flatMap(row => {
|
|
const value = rate(row, [`${side}-current`, `${side}-10-second-average`, `${side}-total-average`])
|
|
return value === null ? [] : [value]
|
|
})
|
|
}
|
|
const txSeries = series("tx"), rxSeries = series("rx"), last = rows.at(-1) ?? {}
|
|
const average = (side: "tx" | "rx", values: number[]) =>
|
|
rate(last, [`${side}-total-average`, `${side}-10-second-average`]) ??
|
|
(values.length ? values.reduce((sum, value) => sum + value / values.length, 0) : null)
|
|
return { txAvgMbps: average("tx", txSeries), rxAvgMbps: average("rx", rxSeries), txSeries, rxSeries }
|
|
}
|