another huge bugfix push, working releast

This commit is contained in:
2026-04-19 20:52:32 -07:00
parent 18ed5bd3a2
commit 71e0df2db0
4 changed files with 37 additions and 63 deletions

View File

@ -155,8 +155,8 @@ if (!in_array($mode, $validModes, true)) {
/* ---------- API configuration per mode ---------- */
$apiConfig = [
'cosmostat' => ['bind' => '10.200.27.20', 'port' => '5000'],
/*'gali' => ['bind' => '10.200.27.20', 'port' => '5000'], // same as cosmostat*/
'drive_health' => ['bind' => '172.25.1.18', 'port' => '5001'], // new API
/*'gali' => ['bind' => '10.200.27.20', 'port' => '5000'], // space filler */
'drive_health' => ['bind' => '0.0.0.0', 'port' => '5001'], // drive health API
];
/* ---------- Helper: fetch client details ---------- */
@ -251,7 +251,7 @@ function renderSidebar(string $mode){
?>
<nav class="sidebar">
<form method="get" id="modeForm">
<label for="modeSelect">Mode:</label>
<label for="modeSelect"></label>
<select class="select-dark" name="mode" id="modeSelect" onchange="this.form.submit()">
<?php foreach ($modes as $key => $label): ?><option value="<?= h($key) ?>" <?= $mode === $key ? 'selected' : '' ?>><?= h($label) ?></option>
<?php endforeach; ?></select>
@ -297,6 +297,13 @@ function renderSidebar(string $mode){
<?php endif; ?>
<?php endif; ?>
<?php if ($mode == 'cosmostat'): ?>
<input type="hidden" name="host" value="<?= h($selectedId) ?>">
<h3>Endpoints</h3>
<ol id="endpointList"></ol>
<?php endif; ?>
<?php if ($mode == 'gali'): ?>
<h3>Shuttle Gali</h3>
<?php endif; ?>
@ -473,7 +480,6 @@ function renderMainContent(string $mode){
</div> <!-- /wrapper -->
<?php if ($mode != 'drive_health'): ?>
<!-- cosmostat javascript -->
<script src="socket.io/socket.io.js"></script>
<script src="src/system_metrics.js"></script>
@ -488,9 +494,7 @@ function renderMainContent(string $mode){
help.style.display = help.style.display === 'none' || help.style.display === '' ? 'block' : 'none';
});
</script>
<?php endif; ?>
<?php if ($mode == 'drive_health'): ?>
<!-- drive health javascript -->
<script>
// Removal Handler
@ -503,7 +507,6 @@ function renderMainContent(string $mode){
document.getElementById('remove_hosts_input').value = ids.join(',');
});
</script>
<?php endif; ?>
</body>
</html>

View File

@ -61,13 +61,17 @@ a:hover { text-decoration: underline; }
/* optional: keep it above other content */
z-index: 1000;
}
.sidebar h3 { margin: 0 0 .4rem 0; font-size: 1.1rem; }
.sidebar h3 { margin: 0 0 .4rem 0; font-size: 1.3rem; }
.sidebar ul { list-style: none; padding: 0; margin: 0; }
.sidebar ol { list-style: none; padding: 0; margin: 0; }
.sidebar li { margin-bottom: .4rem; }
.sidebar li { margin-bottom: .4rem; font-size: 1.1rem; }
.sidebar a { color: var(--clr-accent); }
.sidebar a.active { font-weight: bold; }
/*
.endpointList {
}
*/
.main{
flex: 1;
padding: 1rem;

View File

@ -1,10 +1,7 @@
/* ==============================================================
system_metrics.js
============================================================== */
/* system_metrics.js */
(() => {
/* ==========================================================
Socket.IO setup
========================================================== */
/* Socket.IO setup */
const socket = io({
transports: ['websocket', 'polling'],
reconnection: true,
@ -15,15 +12,11 @@
pingTimeout: 5000,
pingInterval: 25000,
});
/* ==========================================================
Color constants
========================================================== */
/* Color constants */
const GREEN = [ 39, 174, 96]; // #27ae60
const YELLOW = [243, 156, 18]; // #f39c12
const RED = [192, 57, 43]; // #c0392b
/* ==========================================================
Helpers
========================================================== */
/* Helpers */
const hostTimestamps = {}; // keyed by short_id
const toRgb = (r, g, b) => `rgb(${r},${g},${b})`;
const T20 = 20 * 1000;
@ -53,15 +46,11 @@
const el = document.getElementById(id);
if (el) el.textContent = txt;
}
/* ==========================================================
Get the short_id from the query string
========================================================== */
/* Get the short_id from the query string */
function getSelectedId() {
return new URLSearchParams(window.location.search).get('host') || '';
}
/* ==========================================================
Sidebar building - uses short_id for status key
========================================================== */
/* Sidebar building - uses short_id for status key */
function buildList(systemList) {
const ul = document.getElementById('endpointList');
@ -71,9 +60,7 @@
return;
}
/* ────────────────────────────────────────
* Sort: servers first, then by IP
* ──────────────────────────────────────── */
/* Sort: servers first, then by IP */
const toInt = ip => {
// guard against undefined / empty string
if (!ip) return 0;
@ -81,12 +68,12 @@
};
const sorted = [...systemList].sort((a, b) => {
// a. Servers go before nonservers
// a. Servers go before non-servers
const aServer = !!a.is_server;
const bServer = !!b.is_server;
if (aServer !== bServer) return aServer ? -1 : 1; // true < false
// b. Same “is_server” status fall back to IP sorting
// b. Same “is_server” status - fall back to IP sorting
const aIp = a.active_ip ?? '';
const bIp = b.active_ip ?? '';
@ -96,16 +83,12 @@
return toInt(aIp) - toInt(bIp);
});
/* ────────────────────────────────────────
* Bail if nothing actually changed
* ──────────────────────────────────────── */
/* Bail if nothing actually changed */
const current = Array.from(ul.children).map(li => li.dataset.id);
const newIds = sorted.map(s => s.short_id);
if (arraysEqual(current, newIds)) return; // no visual change needed
/* ────────────────────────────────────────
* Build the DOM
* ──────────────────────────────────────── */
/* Build the DOM */
const selected = getSelectedId().toLowerCase();
ul.innerHTML = ''; // reset
@ -117,7 +100,7 @@
status.className = 'host-status';
status.dataset.id = item.short_id;
// • Link display hostname, encode short_id in URL
// • Link - display hostname, encode short_id in URL
const a = document.createElement('a');
a.href = '?host=' + encodeURIComponent(item.short_id);
a.textContent = item.hostname;
@ -130,9 +113,7 @@
});
}
/* ==========================================================
Update status colors every second
========================================================== */
/* Update status colors every second */
function updateStatusColors() {
const nowSec = Date.now() / 1000;
Object.entries(hostTimestamps).forEach(([id, ts]) => {
@ -145,9 +126,7 @@
});
}
setInterval(updateStatusColors, 1000);
/* ==========================================================
Utility helpers
========================================================== */
/* Utility helpers */
function arraysEqual(a, b) {
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
@ -225,9 +204,7 @@
});
return table;
}
/* ==========================================================
Handle incoming data
========================================================== */
/* Handle incoming data */
let lastUpdate = Date.now();
function handleSummary(raw) {
lastUpdate = Date.now(); // reset watchdog
@ -260,9 +237,7 @@
: [];
renderGenericTable('host_metrics', hostData, 'No Stats available');
}
/* ==========================================================
Socket event wiring
========================================================== */
/* Socket event wiring */
socket.on('client_summary', handleSummary);
socket.on('connect', () => {
safeSetText('client_summary', 'Connected');
@ -275,16 +250,12 @@
safeSetText('client_summary', `Re-connected (attempt ${attempt})`);
requestSummary();
});
/* ==========================================================
Request logic
========================================================== */
/* Request logic */
function requestSummary() {
if (!socket.connected) return; // guard against stale emits
socket.emit('get_client_summary'); // server will reply via client_summary
}
/* ==========================================================
Recursive polling
========================================================== */
/* Recursive polling */
let pollTimer = null;
function pollLoop() {
if (!socket.connected) return;
@ -294,9 +265,7 @@
socket.on('connect', () => {
if (!pollTimer) pollLoop();
});
/* ==========================================================
Watchdog - force reconnect if no data for 15s
========================================================== */
/* Watchdog - force reconnect if no data for 15s */
function watchdog() {
if (Date.now() - lastUpdate > 15000 && socket.connected) {
safeSetText('client_summary', 'No updates - reconnecting...');
@ -305,9 +274,7 @@
setTimeout(watchdog, 5000);
}
watchdog();
/* ==========================================================
Keep the 'active' link in sync when the URL changes
========================================================== */
/* Keep the 'active' link in sync when the URL changes */
window.addEventListener('popstate', () => {
const selected = getSelectedId().toLowerCase();
document.querySelectorAll('#endpointList a').forEach(a =>