CH-J Server Managerspráva serverov nad SSH
Menu
Uverejnený zdroj

CH-J Server Manager

Prechádzať adresáre a súbory pre konkrétne vydanie aplikácie.

Stiahnuť zdroj ZIP
CH-J / Server Manager 339 súbory
core-20261014T184258Z-3fbed0b93fdf Pridané: Dátum nezaznamenaný · Postavený:
Súbory
index.js Pridané: Dátum nezaznamenaný 9,9 KB · 151 riadky
Stiahnuť súbor
1"use strict";
3const api = window.chjPlugin;
4const 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};
18let busy = false;
19let previousNetwork = new Map();
21function 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]}`;
26function 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`;
31function percent(used, total) { return total > 0 ? Math.max(0, Math.min(100, used / total * 100)) : 0; }
32function setStatus(message, error = false) { elements.status.textContent = message; elements.status.classList.toggle("error", error); }
33function 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;
39function networkRate(current, previous, elapsedSeconds) {
40 const difference = Number(current || 0) - Number(previous || 0);
41 return elapsedSeconds > 0 && difference >= 0 ? difference / elapsedSeconds : 0;
43function 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.length
56 ? `${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;
85async 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.");
95async 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?.logicalCores
114 ? `${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.length
117 ? 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; }
140elements.closeButton.addEventListener("click", () => api.close());
141elements.refreshSessionsButton.addEventListener("click", loadSessions);
142elements.refreshMetricsButton.addEventListener("click", loadMetrics);
143elements.sessionSelect.addEventListener("change", () => { previousNetwork = new Map(); elements.refreshMetricsButton.disabled = !elements.sessionSelect.value; void loadMetrics(); });
144setInterval(() => { 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-256c11a8ab988b8fbf4823ea00d92d9453c00139cf156705a9ce913ef1795b5436a

CH-J Proprietary Software License 1.14 · Zdroj sa poskytuje v rámci CH-J Proprietary Software License 1.14. Jeho dostupnosť nemení licenčné podmienky ani neposkytuje dodatočné práva.

Archív SHA-2563df08cf5e899262a6ce92d7ec2caf5c42b683f1f2b57055662b845ff7dde67a8