feat(monitoring): improve network activity metrics with live domain request rates and backend identifiers

This commit is contained in:
2026-04-25 20:37:28 +00:00
parent 97017ede98
commit b3751abd17
18 changed files with 318 additions and 93 deletions
+1 -1
View File
@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@serve.zone/dcrouter',
version: '13.20.2',
version: '13.21.0',
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
}
+23 -18
View File
@@ -512,15 +512,6 @@ export const fetchNetworkStatsAction = networkStatePart.createAction(async (stat
if (!context.identity) return currentState;
try {
// Fetch active connections using the existing endpoint
const connectionsRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
interfaces.requests.IReq_GetActiveConnections
>('/typedrequest', 'getActiveConnections');
const connectionsResponse = await connectionsRequest.fire({
identity: context.identity,
});
// Get network stats for throughput and IP data
const networkStatsRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
interfaces.requests.IReq_GetNetworkStats
@@ -533,22 +524,35 @@ export const fetchNetworkStatsAction = networkStatePart.createAction(async (stat
// Use the connections data for the connection list
// and network stats for throughput and IP analytics
const connectionsByIP: { [ip: string]: number } = {};
const throughputByIP = new Map<string, { in: number; out: number }>();
for (const item of networkStatsResponse.throughputByIP || []) {
throughputByIP.set(item.ip, { in: item.in, out: item.out });
}
// Build connectionsByIP from network stats if available
if (networkStatsResponse.connectionsByIP && Array.isArray(networkStatsResponse.connectionsByIP)) {
networkStatsResponse.connectionsByIP.forEach((item: { ip: string; count: number }) => {
connectionsByIP[item.ip] = item.count;
});
} else {
// Fallback: calculate from connections
connectionsResponse.connections.forEach(conn => {
const ip = conn.remoteAddress;
connectionsByIP[ip] = (connectionsByIP[ip] || 0) + 1;
});
}
const connections: interfaces.data.IConnectionInfo[] = Object.entries(connectionsByIP).map(([ip, count]) => {
const tp = throughputByIP.get(ip);
return {
id: `ip-${ip}`,
remoteAddress: ip,
localAddress: 'server',
startTime: 0,
protocol: 'https',
state: 'connected',
bytesReceived: tp?.in || 0,
bytesSent: tp?.out || 0,
connectionCount: count,
};
});
return {
connections: connectionsResponse.connections,
connections,
connectionsByIP,
throughputRate: networkStatsResponse.throughputRate || { bytesInPerSecond: 0, bytesOutPerSecond: 0 },
totalBytes: networkStatsResponse.totalDataTransferred
@@ -2589,7 +2593,7 @@ async function dispatchCombinedRefreshActionInner() {
email: true,
dns: true,
security: true,
network: currentView === 'network', // Only fetch network if on network view
network: currentView === 'network' && currentSubview === 'activity',
radius: true,
vpn: true,
},
@@ -2617,7 +2621,7 @@ async function dispatchCombinedRefreshActionInner() {
// Build connectionsByIP from connectionDetails (now populated with real per-IP data)
network.connectionDetails.forEach(conn => {
connectionsByIP[conn.remoteAddress] = (connectionsByIP[conn.remoteAddress] || 0) + 1;
connectionsByIP[conn.remoteAddress] = (connectionsByIP[conn.remoteAddress] || 0) + (conn.connectionCount || 1);
});
// Build connections from connectionDetails (real per-IP aggregates)
@@ -2630,6 +2634,7 @@ async function dispatchCombinedRefreshActionInner() {
state: conn.state as any,
bytesReceived: conn.bytesIn,
bytesSent: conn.bytesOut,
connectionCount: conn.connectionCount,
}));
networkStatePart.setState({
@@ -79,7 +79,6 @@ export class OpsViewNetworkActivity extends DeesElement {
// Subscribe and track unsubscribe functions
const statsUnsubscribe = appstate.statsStatePart.select().subscribe((state) => {
this.statsState = state;
this.updateNetworkData();
});
this.rxSubscriptions.push(statsUnsubscribe);
@@ -560,6 +559,8 @@ export class OpsViewNetworkActivity extends DeesElement {
'Throughput Out': this.formatBitsPerSecond(item.bytesOutPerSecond),
'Transferred / min': this.formatBytes(totalBytesPerMin),
'Connections': item.activeConnections,
'Req/s': item.requestsPerSecond != null ? item.requestsPerSecond.toFixed(1) : '-',
'Req/min': item.requestsLastMinute != null ? item.requestsLastMinute.toFixed(0) : '-',
'Requests': item.requestCount?.toLocaleString() ?? '0',
'Routes': item.routeCount,
};
@@ -583,7 +584,7 @@ export class OpsViewNetworkActivity extends DeesElement {
return html`
<dees-table
.data=${backends}
.rowKey=${'backend'}
.rowKey=${'id'}
.highlightUpdates=${'flash'}
.displayFunction=${(item: interfaces.data.IBackendInfo) => {
const totalErrors = item.connectErrors + item.handshakeErrors + item.requestErrors;
@@ -707,6 +708,9 @@ export class OpsViewNetworkActivity extends DeesElement {
}
const throughput = this.calculateThroughput();
if (this.networkState.lastUpdated && now - this.networkState.lastUpdated > 3000) {
return;
}
// Convert to Mbps (bytes * 8 / 1,000,000)
const throughputInMbps = (throughput.in * 8) / 1000000;