import { Body, Controller, HttpException, HttpStatus, Param, Post, Session, Sse, UseGuards, } from '@nestjs/common'; import { LobbyService } from '../services/lobby.service'; import { AuthGuard } from '../guards/auth.guard'; import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; import { Game } from '../entities/game.entity'; import { GamePipe, GameStartedPipe } from '../pipe/game.pipe'; import { Observable, fromEvent, map } from 'rxjs'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { GameService } from '../services/games.service'; import { ConfigService } from '@nestjs/config'; import { SessionData } from 'express-session'; @ApiTags('game') @Controller('games/:id') export class GamesController { constructor( private readonly lobbyService: LobbyService, private readonly gameService: GameService, private eventEmitter: EventEmitter2, private configService: ConfigService, ) {} @Post('/start') @ApiOperation({ summary: 'Start game' }) @ApiResponse({ status: 201, description: 'Game successfully started.', }) @ApiResponse({ status: 400, description: 'Bad Request', }) @ApiResponse({ status: 403, description: 'You can only start games you own', }) @UseGuards(AuthGuard) async start( @Param('id') id: string, @Session() session: SessionData, @Param('id', GamePipe) game: Game, ) { if (game.started) { throw new HttpException('Game already started', HttpStatus.BAD_REQUEST); } if (game.players.length < 2 && !this.configService.get('DEV_MODE')) { throw new HttpException( 'Not enough teams to start the game', HttpStatus.BAD_REQUEST, ); } if (game.owner.id != session.user.id) { throw new HttpException( 'You can only start games you own', HttpStatus.FORBIDDEN, ); } await this.gameService.start(game); return; } @Post('surrender') @ApiOperation({ summary: 'Leave a game that has already started' }) @UseGuards(AuthGuard) surrender( @Param('id') id: string, @Session() session: SessionData, @Param('id', GamePipe) game: Game, ) { if (!game.started) { throw new HttpException('Game has not started', HttpStatus.BAD_REQUEST); } return this.lobbyService.leaveGame(game, session.user); } @Post('kick/:playerId') @ApiOperation({ summary: 'Kick a player' }) @UseGuards(AuthGuard) kick( @Param('id') id: string, @Session() session: SessionData, @Param('id', GamePipe) game: Game, @Param('playerId') playerId: string, ) { if (session.user.id != game.owner.id) { throw new HttpException( 'You do do not own this game', HttpStatus.FORBIDDEN, ); } return this.lobbyService.kickPlayer(game, session.user, playerId); } @Sse('/subscribe') subscribe(@Param('id') id: string): Observable<{ data: string }> { return fromEvent(this.eventEmitter, 'sse.game.' + id).pipe( map((payload: any) => { return { data: JSON.stringify(payload), }; }), ); } }