Files
ContentGen_BE/src/modules/events/events.gateway.ts
Harun CAN acb103657b
Some checks failed
Backend Deploy 🚀 / build-and-deploy (push) Has been cancelled
main
2026-03-30 00:21:32 +03:00

206 lines
5.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}
}