sto-k-odnomu/backend/src/rooms/rooms.service.ts

275 lines
6.7 KiB
TypeScript
Raw Normal View History

2026-01-07 14:23:06 +00:00
import { Injectable, Inject, forwardRef } from '@nestjs/common';
2026-01-03 14:07:04 +00:00
import { PrismaService } from '../prisma/prisma.service';
import { customAlphabet } from 'nanoid';
2026-01-07 14:32:51 +00:00
import { RoomEventsService } from '../game/room-events.service';
2026-01-08 17:56:00 +00:00
import { RoomPackService } from '../room-pack/room-pack.service';
2026-01-03 14:07:04 +00:00
const nanoid = customAlphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 6);
@Injectable()
export class RoomsService {
2026-01-07 14:23:06 +00:00
constructor(
private prisma: PrismaService,
2026-01-07 14:32:51 +00:00
@Inject(forwardRef(() => RoomEventsService))
private roomEventsService: RoomEventsService,
2026-01-08 17:56:00 +00:00
private roomPackService: RoomPackService,
2026-01-07 14:23:06 +00:00
) {}
2026-01-03 14:07:04 +00:00
2026-01-06 20:12:36 +00:00
async createRoom(hostId: string, questionPackId?: string, settings?: any) {
2026-01-03 14:07:04 +00:00
const code = nanoid();
const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
2026-01-06 20:33:44 +00:00
// Remove undefined values from settings and ensure questionPackId is handled correctly
const cleanSettings = settings ? { ...settings } : {};
if ('questionPackId' in cleanSettings) {
delete cleanSettings.questionPackId;
}
2026-01-03 14:07:04 +00:00
const room = await this.prisma.room.create({
data: {
code,
hostId,
expiresAt,
2026-01-06 20:33:44 +00:00
...cleanSettings,
questionPackId: questionPackId || null,
2026-01-03 14:07:04 +00:00
},
include: {
host: true,
questionPack: true,
},
});
await this.prisma.participant.create({
data: {
userId: hostId,
roomId: room.id,
name: room.host.name || 'Host',
role: 'HOST',
},
});
2026-01-08 17:56:00 +00:00
// Create RoomPack (always, even if empty)
await this.roomPackService.create(room.id, questionPackId);
// Return room with roomPack
return this.getRoomByCode(room.code);
2026-01-03 14:07:04 +00:00
}
async getRoomByCode(code: string) {
return this.prisma.room.findUnique({
where: { code },
include: {
host: true,
participants: {
include: { user: true },
},
questionPack: true,
2026-01-08 17:56:00 +00:00
roomPack: true,
2026-01-03 14:07:04 +00:00
},
});
}
async joinRoom(roomId: string, userId: string, name: string, role: 'PLAYER' | 'SPECTATOR') {
2026-01-07 14:23:06 +00:00
const participant = await this.prisma.participant.create({
2026-01-03 14:07:04 +00:00
data: {
userId,
roomId,
name,
role,
},
});
2026-01-07 14:23:06 +00:00
// Получаем обновленную комнату со всеми участниками
const room = await this.prisma.room.findUnique({
where: { id: roomId },
include: {
host: true,
participants: {
include: { user: true },
},
questionPack: true,
},
});
// Отправляем событие roomUpdate всем клиентам в комнате
2026-01-07 14:32:51 +00:00
if (room) {
this.roomEventsService.emitRoomUpdate(room.code, room);
2026-01-07 14:23:06 +00:00
}
return participant;
2026-01-03 14:07:04 +00:00
}
async updateRoomStatus(roomId: string, status: 'WAITING' | 'PLAYING' | 'FINISHED') {
return this.prisma.room.update({
where: { id: roomId },
data: { status },
});
}
async updateParticipantScore(participantId: string, score: number) {
return this.prisma.participant.update({
where: { id: participantId },
data: { score },
});
}
2026-01-06 20:12:36 +00:00
async updateQuestionPack(roomId: string, questionPackId: string) {
return this.prisma.room.update({
where: { id: roomId },
data: {
questionPackId,
currentQuestionIndex: 0,
revealedAnswers: {},
},
include: {
host: true,
participants: {
include: { user: true },
},
questionPack: true,
},
});
}
2026-01-08 13:18:07 +00:00
async updateCustomQuestions(roomId: string, questions: any) {
2026-01-08 17:56:00 +00:00
// DEPRECATED: Use updateRoomPack instead
return this.updateRoomPack(roomId, questions);
}
async updateRoomPack(roomId: string, questions: any[]) {
await this.roomPackService.updateQuestions(roomId, questions);
const room = await this.prisma.room.findUnique({
2026-01-08 13:18:07 +00:00
where: { id: roomId },
include: {
host: true,
participants: {
include: { user: true },
},
questionPack: true,
2026-01-08 17:56:00 +00:00
roomPack: true,
2026-01-08 13:18:07 +00:00
},
});
2026-01-08 17:56:00 +00:00
this.roomEventsService.emitRoomPackUpdated(room.code, room);
2026-01-08 13:18:07 +00:00
return room;
}
async getEffectiveQuestions(roomId: string) {
const room = await this.prisma.room.findUnique({
where: { id: roomId },
2026-01-08 17:56:00 +00:00
include: { roomPack: true, questionPack: true },
2026-01-08 13:18:07 +00:00
});
if (!room) {
return null;
}
2026-01-08 17:56:00 +00:00
// Priority 1: RoomPack questions
if (room.roomPack && room.roomPack.questions) {
return room.roomPack.questions;
2026-01-08 13:18:07 +00:00
}
2026-01-08 17:56:00 +00:00
// Priority 2: QuestionPack (fallback for legacy rooms)
2026-01-08 13:18:07 +00:00
if (room.questionPack) {
return room.questionPack.questions;
}
return null;
}
async updateRoomSettings(roomId: string, settings: any) {
const room = await this.prisma.room.update({
where: { id: roomId },
data: settings,
include: {
host: true,
participants: {
include: { user: true },
},
questionPack: true,
},
});
this.roomEventsService.emitRoomUpdate(room.code, room);
return room;
}
async restartGame(roomId: string) {
await this.prisma.room.update({
where: { id: roomId },
data: {
status: 'WAITING',
currentQuestionIndex: 0,
revealedAnswers: {},
currentPlayerId: null,
isGameOver: false,
answeredQuestions: 0,
},
});
await this.prisma.participant.updateMany({
where: { roomId },
data: { score: 0 },
});
const room = await this.prisma.room.findUnique({
where: { id: roomId },
include: {
host: true,
participants: {
include: { user: true },
},
questionPack: true,
},
});
if (room) {
this.roomEventsService.emitGameRestarted(room.code, room);
}
return room;
}
async setCurrentPlayer(roomId: string, playerId: string) {
const room = await this.prisma.room.update({
where: { id: roomId },
data: { currentPlayerId: playerId },
include: {
host: true,
participants: {
include: { user: true },
},
questionPack: true,
},
});
this.roomEventsService.emitCurrentPlayerChanged(room.code, { playerId });
return room;
}
async kickPlayer(roomId: string, participantId: string) {
await this.prisma.participant.update({
where: { id: participantId },
data: { isActive: false },
});
const room = await this.prisma.room.findUnique({
where: { id: roomId },
include: {
host: true,
participants: {
include: { user: true },
},
questionPack: true,
},
});
if (room) {
this.roomEventsService.emitPlayerKicked(room.code, { participantId, room });
}
return room;
}
2026-01-03 14:07:04 +00:00
}