diff --git a/backend/src/index.ts b/backend/src/index.ts index ea2302d0..57a6cd26 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -3,7 +3,7 @@ import cors from 'cors'; import cookieParser from 'cookie-parser'; import WebSocket from 'ws'; import jwt from 'jsonwebtoken'; -import DockerController from './services/DockerController'; +import DockerController, { globalDockerNetwork } from './services/DockerController'; import { FileSystemService } from './services/FileSystemService'; import { ComposeService } from './services/ComposeService'; import { ConfigService } from './services/ConfigService'; @@ -607,24 +607,16 @@ app.get('/api/stats', async (req: Request, res: Response) => { // Get host system stats app.get('/api/system/stats', async (req: Request, res: Response) => { try { - const [currentLoad, mem, fsSize, networkStats] = await Promise.all([ + const [currentLoad, mem, fsSize] = await Promise.all([ si.currentLoad(), si.mem(), - si.fsSize(), - si.networkStats(), + si.fsSize() ]); + let rxSec = Math.max(0, globalDockerNetwork.rxSec); + let txSec = Math.max(0, globalDockerNetwork.txSec); let rxBytes = 0; let txBytes = 0; - let rxSec = 0; - let txSec = 0; - - networkStats.forEach(net => { - rxBytes += net.rx_bytes || 0; - txBytes += net.tx_bytes || 0; - rxSec += net.rx_sec || 0; - txSec += net.tx_sec || 0; - }); // Find the main mount (usually the largest or root mount) const mainDisk = fsSize.find(fs => fs.mount === '/' || fs.mount === 'C:') || fsSize[0]; diff --git a/backend/src/services/DockerController.ts b/backend/src/services/DockerController.ts index fa28d75d..f8ae97bf 100644 --- a/backend/src/services/DockerController.ts +++ b/backend/src/services/DockerController.ts @@ -449,4 +449,55 @@ class DockerController { } } +export let globalDockerNetwork = { rxSec: 0, txSec: 0 }; +let lastNetSum = { rx: 0, tx: 0, timestamp: Date.now() }; + +export const updateGlobalDockerNetwork = async () => { + try { + const dockerController = DockerController.getInstance(); + const containers = await dockerController.getRunningContainers(); + + const statsResults = await Promise.allSettled( + containers.map(c => dockerController.getContainerStatsStream(c.Id)) + ); + + let currentRxSum = 0; + let currentTxSum = 0; + + for (const result of statsResults) { + if (result.status === 'fulfilled') { + try { + const stats = typeof result.value === 'string' ? JSON.parse(result.value) : result.value; + if (stats.networks) { + for (const [_, net] of Object.entries(stats.networks) as any) { + currentRxSum += net.rx_bytes || 0; + currentTxSum += net.tx_bytes || 0; + } + } + } catch (e) { + // ignore parsing errors + } + } + } + + const now = Date.now(); + const timeDiffSeconds = (now - lastNetSum.timestamp) / 1000; + + if (timeDiffSeconds > 0) { + const rxDelta = currentRxSum >= lastNetSum.rx ? currentRxSum - lastNetSum.rx : 0; + const txDelta = currentTxSum >= lastNetSum.tx ? currentTxSum - lastNetSum.tx : 0; + + globalDockerNetwork.rxSec = rxDelta / timeDiffSeconds; + globalDockerNetwork.txSec = txDelta / timeDiffSeconds; + } + + lastNetSum = { rx: currentRxSum, tx: currentTxSum, timestamp: now }; + } catch (error) { + console.error('Failed to update global docker network stats:', error); + } +}; + +// Start the interval tracker +setInterval(updateGlobalDockerNetwork, 3000); + export default DockerController; diff --git a/frontend/src/components/HomeDashboard.tsx b/frontend/src/components/HomeDashboard.tsx index a989d28d..231dc11b 100644 --- a/frontend/src/components/HomeDashboard.tsx +++ b/frontend/src/components/HomeDashboard.tsx @@ -172,7 +172,7 @@ export default function HomeDashboard() { - Host Network + Docker Network