Added the ability to establish a connection using a web socket

pull/12/head
DmitriyA 2025-04-01 11:52:04 -04:00
parent c4fdfb1280
commit 49a5471c01
4 changed files with 117 additions and 4 deletions

View File

@ -33,7 +33,10 @@
"pg": "^8.14.1",
"typeorm": "^0.3.21",
"bcrypt": "^5.1.1",
"@types/bcrypt": "^5.0.2"
"@types/bcrypt": "^5.0.2",
"socket.io": "^4.8.1",
"@nestjs/websockets": "11.0.12",
"@nestjs/platform-socket.io": "11.0.12"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",

View File

@ -5,6 +5,7 @@ import { PrometheusService } from './prometheus.service';
import { MetricsController } from './metrics.controller';
import { ConfigModule } from '@nestjs/config';
import { AuthModule } from './auth/auth.module';
import { MetricsGateway } from './metrics.gateway';
@Module({
imports: [
@ -27,6 +28,10 @@ import { AuthModule } from './auth/auth.module';
AuthModule,
],
controllers: [MetricsController],
providers: [PrometheusService],
providers: [
PrometheusService,
MetricsGateway,
],
exports: [MetricsGateway],
})
export class AppModule { }

View File

@ -3,11 +3,15 @@ import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule, { cors: false });
const app = await NestFactory.create(AppModule);
//настройка CORS
app.enableCors({
origin: '*',
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
allowedHeaders: 'Content-Type, Authorization',
});
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();

101
src/metrics.gateway.ts Normal file
View File

@ -0,0 +1,101 @@
import { WebSocketGateway, WebSocketServer, OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect, SubscribeMessage, } from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import { PrometheusService } from './prometheus.service';
import { Logger } from '@nestjs/common';
@WebSocketGateway({
cors: {
origin: '*', // В production укажите конкретные домены
methods: ['GET', 'POST'],
credentials: true
},
namespace: '/metrics-ws'
})
export class MetricsGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
@WebSocketServer() server: Server;
private readonly logger = new Logger(MetricsGateway.name);
private activeSockets: Map<string, Socket> = new Map();
constructor(private readonly prometheusService: PrometheusService) { }
afterInit(server: Server) {
this.logger.log('WebSocket Gateway initialized');
this.logger.log('WebSocket server initialized successfully');
}
handleConnection(client: Socket) {
this.logger.log(`Client connected: ${client.id}`);
this.logger.log(`New client connected: ${client.id} from ${client.handshake.address}`);
this.activeSockets.set(client.id, client);
}
handleDisconnect(client: Socket) {
this.logger.log(`Client disconnected: ${client.id}`);
this.activeSockets.delete(client.id);
}
@SubscribeMessage('get-metrics')
async handleGetMetrics(client: Socket, payload: any) {
const { metric, start, end, step } = payload;
try {
const data = start && end && step
? await this.prometheusService.fetchMetricsRange(metric, start, end, step)
: await this.prometheusService.fetchMetrics(metric);
client.emit('metrics-data', { metric, data });
} catch (error) {
this.logger.error(`Error fetching metrics: ${error.message}`);
client.emit('metrics-error', {
metric,
error: error.message
});
}
}
@SubscribeMessage('get-metric-types')
async handleGetMetricTypes(client: Socket, payload: { metric: string }) {
try {
const type = await this.prometheusService.fetchMetricType(payload.metric);
const description = await this.prometheusService.fetchMetricDescription(payload.metric);
client.emit('metric-types', {
metric: payload.metric,
type,
description
});
} catch (error) {
this.logger.log(`Error fetching metric types: ${error.message}`);
client.emit('metrics-error', {
metric: payload.metric,
error: error.message
});
}
}
@SubscribeMessage('get-all-metrics')
async handleGetAllMetrics(client: Socket) {
try {
const metrics = await this.prometheusService.fetchAllMetrics();
client.emit('all-metrics', metrics);
} catch (error) {
this.logger.log(`Error fetching all metrics: ${error.message}`);
client.emit('metrics-error', {
error: error.message
});
}
}
// Метод для периодической отправки обновлений
async sendPeriodicUpdates(metric: string, interval: number = 5000) {
const timer = setInterval(async () => {
try {
const data = await this.prometheusService.fetchMetrics(metric);
this.server.emit('metrics-update', { metric, data });
} catch (error) {
this.logger.error(`Error in periodic update for ${metric}: ${error.message}`);
}
}, interval);
// Возвращаем функцию для остановки обновлений
return () => clearInterval(timer);
}
}