Includes current frontend and backend work in progress and removes generated artifacts from tracking to keep the repository clean for дальнейшая разработка. Co-authored-by: Cursor <[email protected]>
107 lines
4.0 KiB
TypeScript
107 lines
4.0 KiB
TypeScript
/**
|
|
* Разбор полей /system/resource из RouterOS REST: не всегда «сырые» байты в виде десятичной строки.
|
|
* На железе часто встречаются значения вида "224.0MiB", "94.2MiB"; parseInt от этого даёт мусор или 0.
|
|
*/
|
|
|
|
export function parseRosDataSizeBytes(raw: unknown): number {
|
|
if (raw == null) return 0
|
|
if (typeof raw === "number" && Number.isFinite(raw)) return Math.max(0, Math.floor(raw))
|
|
let s = String(raw).trim().replace(/\s+/g, "")
|
|
if (!s) return 0
|
|
if (/^\d+$/.test(s)) {
|
|
const n = Number.parseInt(s, 10)
|
|
return Number.isFinite(n) ? Math.max(0, n) : 0
|
|
}
|
|
const m = s.match(/^(\d+(?:[.,]\d+)?)(KiB|MiB|GiB|TiB|Ki|Mi|Gi|Ti|KB|MB|GB|TB)$/i)
|
|
if (m) {
|
|
const v = Number.parseFloat(m[1].replace(",", "."))
|
|
if (!Number.isFinite(v) || v < 0) return 0
|
|
const u = m[2].toLowerCase()
|
|
const mult =
|
|
u === "ki" || u === "kib" || u === "kb" ? 1024
|
|
: u === "mi" || u === "mib" || u === "mb" ? 1024 ** 2
|
|
: u === "gi" || u === "gib" || u === "gb" ? 1024 ** 3
|
|
: u === "ti" || u === "tib" || u === "tb" ? 1024 ** 4
|
|
: 1
|
|
return Math.max(0, Math.floor(v * mult))
|
|
}
|
|
const fallback = Number.parseInt(s, 10)
|
|
return Number.isFinite(fallback) ? Math.max(0, fallback) : 0
|
|
}
|
|
|
|
/** cpu-load: "7%", "7", 7 */
|
|
export function parseRosCpuLoadPercent(raw: unknown): number {
|
|
if (raw == null) return 0
|
|
if (typeof raw === "number" && Number.isFinite(raw)) {
|
|
return Math.min(100, Math.max(0, Math.round(raw)))
|
|
}
|
|
const s = String(raw).trim().replace("%", "").replace(",", ".").trim()
|
|
if (!s) return 0
|
|
const n = Number.parseFloat(s)
|
|
if (!Number.isFinite(n)) return 0
|
|
return Math.min(100, Math.max(0, Math.round(n)))
|
|
}
|
|
|
|
/**
|
|
* `uptime` из /system/resource (REST): обычно "2d20h12m20s", "39m", "29s".
|
|
* Встречаются варианты: только секунды строкой, `d.hh:mm:ss`, `hh:mm:ss` без суффиксов.
|
|
* @see https://help.mikrotik.com/docs/display/ROS/Resource
|
|
*/
|
|
export function parseRosUptimeToSeconds(raw: unknown): number {
|
|
if (raw == null) return 0
|
|
if (typeof raw === "number" && Number.isFinite(raw)) {
|
|
return Math.max(0, Math.floor(raw))
|
|
}
|
|
const s0 = String(raw).trim().replace(/\u00a0/g, " ").trim()
|
|
if (!s0) return 0
|
|
|
|
// Только десятичные цифры — секунды (некоторые клиенты/прокси)
|
|
if (/^\d+$/.test(s0)) {
|
|
const n = Number.parseInt(s0, 10)
|
|
return Number.isFinite(n) ? Math.max(0, n) : 0
|
|
}
|
|
|
|
const s = s0.toLowerCase().replace(/\s+/g, "")
|
|
|
|
// 1d18:27:15
|
|
const dClock = s.match(/^(\d+)d(\d{1,3}):(\d{2}):(\d{2})$/i)
|
|
if (dClock) {
|
|
const d = Number.parseInt(dClock[1], 10)
|
|
const hh = Number.parseInt(dClock[2], 10)
|
|
const mm = Number.parseInt(dClock[3], 10)
|
|
const ss = Number.parseInt(dClock[4], 10)
|
|
if ([d, hh, mm, ss].every((x) => Number.isFinite(x) && x >= 0)) {
|
|
return d * 86400 + hh * 3600 + mm * 60 + ss
|
|
}
|
|
}
|
|
|
|
// 18:27:15 — только если нет суффиксов w/d/h/m/s (иначе это часть "2d20h12m20s")
|
|
if (!/[wdhms]/i.test(s0) && /^\d{1,7}:\d{2}:\d{2}$/.test(s)) {
|
|
const p = s.split(":")
|
|
if (p.length === 3) {
|
|
const hh = Number.parseInt(p[0], 10)
|
|
const mm = Number.parseInt(p[1], 10)
|
|
const sec = Number.parseInt(p[2], 10)
|
|
if ([hh, mm, sec].every((x) => Number.isFinite(x) && x >= 0)) {
|
|
return hh * 3600 + mm * 60 + sec
|
|
}
|
|
}
|
|
}
|
|
|
|
let total = 0
|
|
for (const m of s.matchAll(/(\d+)(w|d|h|m(?!s)|s)/gi)) {
|
|
const n = Number.parseInt(m[1], 10)
|
|
if (!Number.isFinite(n) || n < 0) continue
|
|
const u = m[2].toLowerCase()
|
|
switch (u) {
|
|
case "w": total += n * 604800; break
|
|
case "d": total += n * 86400; break
|
|
case "h": total += n * 3600; break
|
|
case "m": total += n * 60; break
|
|
case "s": total += n; break
|
|
default: break
|
|
}
|
|
}
|
|
return Math.max(0, total)
|
|
}
|