Create websocket exception filter
parent
e323623007
commit
5d55631812
|
|
@ -1,4 +1,4 @@
|
||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Injectable, Logger, UseFilters } from '@nestjs/common';
|
||||||
import {
|
import {
|
||||||
ConnectedSocket,
|
ConnectedSocket,
|
||||||
OnGatewayConnection,
|
OnGatewayConnection,
|
||||||
|
|
@ -10,6 +10,8 @@ import { PlayerService } from './players/player.service';
|
||||||
import { GameService } from 'src/games/game.service';
|
import { GameService } from 'src/games/game.service';
|
||||||
import { Socket } from 'socket.io';
|
import { Socket } from 'socket.io';
|
||||||
import { ClientEvent, CreateLobbyEvent, JoinLobbyEvent } from 'interface';
|
import { ClientEvent, CreateLobbyEvent, JoinLobbyEvent } from 'interface';
|
||||||
|
import { WsExceptionFilter } from './websocket-exception-filter';
|
||||||
|
import { PlayerNotFoundException } from './exceptions';
|
||||||
|
|
||||||
@WebSocketGateway({ cors: true })
|
@WebSocketGateway({ cors: true })
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
|
@ -24,6 +26,7 @@ export class AppService implements OnGatewayConnection {
|
||||||
this.playerService.createPlayer(client.id);
|
this.playerService.createPlayer(client.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UseFilters(new WsExceptionFilter([PlayerNotFoundException]))
|
||||||
@SubscribeMessage(ClientEvent.CREATE_LOBBY)
|
@SubscribeMessage(ClientEvent.CREATE_LOBBY)
|
||||||
handleCreateLobby(
|
handleCreateLobby(
|
||||||
@ConnectedSocket() client: Socket,
|
@ConnectedSocket() client: Socket,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { WsException } from '@nestjs/websockets';
|
||||||
|
import { ErrorCode } from 'interface';
|
||||||
|
|
||||||
|
export abstract class WebSocketException extends WsException {
|
||||||
|
public readonly errorCode: ErrorCode;
|
||||||
|
|
||||||
|
constructor(message: string, errorCode: ErrorCode) {
|
||||||
|
super(message);
|
||||||
|
this.errorCode = errorCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PlayerNotFoundException extends WebSocketException {
|
||||||
|
constructor(playerId: string) {
|
||||||
|
super(
|
||||||
|
'Unable to find player from ID: ' + playerId,
|
||||||
|
ErrorCode.PLAYER_NOT_FOUND,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GameNotFoundException extends WebSocketException {
|
||||||
|
constructor(gameId: string) {
|
||||||
|
super(
|
||||||
|
'Unable to find game from ID: ' + gameId,
|
||||||
|
ErrorCode.GAME_NOT_FOUND,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
import { Player } from './player';
|
import { Player } from './player';
|
||||||
|
import { PlayerNotFoundException } from 'src/exceptions';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PlayerService {
|
export class PlayerService {
|
||||||
|
|
@ -17,6 +18,10 @@ export class PlayerService {
|
||||||
|
|
||||||
getPlayer(socketId: string) {
|
getPlayer(socketId: string) {
|
||||||
this.logger.log(this.players.get(socketId).userName);
|
this.logger.log(this.players.get(socketId).userName);
|
||||||
|
const player = this.players.get(socketId);
|
||||||
|
if (!player) {
|
||||||
|
throw new PlayerNotFoundException(socketId);
|
||||||
|
}
|
||||||
return this.players.get(socketId);
|
return this.players.get(socketId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { ArgumentsHost, Catch, Logger } from '@nestjs/common';
|
||||||
|
import { BaseWsExceptionFilter } from '@nestjs/websockets';
|
||||||
|
import { GameNotFoundException, PlayerNotFoundException, WebSocketException } from './exceptions';
|
||||||
|
import { Socket } from 'socket.io';
|
||||||
|
import { ClientEvent } from 'interface';
|
||||||
|
import { emitCreateLobbyError } from 'interface';
|
||||||
|
|
||||||
|
@Catch(PlayerNotFoundException, GameNotFoundException)
|
||||||
|
export class WsExceptionFilter extends BaseWsExceptionFilter<WebSocketException> {
|
||||||
|
private readonly logger = new Logger(BaseWsExceptionFilter.name);
|
||||||
|
private readonly caughtExceptions: (typeof WebSocketException)[];
|
||||||
|
|
||||||
|
constructor(caughtExceptions: (typeof WebSocketException)[]) {
|
||||||
|
super();
|
||||||
|
this.caughtExceptions = caughtExceptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
catch(exception: WebSocketException, host: ArgumentsHost) {
|
||||||
|
const socket = host.switchToWs().getClient() as Socket;
|
||||||
|
const method = host.switchToWs().getPattern();
|
||||||
|
const data: object = host.switchToWs().getData();
|
||||||
|
this.logger.log(
|
||||||
|
`Caught exception: ${exception}
|
||||||
|
for request to ${method}
|
||||||
|
from client ${socket.id}
|
||||||
|
with input ${data}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!this.caughtExceptions.find(
|
||||||
|
(caughtException) => exception instanceof caughtException,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
this.logger.fatal("Uncaught exception", exception)
|
||||||
|
super.catch(exception, host);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (method) {
|
||||||
|
case ClientEvent.CREATE_LOBBY:
|
||||||
|
emitCreateLobbyError(socket, { error: exception.errorCode });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
export * from "./constants/TrackType";
|
export * from "./constants/TrackType";
|
||||||
|
export * from "./server-events/CreateLobbyError";
|
||||||
export * from "./server-events/ServerError";
|
export * from "./server-events/ServerError";
|
||||||
export * from "./server-events/ServerEvent";
|
export * from "./server-events/ServerEvent";
|
||||||
export * from "./server-events/UpdateLobbyEvent";
|
export * from "./server-events/UpdateLobbyEvent";
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { Socket as ServerSocket } from "socket.io";
|
||||||
|
import { Socket as ClientSocket } from "socket.io-client";
|
||||||
|
import { ErrorCode, ServerError } from "./ServerError";
|
||||||
|
|
||||||
|
export type CreateLobbyError = {
|
||||||
|
error: ErrorCode.PLAYER_NOT_FOUND | ErrorCode.GAME_NOT_FOUND;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const emitCreateLobbyError = (
|
||||||
|
socket: ServerSocket,
|
||||||
|
payload: CreateLobbyError,
|
||||||
|
) => {
|
||||||
|
socket.emit(ServerError.CREATE_LOBBY_ERROR, payload);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const attachHandlerToCreateLobbyError = (
|
||||||
|
socket: ClientSocket,
|
||||||
|
handler: (payload: CreateLobbyError) => void,
|
||||||
|
): (() => void) => {
|
||||||
|
socket.on(ServerError.CREATE_LOBBY_ERROR, handler);
|
||||||
|
return () => socket.off(ServerError.CREATE_LOBBY_ERROR);
|
||||||
|
};
|
||||||
|
|
@ -2,3 +2,8 @@ export enum ServerError {
|
||||||
CREATE_LOBBY_ERROR = "create-lobby-error",
|
CREATE_LOBBY_ERROR = "create-lobby-error",
|
||||||
JOIN_LOBBY_ERROR = "join-lobby-error",
|
JOIN_LOBBY_ERROR = "join-lobby-error",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ErrorCode {
|
||||||
|
PLAYER_NOT_FOUND = "player-not-found",
|
||||||
|
GAME_NOT_FOUND = "game-not-found",
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ const root = ReactDOM.createRoot(
|
||||||
document.getElementById("root") as HTMLElement,
|
document.getElementById("root") as HTMLElement,
|
||||||
);
|
);
|
||||||
const socket = io("http://localhost:3010");
|
const socket = io("http://localhost:3010");
|
||||||
|
socket.on("exception", console.log);
|
||||||
root.render(
|
root.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App socket={socket} />
|
<App socket={socket} />
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue