Files
dcrouter/ts/opsserver/handlers/stats.handler.ts

376 lines
11 KiB
TypeScript
Raw Normal View History

import * as plugins from '../../plugins.js';
import type { OpsServer } from '../classes.opsserver.js';
import * as interfaces from '../../../ts_interfaces/index.js';
import { MetricsManager } from '../../monitoring/index.js';
export class StatsHandler {
public typedrouter = new plugins.typedrequest.TypedRouter();
constructor(private opsServerRef: OpsServer) {
// Add this handler's router to the parent
this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
this.registerHandlers();
}
private registerHandlers(): void {
// Server Statistics Handler
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetServerStatistics>(
'getServerStatistics',
async (dataArg, toolsArg) => {
const stats = await this.collectServerStats();
return {
stats: {
uptime: stats.uptime,
startTime: Date.now() - (stats.uptime * 1000),
memoryUsage: stats.memoryUsage,
cpuUsage: stats.cpuUsage,
activeConnections: stats.activeConnections,
totalConnections: stats.totalConnections,
},
history: dataArg.includeHistory ? stats.history : undefined,
};
}
)
);
// Email Statistics Handler
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetEmailStatistics>(
'getEmailStatistics',
async (dataArg, toolsArg) => {
const emailServer = this.opsServerRef.dcRouterRef.emailServer;
if (!emailServer) {
return {
stats: {
sent: 0,
received: 0,
bounced: 0,
queued: 0,
failed: 0,
averageDeliveryTime: 0,
deliveryRate: 0,
bounceRate: 0,
},
};
}
const stats = await this.collectEmailStats();
return {
stats: {
sent: stats.sentToday,
received: stats.receivedToday,
bounced: Math.floor(stats.sentToday * stats.bounceRate / 100),
queued: stats.queueSize,
failed: 0,
averageDeliveryTime: 0,
deliveryRate: stats.deliveryRate,
bounceRate: stats.bounceRate,
},
domainBreakdown: dataArg.includeDetails ? stats.domainBreakdown : undefined,
};
}
)
);
// DNS Statistics Handler
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetDnsStatistics>(
'getDnsStatistics',
async (dataArg, toolsArg) => {
const dnsServer = this.opsServerRef.dcRouterRef.dnsServer;
if (!dnsServer) {
return {
stats: {
totalQueries: 0,
cacheHits: 0,
cacheMisses: 0,
cacheHitRate: 0,
activeDomains: 0,
averageResponseTime: 0,
queryTypes: {},
},
};
}
const stats = await this.collectDnsStats();
return {
stats: {
totalQueries: stats.totalQueries,
cacheHits: stats.cacheHits,
cacheMisses: stats.cacheMisses,
cacheHitRate: stats.cacheHitRate,
activeDomains: stats.topDomains.length,
averageResponseTime: 0,
queryTypes: stats.queryTypes,
},
domainBreakdown: dataArg.includeQueryTypes ? stats.domainBreakdown : undefined,
};
}
)
);
// Queue Status Handler
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetQueueStatus>(
'getQueueStatus',
async (dataArg, toolsArg) => {
const emailServer = this.opsServerRef.dcRouterRef.emailServer;
const queues: interfaces.data.IQueueStatus[] = [];
if (emailServer) {
const status = await this.getQueueStatus();
queues.push({
name: dataArg.queueName || 'default',
size: status.pending,
processing: status.active,
failed: status.failed,
retrying: status.retrying,
averageProcessingTime: 0,
});
}
return {
queues,
totalItems: queues.reduce((sum, q) => sum + q.size + q.processing + q.failed + q.retrying, 0),
};
}
)
);
// Health Status Handler
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetHealthStatus>(
'getHealthStatus',
async (dataArg, toolsArg) => {
const health = await this.checkHealthStatus();
return {
health: {
healthy: health.healthy,
uptime: process.uptime(),
services: health.services.reduce((acc, service) => {
acc[service.name] = {
status: service.status,
message: service.message,
lastCheck: Date.now(),
};
return acc;
}, {} as any),
version: '2.12.0', // TODO: Get from package.json
},
};
}
)
);
}
private async collectServerStats(): Promise<{
uptime: number;
cpuUsage: {
user: number;
system: number;
};
memoryUsage: interfaces.data.IServerStats['memoryUsage'];
requestsPerSecond: number;
activeConnections: number;
totalConnections: number;
history: Array<{
timestamp: number;
value: number;
}>;
}> {
// Get metrics from MetricsManager if available
if (this.opsServerRef.dcRouterRef.metricsManager) {
const serverStats = await this.opsServerRef.dcRouterRef.metricsManager.getServerStats();
return {
uptime: serverStats.uptime,
cpuUsage: serverStats.cpuUsage,
memoryUsage: serverStats.memoryUsage,
requestsPerSecond: serverStats.requestsPerSecond,
activeConnections: serverStats.activeConnections,
totalConnections: serverStats.totalConnections,
history: [], // TODO: Implement history tracking
};
}
// Fallback to basic stats if MetricsManager not available
const uptime = process.uptime();
const memUsage = process.memoryUsage();
const cpuUsage = plugins.os.loadavg()[0] * 100 / plugins.os.cpus().length;
return {
uptime,
cpuUsage: {
user: cpuUsage * 0.7,
system: cpuUsage * 0.3,
},
memoryUsage: {
heapUsed: memUsage.heapUsed,
heapTotal: memUsage.heapTotal,
external: memUsage.external,
rss: memUsage.rss,
},
requestsPerSecond: 0,
activeConnections: 0,
totalConnections: 0,
history: [],
};
}
private async collectEmailStats(): Promise<{
sentToday: number;
receivedToday: number;
bounceRate: number;
deliveryRate: number;
queueSize: number;
domainBreakdown?: { [domain: string]: interfaces.data.IEmailStats };
}> {
// Get metrics from MetricsManager if available
if (this.opsServerRef.dcRouterRef.metricsManager) {
const emailStats = await this.opsServerRef.dcRouterRef.metricsManager.getEmailStats();
return {
sentToday: emailStats.sentToday,
receivedToday: emailStats.receivedToday,
bounceRate: emailStats.bounceRate,
deliveryRate: emailStats.deliveryRate,
queueSize: emailStats.queueSize,
};
}
// Fallback if MetricsManager not available
return {
sentToday: 0,
receivedToday: 0,
bounceRate: 0,
deliveryRate: 100,
queueSize: 0,
};
}
private async collectDnsStats(): Promise<{
queriesPerSecond: number;
totalQueries: number;
cacheHits: number;
cacheMisses: number;
cacheHitRate: number;
topDomains: Array<{
domain: string;
count: number;
}>;
queryTypes: { [key: string]: number };
domainBreakdown?: { [domain: string]: interfaces.data.IDnsStats };
}> {
// Get metrics from MetricsManager if available
if (this.opsServerRef.dcRouterRef.metricsManager) {
const dnsStats = await this.opsServerRef.dcRouterRef.metricsManager.getDnsStats();
return {
queriesPerSecond: dnsStats.queriesPerSecond,
totalQueries: dnsStats.totalQueries,
cacheHits: dnsStats.cacheHits,
cacheMisses: dnsStats.cacheMisses,
cacheHitRate: dnsStats.cacheHitRate,
topDomains: dnsStats.topDomains,
queryTypes: dnsStats.queryTypes,
};
}
// Fallback if MetricsManager not available
return {
queriesPerSecond: 0,
totalQueries: 0,
cacheHits: 0,
cacheMisses: 0,
cacheHitRate: 0,
topDomains: [],
queryTypes: {},
};
}
private async getQueueStatus(): Promise<{
pending: number;
active: number;
failed: number;
retrying: number;
items: Array<{
id: string;
recipient: string;
subject: string;
status: string;
attempts: number;
nextRetry?: number;
}>;
}> {
// TODO: Implement actual queue status collection
return {
pending: 0,
active: 0,
failed: 0,
retrying: 0,
items: [],
};
}
private async checkHealthStatus(): Promise<{
healthy: boolean;
services: Array<{
name: string;
status: 'healthy' | 'degraded' | 'unhealthy';
message?: string;
}>;
checks: Array<{
name: string;
passed: boolean;
message?: string;
}>;
}> {
const services: Array<{
name: string;
status: 'healthy' | 'degraded' | 'unhealthy';
message?: string;
}> = [];
// Check HTTP Proxy
if (this.opsServerRef.dcRouterRef.smartProxy) {
services.push({
name: 'HTTP/HTTPS Proxy',
status: 'healthy',
});
}
// Check Email Server
if (this.opsServerRef.dcRouterRef.emailServer) {
services.push({
name: 'Email Server',
status: 'healthy',
});
}
// Check DNS Server
if (this.opsServerRef.dcRouterRef.dnsServer) {
services.push({
name: 'DNS Server',
status: 'healthy',
});
}
// Check OpsServer
services.push({
name: 'OpsServer',
status: 'healthy',
});
const healthy = services.every(s => s.status === 'healthy');
return {
healthy,
services,
checks: [
{
name: 'Memory Usage',
passed: process.memoryUsage().heapUsed < (plugins.os.totalmem() * 0.9),
message: 'Memory usage within limits',
},
],
};
}
}