Gepubliceerde bron
Download bron ZIP
CH-J Server Manager
Blader door mappen en bestanden voor een specifieke toepassing release.
CH-J / Server Manager
339 bestanden
core-20261014T184258Z-3fbed0b93fdf
Toegevoegd: Datum niet geregistreerd · Gebouwd:
1
"use strict";3
const api = window.chjPlugin;4
const elements = {5
pluginVersion: document.querySelector("#pluginVersion"), closeButton: document.querySelector("#closeButton"),6
sessionSelect: document.querySelector("#sessionSelect"), refreshSessionsButton: document.querySelector("#refreshSessionsButton"),7
refreshMetricsButton: document.querySelector("#refreshMetricsButton"), autoRefresh: document.querySelector("#autoRefresh"),8
status: document.querySelector("#status"), hostname: document.querySelector("#hostname"), platform: document.querySelector("#platform"),9
kernel: document.querySelector("#kernel"), uptime: document.querySelector("#uptime"), load: document.querySelector("#load"),10
cpu: document.querySelector("#cpu"), cpuBar: document.querySelector("#cpuBar"), cpuDetail: document.querySelector("#cpuDetail"),11
cpuArchitecture: document.querySelector("#cpuArchitecture"), cpuModel: document.querySelector("#cpuModel"),12
cpuTopology: document.querySelector("#cpuTopology"), cpuTypes: document.querySelector("#cpuTypes"),13
memory: document.querySelector("#memory"), memoryBar: document.querySelector("#memoryBar"), memoryDetail: document.querySelector("#memoryDetail"),14
swap: document.querySelector("#swap"), swapBar: document.querySelector("#swapBar"), swapDetail: document.querySelector("#swapDetail"),15
disk: document.querySelector("#disk"), diskBar: document.querySelector("#diskBar"), diskDetail: document.querySelector("#diskDetail"),16
networkSummary: document.querySelector("#networkSummary"), networkInterfaces: document.querySelector("#networkInterfaces")17
};18
let busy = false;19
let previousNetwork = new Map();21
function bytes(value) {22
const units = ["B", "KB", "MB", "GB", "TB"]; let amount = Number(value || 0); let unit = 0;23
while (amount >= 1024 && unit < units.length - 1) { amount /= 1024; unit += 1; }24
return `${amount.toLocaleString("cs-CZ", { maximumFractionDigits: 1 })} ${units[unit]}`;25
}26
function duration(seconds) {27
let remaining = Math.max(0, Number(seconds) || 0); const days = Math.floor(remaining / 86400); remaining %= 86400;28
const hours = Math.floor(remaining / 3600); const minutes = Math.floor((remaining % 3600) / 60);29
return `${days ? `${days} d ` : ""}${hours} h ${minutes} min`;30
}31
function percent(used, total) { return total > 0 ? Math.max(0, Math.min(100, used / total * 100)) : 0; }32
function setStatus(message, error = false) { elements.status.textContent = message; elements.status.classList.toggle("error", error); }33
function element(tag, className, text) {34
const node = document.createElement(tag);35
if (className) node.className = className;36
if (text !== undefined) node.textContent = text;37
return node;38
}39
function networkRate(current, previous, elapsedSeconds) {40
const difference = Number(current || 0) - Number(previous || 0);41
return elapsedSeconds > 0 && difference >= 0 ? difference / elapsedSeconds : 0;42
}43
function renderNetwork(network, collectedAt) {44
const interfaces = Array.isArray(network?.interfaces) ? network.interfaces : [];45
elements.networkInterfaces.replaceChildren();46
if (!network) {47
elements.networkSummary.textContent = "vyžaduje nový Core";48
elements.networkInterfaces.append(element("p", "empty", "Síťové metriky vyžadují novější sestavení Core."));49
previousNetwork = new Map();50
return;51
}52
const collectedMs = Date.parse(collectedAt) || Date.now();53
const nextNetwork = new Map();54
const active = interfaces.filter((item) => item.state === "up" || item.state === "active").length;55
elements.networkSummary.textContent = interfaces.length56
? `${active}/${interfaces.length} aktivní${network.defaultInterface ? ` · výchozí ${network.defaultInterface}` : ""}`57
: "žádná rozhraní";58
if (!interfaces.length) elements.networkInterfaces.append(element("p", "empty", "Nebyla nalezena žádná síťová rozhraní mimo loopback."));59
for (const item of interfaces) {60
const card = element("article", "network-interface");61
const heading = element("div", "interface-heading");62
const name = element("strong", "interface-name", item.name || "unknown");63
if (item.isDefault) name.append(element("span", "default-mark", "výchozí"));64
const isUp = item.state === "up" || item.state === "active";65
heading.append(name, element("span", `state ${isUp ? "up" : "down"}`, isUp ? "aktivní" : (item.state || "neznámý")));66
const addresses = Array.isArray(item.addresses) && item.addresses.length ? item.addresses.join(" · ") : "bez globální IP adresy";67
card.append(heading, element("p", "addresses", addresses));68
if (item.mac) card.append(element("p", "mac", `MAC ${item.mac}`));69
const previous = previousNetwork.get(item.name);70
const elapsedSeconds = previous ? Math.max(0, (collectedMs - previous.collectedMs) / 1000) : 0;71
const rxRate = previous ? networkRate(item.rxBytes, previous.rxBytes, elapsedSeconds) : 0;72
const txRate = previous ? networkRate(item.txBytes, previous.txBytes, elapsedSeconds) : 0;73
const traffic = element("div", "traffic");74
traffic.append(75
element("span", "rx", `↓ ${bytes(item.rxBytes)}${previous ? ` · ${bytes(rxRate)}/s` : ""}`),76
element("span", "tx", `↑ ${bytes(item.txBytes)}${previous ? ` · ${bytes(txRate)}/s` : ""}`)77
);78
card.append(traffic);79
elements.networkInterfaces.append(card);80
nextNetwork.set(item.name, { rxBytes: item.rxBytes, txBytes: item.txBytes, collectedMs });81
}82
previousNetwork = nextNetwork;83
}85
async function loadSessions() {86
const selected = elements.sessionSelect.value;87
const sessions = (await api.sessions.list()).filter((session) => session.state === "connected");88
elements.sessionSelect.replaceChildren(new Option(sessions.length ? "Vyberte relaci…" : "Žádná připojená relace", ""));89
for (const session of sessions) elements.sessionSelect.add(new Option(`${session.label} — ${session.username}@${session.host}`, session.sessionId));90
elements.sessionSelect.value = sessions.some((session) => session.sessionId === selected) ? selected : (sessions[0]?.sessionId || "");91
elements.refreshMetricsButton.disabled = !elements.sessionSelect.value;92
if (!sessions.length) setStatus("Nejprve se v Core připojte k serveru přes SSH.");93
}95
async function loadMetrics() {96
const sessionId = elements.sessionSelect.value;97
if (!sessionId || busy) return;98
busy = true; elements.refreshMetricsButton.disabled = true; setStatus("Načítám systémové metriky…");99
try {100
const metrics = await api.system.readMetrics(sessionId);101
elements.hostname.textContent = metrics.hostname;102
elements.platform.textContent = metrics.platform;103
elements.kernel.textContent = metrics.kernel;104
elements.uptime.textContent = duration(metrics.uptimeSeconds);105
elements.load.textContent = Number(metrics.load1 || 0).toLocaleString("cs-CZ", { maximumFractionDigits: 2 });106
const cpu = metrics.cpu;107
const cpuUsage = Number(cpu?.usagePercent || 0);108
elements.cpu.textContent = cpu ? `${cpuUsage.toLocaleString("cs-CZ", { maximumFractionDigits: 1 })} %` : "nedostupné";109
elements.cpuBar.style.width = `${Math.max(0, Math.min(100, cpuUsage))}%`;110
elements.cpuDetail.textContent = cpu?.logicalCores ? `${cpu.logicalCores} logických procesorů` : "vyžaduje novější Core";111
elements.cpuArchitecture.textContent = cpu?.architecture || "neznámá architektura";112
elements.cpuModel.textContent = cpu?.model || "Údaj o modelu CPU není dostupný.";113
elements.cpuTopology.textContent = cpu?.logicalCores114
? `${cpu.logicalCores} logických · ${cpu.physicalCores || "?"} fyzických · ${cpu.sockets || "?"} socketů`115
: "Metrika vyžaduje novější sestavení Core.";116
elements.cpuTypes.textContent = Array.isArray(cpu?.coreTypes) && cpu.coreTypes.length117
? cpu.coreTypes.map((type) => `${type.name} ${type.count}`).join(" · ")118
: "Server nerozlišuje typy jader.";119
const memoryUsed = Math.max(0, metrics.memory.total - metrics.memory.available);120
const memoryPercent = percent(memoryUsed, metrics.memory.total);121
elements.memory.textContent = `${memoryPercent.toLocaleString("cs-CZ", { maximumFractionDigits: 1 })} %`;122
elements.memoryBar.style.width = `${memoryPercent}%`;123
elements.memoryDetail.textContent = `${bytes(memoryUsed)} / ${bytes(metrics.memory.total)}`;124
const swapTotal = Number(metrics.swap?.total || 0);125
const swapUsed = Number(metrics.swap?.used || 0);126
const swapPercent = percent(swapUsed, swapTotal);127
elements.swap.textContent = swapTotal > 0 ? `${swapPercent.toLocaleString("cs-CZ", { maximumFractionDigits: 1 })} %` : "neaktivní";128
elements.swapBar.style.width = `${swapPercent}%`;129
elements.swapDetail.textContent = `${bytes(swapUsed)} / ${bytes(swapTotal)}`;130
const diskPercent = percent(metrics.disk.used, metrics.disk.total);131
elements.disk.textContent = `${diskPercent.toLocaleString("cs-CZ", { maximumFractionDigits: 1 })} %`;132
elements.diskBar.style.width = `${diskPercent}%`;133
elements.diskDetail.textContent = `${bytes(metrics.disk.used)} / ${bytes(metrics.disk.total)}`;134
renderNetwork(metrics.network, metrics.collectedAt);135
setStatus(`Aktualizováno ${new Date(metrics.collectedAt).toLocaleTimeString("cs-CZ")}.`);136
} catch (error) { setStatus(error?.message || String(error), true); }137
finally { busy = false; elements.refreshMetricsButton.disabled = !elements.sessionSelect.value; }138
}140
elements.closeButton.addEventListener("click", () => api.close());141
elements.refreshSessionsButton.addEventListener("click", loadSessions);142
elements.refreshMetricsButton.addEventListener("click", loadMetrics);143
elements.sessionSelect.addEventListener("change", () => { previousNetwork = new Map(); elements.refreshMetricsButton.disabled = !elements.sessionSelect.value; void loadMetrics(); });144
setInterval(() => { if (elements.autoRefresh.checked) void loadMetrics(); }, 5000);146
(async () => {147
const info = await api.getInfo();148
elements.pluginVersion.textContent = `${info.name} v${info.version} · ${info.publisher}`;149
await loadSessions();150
await loadMetrics();151
})().catch((error) => setStatus(error?.message || String(error), true));SHA-256
c11a8ab988b8fbf4823ea00d92d9453c00139cf156705a9ce913ef1795b5436aCH-J Proprietary Software License 1.14 · Bron wordt geleverd onder de CH-J Proprietary Software License 1.14. De beschikbaarheid verandert de licentievoorwaarden niet of verleent geen extra rechten.
Archief SHA-256
3df08cf5e899262a6ce92d7ec2caf5c42b683f1f2b57055662b845ff7dde67a8