sto-k-odnomu/backend/src/game/game.gateway.ts

216 lines
7.4 KiB
TypeScript
Raw Normal View History

2026-01-03 14:07:04 +00:00
import {
WebSocketGateway,
WebSocketServer,
SubscribeMessage,
OnGatewayConnection,
OnGatewayDisconnect,
2026-01-07 14:32:51 +00:00
OnGatewayInit,
2026-01-03 14:07:04 +00:00
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import { RoomsService } from '../rooms/rooms.service';
2026-01-07 14:32:51 +00:00
import { RoomEventsService } from './room-events.service';
2026-01-08 13:18:07 +00:00
import { PrismaService } from '../prisma/prisma.service';
2026-01-03 14:07:04 +00:00
@WebSocketGateway({
cors: {
2026-01-04 21:48:55 +00:00
// Примечание: декоратор выполняется на этапе инициализации,
// ConfigModule.forRoot() уже загружает переменные в process.env
2026-01-03 14:07:04 +00:00
origin: process.env.CORS_ORIGIN || 'http://localhost:5173',
credentials: true,
},
})
2026-01-07 14:32:51 +00:00
export class GameGateway implements OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit {
2026-01-03 14:07:04 +00:00
@WebSocketServer()
server: Server;
2026-01-07 14:32:51 +00:00
constructor(
private roomsService: RoomsService,
private roomEventsService: RoomEventsService,
2026-01-08 13:18:07 +00:00
private prisma: PrismaService,
2026-01-07 14:32:51 +00:00
) {}
afterInit(server: Server) {
this.roomEventsService.setServer(server);
}
2026-01-03 14:07:04 +00:00
handleConnection(client: Socket) {
console.log(`Client connected: ${client.id}`);
}
handleDisconnect(client: Socket) {
console.log(`Client disconnected: ${client.id}`);
}
2026-01-08 13:18:07 +00:00
private async isHost(roomId: string, userId: string): Promise<boolean> {
const room = await this.prisma.room.findUnique({
where: { id: roomId },
select: { hostId: true },
});
return room?.hostId === userId;
}
2026-01-03 14:07:04 +00:00
@SubscribeMessage('joinRoom')
async handleJoinRoom(client: Socket, payload: { roomCode: string; userId: string }) {
client.join(payload.roomCode);
const room = await this.roomsService.getRoomByCode(payload.roomCode);
this.server.to(payload.roomCode).emit('roomUpdate', room);
}
@SubscribeMessage('startGame')
2026-01-08 13:18:07 +00:00
async handleStartGame(client: Socket, payload: { roomId: string; roomCode: string; userId: string }) {
const isHost = await this.isHost(payload.roomId, payload.userId);
if (!isHost) {
client.emit('error', { message: 'Only the host can start the game' });
return;
}
2026-01-03 14:07:04 +00:00
await this.roomsService.updateRoomStatus(payload.roomId, 'PLAYING');
const room = await this.roomsService.getRoomByCode(payload.roomCode);
if (room) {
this.server.to(room.code).emit('gameStarted', room);
}
}
@SubscribeMessage('revealAnswer')
2026-01-08 13:18:07 +00:00
async handleRevealAnswer(client: Socket, payload: { roomCode: string; answerIndex: number; userId: string; roomId: string }) {
const isHost = await this.isHost(payload.roomId, payload.userId);
if (!isHost) {
client.emit('error', { message: 'Only the host can reveal answers' });
return;
}
2026-01-03 14:07:04 +00:00
this.server.to(payload.roomCode).emit('answerRevealed', payload);
}
@SubscribeMessage('updateScore')
2026-01-08 13:18:07 +00:00
async handleUpdateScore(client: Socket, payload: { participantId: string; score: number; roomCode: string; userId: string; roomId: string }) {
const isHost = await this.isHost(payload.roomId, payload.userId);
if (!isHost) {
client.emit('error', { message: 'Only the host can update scores' });
return;
}
2026-01-03 14:07:04 +00:00
await this.roomsService.updateParticipantScore(payload.participantId, payload.score);
this.server.to(payload.roomCode).emit('scoreUpdated', payload);
}
@SubscribeMessage('nextQuestion')
2026-01-08 13:18:07 +00:00
async handleNextQuestion(client: Socket, payload: { roomCode: string; userId: string; roomId: string }) {
const isHost = await this.isHost(payload.roomId, payload.userId);
if (!isHost) {
client.emit('error', { message: 'Only the host can change questions' });
return;
}
2026-01-03 14:07:04 +00:00
this.server.to(payload.roomCode).emit('questionChanged', payload);
}
@SubscribeMessage('endGame')
2026-01-08 13:18:07 +00:00
async handleEndGame(client: Socket, payload: { roomId: string; roomCode: string; userId: string }) {
const isHost = await this.isHost(payload.roomId, payload.userId);
if (!isHost) {
client.emit('error', { message: 'Only the host can end the game' });
return;
}
2026-01-03 14:07:04 +00:00
await this.roomsService.updateRoomStatus(payload.roomId, 'FINISHED');
this.server.to(payload.roomCode).emit('gameEnded', payload);
}
2026-01-08 13:18:07 +00:00
@SubscribeMessage('setCurrentPlayer')
async handleSetCurrentPlayer(client: Socket, payload: { roomId: string; roomCode: string; userId: string; playerId: string }) {
const isHost = await this.isHost(payload.roomId, payload.userId);
if (!isHost) {
client.emit('error', { message: 'Only the host can select the current player' });
return;
}
await this.prisma.room.update({
where: { id: payload.roomId },
data: { currentPlayerId: payload.playerId },
});
this.server.to(payload.roomCode).emit('currentPlayerChanged', { playerId: payload.playerId });
}
@SubscribeMessage('updateRoomSettings')
async handleUpdateRoomSettings(client: Socket, payload: { roomId: string; roomCode: string; userId: string; settings: any }) {
const isHost = await this.isHost(payload.roomId, payload.userId);
if (!isHost) {
client.emit('error', { message: 'Only the host can update room settings' });
return;
}
await this.prisma.room.update({
where: { id: payload.roomId },
data: payload.settings,
});
const room = await this.roomsService.getRoomByCode(payload.roomCode);
this.server.to(payload.roomCode).emit('roomUpdate', room);
}
@SubscribeMessage('restartGame')
async handleRestartGame(client: Socket, payload: { roomId: string; roomCode: string; userId: string }) {
const isHost = await this.isHost(payload.roomId, payload.userId);
if (!isHost) {
client.emit('error', { message: 'Only the host can restart the game' });
return;
}
await this.prisma.room.update({
where: { id: payload.roomId },
data: {
status: 'WAITING',
currentQuestionIndex: 0,
revealedAnswers: {},
currentPlayerId: null,
isGameOver: false,
answeredQuestions: 0,
},
});
await this.prisma.participant.updateMany({
where: { roomId: payload.roomId },
data: { score: 0 },
});
const room = await this.roomsService.getRoomByCode(payload.roomCode);
this.server.to(payload.roomCode).emit('gameRestarted', room);
}
@SubscribeMessage('updateCustomQuestions')
async handleUpdateCustomQuestions(client: Socket, payload: { roomId: string; roomCode: string; userId: string; questions: any }) {
const isHost = await this.isHost(payload.roomId, payload.userId);
if (!isHost) {
client.emit('error', { message: 'Only the host can update questions' });
return;
}
await this.prisma.room.update({
where: { id: payload.roomId },
data: { customQuestions: payload.questions },
});
const room = await this.roomsService.getRoomByCode(payload.roomCode);
this.server.to(payload.roomCode).emit('customQuestionsUpdated', room);
}
@SubscribeMessage('kickPlayer')
async handleKickPlayer(client: Socket, payload: { roomId: string; roomCode: string; userId: string; participantId: string }) {
const isHost = await this.isHost(payload.roomId, payload.userId);
if (!isHost) {
client.emit('error', { message: 'Only the host can kick players' });
return;
}
await this.prisma.participant.update({
where: { id: payload.participantId },
data: { isActive: false },
});
const room = await this.roomsService.getRoomByCode(payload.roomCode);
this.server.to(payload.roomCode).emit('playerKicked', { participantId: payload.participantId, room });
}
2026-01-03 14:07:04 +00:00
}