Skip to content

Instantly share code, notes, and snippets.

@tbhaxor
Created April 4, 2024 17:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tbhaxor/e463403347e95714b470f726290470b1 to your computer and use it in GitHub Desktop.
Save tbhaxor/e463403347e95714b470f726290470b1 to your computer and use it in GitHub Desktop.
import {
ConnectedSocket,
MessageBody,
OnGatewayConnection,
SubscribeMessage,
WebSocketGateway,
WebSocketServer,
} from '@nestjs/websockets';
import { GameService } from './game.service';
import type { Namespace, Socket } from 'socket.io';
import {
BadRequestException,
ConsoleLogger,
HttpException,
InternalServerErrorException,
UseFilters,
ValidationPipe,
} from '@nestjs/common';
import { GameMazeDto } from './dtos/game-maze-ws.dto';
import { WsGatewayExceptionFilter } from './filters/bad-request/ws-gateway-exception.filter';
import { GameDto } from './dtos/game.dto';
@WebSocketGateway(8080, { transports: ['websocket'], namespace: 'game', cors: { origin: true } })
export class GameGateway implements OnGatewayConnection {
private readonly logger = new ConsoleLogger(GameGateway.name, {
timestamp: true,
logLevels: process.env.NODE_ENV === 'test' && ['fatal'],
});
@WebSocketServer() private io: Namespace;
constructor(private gameService: GameService) {}
@SubscribeMessage('gameMazeMark')
@UseFilters(WsGatewayExceptionFilter)
async handleGameMazeUpdate(
@MessageBody(new ValidationPipe({ transform: true })) body: GameMazeDto,
@ConnectedSocket() socket: Socket,
) {
const game = this.gameService.getGameById(body.gameId);
if (game.currentPlayer != socket.id) {
throw new BadRequestException(['Please wait for your turn.']);
} else if (game.isEnded) {
throw new BadRequestException(['Game is already ended.']);
}
const maze = game.maze.find((v) => v.colId == body.colId && v.rowId == body.rowId);
maze.mark(game.currentSymbol);
this.io.to(body.gameId).emit('gameMazeMarked', {
colId: body.colId,
rowId: body.rowId,
symbol: game.currentSymbol,
});
game.switchTurn();
this.io.to(body.gameId).emit('gameTurn', { playerId: game.currentPlayer });
this.io.to(body.gameId).emit('gameStats', { winner: game.winner, isEnded: game.isEnded, isDraw: game.isDraw });
}
@UseFilters(WsGatewayExceptionFilter)
async handleConnection(socket: Socket) {
this.logger.log(`Player ${socket.id} tried connection from ${socket.conn.remoteAddress}`);
const isNew = typeof socket.handshake.query['gameId'] === 'undefined';
const gameId = (isNew && this.gameService.createGame(socket.id)) || <string>socket.handshake.query['gameId'];
let game: GameDto;
try {
game = this.gameService.getGameById(gameId);
} catch (error) {
this.logger.error(error);
if (error instanceof HttpException) {
socket.emit('exception', error.getResponse());
} else if (error instanceof Error) {
socket.emit('exception', new InternalServerErrorException(error.message).getResponse());
}
return socket.disconnect(true);
}
if (isNew) {
await socket.join(gameId);
socket.emit('gameCreated', { gameId });
} else {
this.gameService.joinToGame(gameId, socket.id);
await socket.join(gameId);
}
this.logger.log(`Player ${socket.id} joined the game ${gameId}`);
this.io.to(gameId).emit('gameJoined', { playerId: socket.id });
this.io.to(gameId).emit('gameTurn', { playerId: game.currentPlayer });
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment