generated from fahricansecer/boilerplate-be
This commit is contained in:
205
src/modules/events/events.gateway.ts
Normal file
205
src/modules/events/events.gateway.ts
Normal file
@@ -0,0 +1,205 @@
|
||||
import {
|
||||
WebSocketGateway,
|
||||
WebSocketServer,
|
||||
SubscribeMessage,
|
||||
OnGatewayConnection,
|
||||
OnGatewayDisconnect,
|
||||
ConnectedSocket,
|
||||
MessageBody,
|
||||
} from '@nestjs/websockets';
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { Server, Socket } from 'socket.io';
|
||||
|
||||
/**
|
||||
* ContentGen AI — Gerçek Zamanlı WebSocket Gateway
|
||||
*
|
||||
* Frontend'e render ilerleme bildirimlerini iletir.
|
||||
* C# Worker → RenderCallbackController → EventsGateway → Frontend
|
||||
*
|
||||
* Room yapısı: "project:{projectId}" — her proje kendi room'una abone olur
|
||||
*/
|
||||
@WebSocketGateway({
|
||||
cors: {
|
||||
origin: ['http://localhost:3001', 'http://localhost:3000', process.env.FRONTEND_URL || '*'],
|
||||
credentials: true,
|
||||
},
|
||||
namespace: '/ws',
|
||||
transports: ['websocket', 'polling'],
|
||||
})
|
||||
export class EventsGateway implements OnGatewayConnection, OnGatewayDisconnect {
|
||||
@WebSocketServer()
|
||||
server: Server;
|
||||
|
||||
private readonly logger = new Logger(EventsGateway.name);
|
||||
private connectedClients = 0;
|
||||
|
||||
handleConnection(client: Socket) {
|
||||
this.connectedClients++;
|
||||
this.logger.log(`Client bağlandı: ${client.id} (toplam: ${this.connectedClients})`);
|
||||
}
|
||||
|
||||
handleDisconnect(client: Socket) {
|
||||
this.connectedClients--;
|
||||
this.logger.log(`Client ayrıldı: ${client.id} (toplam: ${this.connectedClients})`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Frontend, proje detay sayfasına girdiğinde bu event'i gönderir.
|
||||
* Client ilgili proje room'una katılır.
|
||||
*/
|
||||
@SubscribeMessage('join:project')
|
||||
handleJoinProject(
|
||||
@ConnectedSocket() client: Socket,
|
||||
@MessageBody() data: { projectId: string },
|
||||
) {
|
||||
const room = `project:${data.projectId}`;
|
||||
client.join(room);
|
||||
this.logger.debug(`Client ${client.id} → room: ${room}`);
|
||||
return { event: 'joined', data: { room, projectId: data.projectId } };
|
||||
}
|
||||
|
||||
/**
|
||||
* Frontend, proje sayfasından ayrıldığında bu event'i gönderir.
|
||||
*/
|
||||
@SubscribeMessage('leave:project')
|
||||
handleLeaveProject(
|
||||
@ConnectedSocket() client: Socket,
|
||||
@MessageBody() data: { projectId: string },
|
||||
) {
|
||||
const room = `project:${data.projectId}`;
|
||||
client.leave(room);
|
||||
this.logger.debug(`Client ${client.id} ← room: ${room}`);
|
||||
return { event: 'left', data: { room } };
|
||||
}
|
||||
|
||||
/**
|
||||
* Kullanıcı kendi bildirim room'una katılır.
|
||||
* Frontend login sonrası bu event'i göndererek anlık bildirimleri alır.
|
||||
*/
|
||||
@SubscribeMessage('join:user')
|
||||
handleJoinUser(
|
||||
@ConnectedSocket() client: Socket,
|
||||
@MessageBody() data: { userId: string },
|
||||
) {
|
||||
const room = `user:${data.userId}`;
|
||||
client.join(room);
|
||||
this.logger.debug(`Client ${client.id} → user room: ${room}`);
|
||||
return { event: 'joined', data: { room, userId: data.userId } };
|
||||
}
|
||||
|
||||
/**
|
||||
* Kullanıcı bildirim room'undan ayrılır.
|
||||
*/
|
||||
@SubscribeMessage('leave:user')
|
||||
handleLeaveUser(
|
||||
@ConnectedSocket() client: Socket,
|
||||
@MessageBody() data: { userId: string },
|
||||
) {
|
||||
const room = `user:${data.userId}`;
|
||||
client.leave(room);
|
||||
this.logger.debug(`Client ${client.id} ← user room: ${room}`);
|
||||
return { event: 'left', data: { room } };
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════
|
||||
// Server → Client Events (RenderCallbackController tarafından tetiklenir)
|
||||
// ═══════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Render ilerleme bildirimi gönder.
|
||||
* Stage: 'tts' | 'image_generation' | 'music_generation' | 'compositing' | 'encoding'
|
||||
*/
|
||||
emitRenderProgress(
|
||||
projectId: string,
|
||||
payload: {
|
||||
progress: number;
|
||||
stage: string;
|
||||
stageLabel: string;
|
||||
currentScene?: number;
|
||||
totalScenes?: number;
|
||||
eta?: number; // Tahmini kalan saniye
|
||||
},
|
||||
) {
|
||||
this.server.to(`project:${projectId}`).emit('render:progress', {
|
||||
projectId,
|
||||
...payload,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Render tamamlandı bildirimi.
|
||||
*/
|
||||
emitRenderCompleted(
|
||||
projectId: string,
|
||||
payload: {
|
||||
finalVideoUrl: string;
|
||||
thumbnailUrl?: string;
|
||||
processingTimeMs: number;
|
||||
fileSize: number;
|
||||
},
|
||||
) {
|
||||
this.server.to(`project:${projectId}`).emit('render:completed', {
|
||||
projectId,
|
||||
...payload,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Render hatası bildirimi.
|
||||
*/
|
||||
emitRenderFailed(
|
||||
projectId: string,
|
||||
payload: {
|
||||
error: string;
|
||||
stage: string;
|
||||
attemptNumber: number;
|
||||
canRetry: boolean;
|
||||
},
|
||||
) {
|
||||
this.server.to(`project:${projectId}`).emit('render:failed', {
|
||||
projectId,
|
||||
...payload,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Proje durum değişikliği bildirimi (status change).
|
||||
*/
|
||||
emitProjectStatusChanged(projectId: string, status: string) {
|
||||
this.server.to(`project:${projectId}`).emit('project:status', {
|
||||
projectId,
|
||||
status,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Kullanıcıya anlık bildirim gönder.
|
||||
* NotificationsService.createNotification() tarafından çağrılır.
|
||||
*/
|
||||
emitNotification(
|
||||
userId: string,
|
||||
payload: {
|
||||
id: string;
|
||||
type: string;
|
||||
title: string;
|
||||
message?: string | null;
|
||||
metadata?: unknown;
|
||||
isRead: boolean;
|
||||
createdAt: string;
|
||||
},
|
||||
) {
|
||||
this.server.to(`user:${userId}`).emit('notification:new', {
|
||||
...payload,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
/** Bağlı client sayısını döndür (health check için) */
|
||||
getConnectedClientsCount(): number {
|
||||
return this.connectedClients;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user