Compare commits

...

3 Commits

Author SHA1 Message Date
Raven Scott
d9549454e1 fix 2024-11-30 03:26:40 -05:00
Raven Scott
3177976845 update 2024-11-30 03:17:21 -05:00
Raven Scott
b8c6f30d32 better stat tracking 2024-11-30 03:08:13 -05:00

145
app.js
View File

@ -20,9 +20,10 @@ const connections = {};
window.openTerminals = {}; window.openTerminals = {};
let activePeer = null; let activePeer = null;
window.activePeer = null; // Expose to other modules window.activePeer = null; // Expose to other modules
hideStatusIndicator();
let statsInterval = null; // Global variable to hold the interval
hideStatusIndicator();
let statsInterval = null;
let lastStatsUpdate = Date.now();
function stopStatsInterval() { function stopStatsInterval() {
if (statsInterval) { if (statsInterval) {
clearInterval(statsInterval); clearInterval(statsInterval);
@ -31,21 +32,41 @@ function stopStatsInterval() {
} }
} }
function startStatsInterval() { function startStatsInterval() {
// Clear any existing interval
if (statsInterval) { if (statsInterval) {
clearInterval(statsInterval); clearInterval(statsInterval);
} }
// Start a new interval to request stats every second
statsInterval = setInterval(() => { statsInterval = setInterval(() => {
if (window.activePeer) { if (window.activePeer) {
console.log('[INFO] Requesting container stats...'); const now = Date.now();
sendCommand('stats', {}); // Adjust the command if specific arguments are needed if (now - lastStatsUpdate >= 500) { // Ensure at least 500ms between updates
sendCommand('stats', {}); // Adjust command if necessary
lastStatsUpdate = now;
}
} else { } else {
console.warn('[WARN] No active peer; skipping stats request.'); console.warn('[WARN] No active peer; skipping stats request.');
} }
}, 1000); // 1 second interval }, 500); // Poll every 100ms for better reactivity
}
const smoothedStats = {}; // Container-specific smoothing storage
function smoothStats(containerId, newStats, smoothingFactor = 0.2) {
if (!smoothedStats[containerId]) {
smoothedStats[containerId] = { cpu: 0, memory: 0 };
}
smoothedStats[containerId].cpu =
smoothedStats[containerId].cpu * (1 - smoothingFactor) +
newStats.cpu * smoothingFactor;
smoothedStats[containerId].memory =
smoothedStats[containerId].memory * (1 - smoothingFactor) +
newStats.memory * smoothingFactor;
return smoothedStats[containerId];
} }
function refreshContainerStats() { function refreshContainerStats() {
@ -261,43 +282,73 @@ collapseSidebarBtn.addEventListener('click', () => {
function handlePeerData(data, topicId, peer) { function handlePeerData(data, topicId, peer) {
try { try {
// Parse the incoming data
const response = JSON.parse(data.toString()); const response = JSON.parse(data.toString());
console.log(`[DEBUG] Received data from peer (topic: ${topicId}): ${JSON.stringify(response)}`); console.log(`[DEBUG] Received data from peer (topic: ${topicId}): ${JSON.stringify(response)}`);
// Ensure the data is for the active connection // Ensure the data is for the active connection
if (!connections[topicId] || peer !== window.activePeer) { if (!connections[topicId]) {
console.warn(`[WARN] Ignoring data from inactive peer or topic: ${topicId}`); console.warn(`[WARN] No connection found for topic: ${topicId}. Ignoring data.`);
return; return;
} }
// Process the response based on its type if (peer !== connections[topicId].peer) {
console.warn(`[WARN] Ignoring data from a non-active peer for topic: ${topicId}`);
return;
}
// Handle errors in the response
if (response.error) { if (response.error) {
console.error(`[ERROR] Server error: ${response.error}`); console.error(`[ERROR] Server error received: ${response.error}`);
showAlert('danger', response.error); showAlert('danger', response.error);
hideStatusIndicator(); hideStatusIndicator();
return; return;
} }
if (response.type === 'containers') { // Delegate handling based on the response type
renderContainers(response.data, topicId); // Scope containers to this topic switch (response.type) {
} else if (response.type === 'stats') { case 'containers':
response.data.topicId = topicId; // Attach the topicId to the stats console.log('[INFO] Processing container list...');
updateContainerStats(response.data); // Update stats for specific containers renderContainers(response.data, topicId); // Render containers specific to this topic
} else if (response.type === 'terminalOutput') { break;
appendTerminalOutput(response.data, response.containerId, response.encoding);
} else if (response.type === 'containerConfig') { case 'stats':
if (window.inspectContainerCallback) { console.log('[INFO] Updating container stats...');
window.inspectContainerCallback(response.data); if (!response.data.id) {
window.inspectContainerCallback = null; // Reset the callback console.warn('[WARN] Stats response is missing container ID. Skipping update.');
} return;
}
response.data.topicId = topicId; // Attach the topicId to the stats
updateContainerStats(response.data); // Update stats for the specified container
break;
case 'terminalOutput':
console.log('[INFO] Appending terminal output...');
appendTerminalOutput(response.data, response.containerId, response.encoding);
break;
case 'containerConfig':
console.log('[INFO] Handling container configuration...');
if (window.inspectContainerCallback) {
window.inspectContainerCallback(response.data);
window.inspectContainerCallback = null; // Reset the callback
}
break;
default:
console.warn(`[WARN] Unhandled response type: ${response.type}`);
break;
} }
// Handle peer response callback if defined
if (typeof window.handlePeerResponse === 'function') { if (typeof window.handlePeerResponse === 'function') {
window.handlePeerResponse(response); window.handlePeerResponse(response);
} }
} catch (err) { } catch (err) {
// Catch and log any parsing or processing errors
console.error(`[ERROR] Failed to process peer data: ${err.message}`); console.error(`[ERROR] Failed to process peer data: ${err.message}`);
showAlert('danger', 'Failed to process peer data.'); console.error(`[DEBUG] Raw data received: ${data.toString()}`);
showAlert('danger', 'Failed to process peer data. Check the console for details.');
} }
} }
@ -305,6 +356,7 @@ function handlePeerData(data, topicId, peer) {
// Add a new connection // Add a new connection
addConnectionForm.addEventListener('submit', (e) => { addConnectionForm.addEventListener('submit', (e) => {
e.preventDefault(); e.preventDefault();
@ -346,6 +398,7 @@ function addConnection(topicHex) {
e.stopPropagation(); e.stopPropagation();
disconnectConnection(topicId, connectionItem); disconnectConnection(topicId, connectionItem);
}); });
refreshContainerStats();
connectionList.appendChild(connectionItem); connectionList.appendChild(connectionItem);
@ -370,12 +423,13 @@ function addConnection(topicHex) {
window.activePeer = null; window.activePeer = null;
dashboard.classList.add('hidden'); dashboard.classList.add('hidden');
containerList.innerHTML = ''; containerList.innerHTML = '';
stopStatsInterval(); // Stop stats polling
} }
}); });
if (!window.activePeer) { if (!window.activePeer) {
switchConnection(topicId); switchConnection(topicId);
} }
startStatsInterval();
}); });
// Collapse the sidebar after adding a connection // Collapse the sidebar after adding a connection
@ -398,6 +452,15 @@ document.addEventListener('DOMContentLoaded', () => {
const topicHex = savedConnections[topicId].topic; const topicHex = savedConnections[topicId].topic;
addConnection(topicHex); addConnection(topicHex);
}); });
if (Object.keys(connections).length > 0) {
hideWelcomePage();
startStatsInterval(); // Start stats polling for active peers
} else {
showWelcomePage();
}
assertVisibility();
}); });
@ -769,31 +832,35 @@ function addActionListeners(row, container) {
} }
// Function to update container statistics function updateStatsUI(row, stats) {
function updateContainerStats(stats) { requestIdleCallback(() => {
console.log(`[DEBUG] Updating stats for container ID: ${stats.id}, Topic ID: ${stats.topicId}`); row.querySelector('.cpu').textContent = stats.cpu.toFixed(2) || '0.00';
row.querySelector('.memory').textContent = (stats.memory / (1024 * 1024)).toFixed(2) || '0.00';
row.querySelector('.ip-address').textContent = stats.ip || 'No IP Assigned';
});
}
// Ensure stats belong to the active connection function updateContainerStats(stats) {
if (!window.activePeer || !connections[stats.topicId] || window.activePeer !== connections[stats.topicId].peer) { if (!stats || !stats.id || typeof stats.cpu === 'undefined' || typeof stats.memory === 'undefined') {
console.warn(`[WARN] Stats received for inactive or unknown connection. Skipping.`); console.error('[ERROR] Invalid stats object:', stats);
return; return;
} }
// Find the row for the container by its ID console.log(`[DEBUG] Updating stats for container ID: ${stats.id}`);
const row = containerList.querySelector(`tr[data-container-id="${stats.id}"]`); const row = containerList.querySelector(`tr[data-container-id="${stats.id}"]`);
if (!row) { if (!row) {
console.warn(`[WARN] No matching row for container ID: ${stats.id}. Skipping stats update.`); console.warn(`[WARN] No matching row for container ID: ${stats.id}`);
return; return;
} }
// Update the container statistics in the UI const smoothed = smoothStats(stats.id, stats);
row.querySelector('.cpu').textContent = stats.cpu.toFixed(2) || '0.00'; updateStatsUI(row, smoothed);
row.querySelector('.memory').textContent = (stats.memory / (1024 * 1024)).toFixed(2) || '0.00';
row.querySelector('.ip-address').textContent = stats.ip || 'No IP Assigned';
} }
// Function to open the Duplicate Modal with container configurations // Function to open the Duplicate Modal with container configurations
function openDuplicateModal(container) { function openDuplicateModal(container) {
console.log(`[INFO] Opening Duplicate Modal for container: ${container.Id}`); console.log(`[INFO] Opening Duplicate Modal for container: ${container.Id}`);