OrangePi3588Media/web/app.js

116 lines
3.1 KiB
JavaScript

function qs(name) {
const url = new URL(window.location.href);
return url.searchParams.get(name);
}
async function fetchJson(url) {
const res = await fetch(url, { cache: "no-store" });
const text = await res.text();
let data;
try {
data = JSON.parse(text);
} catch {
throw new Error(`Bad JSON from ${url}: ${text.slice(0, 200)}`);
}
if (!res.ok) {
const msg = data && data.error ? data.error : `HTTP ${res.status}`;
throw new Error(msg);
}
return data;
}
function fmt(n, digits = 1) {
if (typeof n !== "number" || !isFinite(n)) return "-";
return n.toFixed(digits);
}
async function updateIndex() {
const body = document.getElementById("graphs-body");
if (!body) return;
let graphs = [];
try {
graphs = await fetchJson("/api/graphs");
} catch (e) {
body.innerHTML = `<tr><td colspan="3">${e.message}</td></tr>`;
return;
}
body.innerHTML = "";
for (const g of graphs) {
const tr = document.createElement("tr");
const statusCls = g.running ? "status-running" : "status-stopped";
tr.innerHTML = `
<td><a href="/graph.html?name=${encodeURIComponent(g.name)}">${g.name}</a></td>
<td class="${statusCls}">${g.running ? "Running" : "Stopped"}</td>
<td>${fmt(g.total_fps)}</td>
`;
body.appendChild(tr);
}
}
async function updateGraph() {
const name = qs("name");
const nodesBody = document.getElementById("nodes-body");
const edgesBody = document.getElementById("edges-body");
if (!name || !nodesBody || !edgesBody) return;
const title = document.getElementById("graph-title");
if (title) title.textContent = `Graph: ${name}`;
let g;
try {
g = await fetchJson(`/api/graphs/${encodeURIComponent(name)}`);
} catch (e) {
nodesBody.innerHTML = `<tr><td colspan="9">${e.message}</td></tr>`;
edgesBody.innerHTML = `<tr><td colspan="7">${e.message}</td></tr>`;
return;
}
const meta = document.getElementById("graph-meta");
if (meta) {
meta.textContent = `running=${g.running} total_fps=${fmt(g.total_fps)} ts_ms=${g.timestamp_ms}`;
}
nodesBody.innerHTML = "";
for (const n of g.nodes) {
const tr = document.createElement("tr");
tr.innerHTML = `
<td>${n.id}</td>
<td>${n.type}</td>
<td>${n.role || ""}</td>
<td>${fmt(n.input_fps)}</td>
<td>${fmt(n.output_fps)}</td>
<td>${n.input_queue ? `${n.input_queue.size}/${n.input_queue.capacity}` : "-"}</td>
<td>${n.drop_total}</td>
<td>${n.error_total}</td>
<td>${fmt(n.avg_process_time_ms, 3)}</td>
`;
nodesBody.appendChild(tr);
}
edgesBody.innerHTML = "";
for (const e of g.edges) {
const tr = document.createElement("tr");
tr.innerHTML = `
<td>${e.from}</td>
<td>${e.to}</td>
<td>${e.queue.size}</td>
<td>${e.queue.capacity}</td>
<td>${e.queue.dropped_total}</td>
<td>${fmt(e.queue.pushed_fps)}</td>
<td>${fmt(e.queue.popped_fps)}</td>
`;
edgesBody.appendChild(tr);
}
}
function boot() {
updateIndex();
updateGraph();
setInterval(updateIndex, 2000);
setInterval(updateGraph, 1000);
}
window.addEventListener("load", boot);