From 5264348e722f9f83ad066a31f4065e1e1db33bbe Mon Sep 17 00:00:00 2001 From: vvandenb Date: Mon, 6 Mar 2023 11:28:57 +0100 Subject: [PATCH] * Linked auth and pong game --- back/volume/src/auth/42.strategy.ts | 10 +- back/volume/src/pong/pong.gateway.ts | 53 ++++++--- back/volume/src/users/entity/user.entity.ts | 7 +- front/volume/src/components/Pong/Pong.svelte | 116 ++++++++++--------- 4 files changed, 110 insertions(+), 76 deletions(-) diff --git a/back/volume/src/auth/42.strategy.ts b/back/volume/src/auth/42.strategy.ts index 0677f00..5b86d8b 100644 --- a/back/volume/src/auth/42.strategy.ts +++ b/back/volume/src/auth/42.strategy.ts @@ -7,6 +7,7 @@ import { createWriteStream } from 'fs' import { UsersService } from 'src/users/users.service' import { User } from 'src/users/entity/user.entity' +import { randomUUID } from 'crypto' @Injectable() export class FtStrategy extends PassportStrategy(Strategy, '42') { @@ -28,7 +29,7 @@ export class FtStrategy extends PassportStrategy(Strategy, '42') { refreshToken: string, profile: Profile, cb: VerifyCallback - ): Promise { + ): Promise { request.session.accessToken = accessToken console.log('accessToken', accessToken, 'refreshToken', refreshToken) const ftId = profile.id as number @@ -36,10 +37,11 @@ export class FtStrategy extends PassportStrategy(Strategy, '42') { if ((await this.usersService.findUser(ftId)) === null) { const newUser = new User() newUser.ftId = profile.id as number + newUser.socketKey = randomUUID() newUser.username = profile.username as string - newUser.avatar = ftId + '.jpg' - this.usersService.create(newUser) - const file = createWriteStream('avatars/' + ftId + '.jpg') + newUser.avatar = `${ftId}.jpg` + void this.usersService.create(newUser) + const file = createWriteStream(`avatars/${ftId}.jpg`) get(profile._json.image.versions.small, function (response) { response.pipe(file) }) diff --git a/back/volume/src/pong/pong.gateway.ts b/back/volume/src/pong/pong.gateway.ts index ce38752..7b93299 100644 --- a/back/volume/src/pong/pong.gateway.ts +++ b/back/volume/src/pong/pong.gateway.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable, UsePipes, ValidationPipe } from '@nestjs/common' +import { UsePipes, ValidationPipe } from '@nestjs/common' import { type WebSocket } from 'ws' import { ConnectedSocket, @@ -21,6 +21,7 @@ import { StringDtoValidated } from './dtos/StringDtoValidated' import { MatchmakingQueue } from './game/MatchmakingQueue' import { MatchmakingDtoValidated } from './dtos/MatchmakingDtoValidated' import { PongService } from './pong.service' +import { UsersService } from 'src/users/users.service' interface WebSocketWithId extends WebSocket { id: string @@ -28,13 +29,24 @@ interface WebSocketWithId extends WebSocket { @WebSocketGateway() export class PongGateway implements OnGatewayConnection, OnGatewayDisconnect { - constructor (private readonly pongService: PongService) {} + constructor ( + private readonly pongService: PongService, + private readonly usersService: UsersService + ) {} private readonly games: Games = new Games(this.pongService) private readonly socketToPlayerName = new Map() private readonly matchmakingQueue = new MatchmakingQueue(this.games) - handleConnection (client: WebSocketWithId): void { + playerIsRegistered (name: string): boolean { + return Array.from(this.socketToPlayerName.values()).includes(name) + } + + @UsePipes(new ValidationPipe({ whitelist: true })) + handleConnection ( + @ConnectedSocket() + client: WebSocketWithId + ): void { const uuid = randomUUID() client.id = uuid } @@ -45,24 +57,39 @@ export class PongGateway implements OnGatewayConnection, OnGatewayDisconnect { ): void { const name: string | undefined = this.socketToPlayerName.get(client) const game: Game | null = this.games.playerGame(name) - if (game !== null) { - console.log('Disconnected ', this.socketToPlayerName.get(client)) - if (game.isPlaying()) { - game.stop() - } + console.log(game) + console.log(game?.isPlaying()) + if (game !== null && game.isPlaying()) { + void game.stop() + } + if (name !== undefined) { this.socketToPlayerName.delete(client) + console.log('Disconnected ', this.socketToPlayerName.get(client)) } } @UsePipes(new ValidationPipe({ whitelist: true })) @SubscribeMessage(GAME_EVENTS.REGISTER_PLAYER) - registerPlayer ( + async registerPlayer ( @ConnectedSocket() client: WebSocketWithId, - @MessageBody() playerName: StringDtoValidated - ): { event: string, data: StringDtoValidated } { - this.socketToPlayerName.set(client, playerName.value) - return { event: GAME_EVENTS.REGISTER_PLAYER, data: playerName } + @MessageBody('playerName') playerName: StringDtoValidated, + @MessageBody('socketKey') socketKey: StringDtoValidated + ): Promise<{ event: string, data: boolean }> { + let succeeded: boolean = false + const user = await this.usersService.findUserByName(playerName.value) + if ( + user !== null && + user.socketKey === socketKey.value && + !this.playerIsRegistered(playerName.value) + ) { + this.socketToPlayerName.set(client, playerName.value) + succeeded = true + console.log('Registered player', playerName.value) + } else { + console.log('Failed to register player', playerName.value) + } + return { event: GAME_EVENTS.REGISTER_PLAYER, data: succeeded } } @SubscribeMessage(GAME_EVENTS.GET_GAME_INFO) diff --git a/back/volume/src/users/entity/user.entity.ts b/back/volume/src/users/entity/user.entity.ts index 384b43d..2316af9 100644 --- a/back/volume/src/users/entity/user.entity.ts +++ b/back/volume/src/users/entity/user.entity.ts @@ -19,6 +19,9 @@ export class User { @Column({ unique: true }) ftId: number + @Column({ unique: true }) + socketKey: string + @Column({ unique: true }) username: string @@ -37,10 +40,10 @@ export class User { @Column({ default: 0 }) matchs: number - @Column({ default: 0}) + @Column({ default: 0 }) rank: number - @Column({ default: 0 , type: "double precision"}) + @Column({ default: 0, type: 'double precision' }) winrate: number @ManyToMany(() => Result, (result: Result) => result.players) diff --git a/front/volume/src/components/Pong/Pong.svelte b/front/volume/src/components/Pong/Pong.svelte index 4ffcb09..9a0bb57 100644 --- a/front/volume/src/components/Pong/Pong.svelte +++ b/front/volume/src/components/Pong/Pong.svelte @@ -8,8 +8,8 @@ import SpectateFriend from "./SpectateFriend.svelte"; import Matchmaking from "./Matchmaking.svelte"; import type { MatchmakingDto } from "./dtos/MatchmakingDto"; - import { store } from "../../Auth"; - import ColorPicker from "./ColorPicker.svelte"; + import { getUser, store } from "../../Auth"; + import ColorPicker from "./ColorPicker.svelte"; const SERVER_URL = `ws://${import.meta.env.VITE_HOST}:${ import.meta.env.VITE_BACK_PORT @@ -22,6 +22,7 @@ let gameCanvas: HTMLCanvasElement; let connected: boolean = false; let loggedIn: boolean = false; + let failedLogIn: boolean = false; let socket: WebSocket; let username: string = $store.username; let elementsColor: string = "#FFFFFF"; @@ -52,11 +53,13 @@ } else gamePlaying = false; } } else if (event == GAME_EVENTS.REGISTER_PLAYER) { - if (data.value == username) { + if (data) { loggedIn = true; setInterval(() => { updateGameInfo(); }, 1000); + } else { + failedLogIn = true; } } else if (event == GAME_EVENTS.CREATE_GAME) { if (data) gamePlaying = true; @@ -76,6 +79,7 @@ } }; socket.onopen = () => { + void logIn(); connected = true; }; socket.onclose = () => { @@ -88,8 +92,13 @@ socket.send(formatWebsocketData(GAME_EVENTS.GET_GAME_INFO)); } - function logIn() { - const data: StringDto = { value: username }; + async function logIn() { + await getUser(); + const socketKey = $store.socketKey; + const data: { playerName: StringDto; socketKey: StringDto } = { + playerName: { value: username }, + socketKey: { value: socketKey }, + }; socket.send(formatWebsocketData(GAME_EVENTS.REGISTER_PLAYER, data)); } @@ -105,63 +114,56 @@ $: { if (game !== undefined) { - game.updateColors(elementsColor, backgroundColor) + game.updateColors(elementsColor, backgroundColor); } } -
- {#if !loggedIn} - Log in: - - -
- {/if} - + {#if matchmaking} +
+ +
+ + {:else if createMatchWindow} +
(createMatchWindow = false)} + on:keydown={() => (createMatchWindow = false)} + > + +
+ {:else if spectateWindow} +
(spectateWindow = false)} + on:keydown={() => (spectateWindow = false)} + > + +
+ {/if} + {:else if !connected} + Connecting to game server... + {:else if failedLogIn} + Failed to log in to game server. Do you have multiple pages open at the same + time? If yes, please close them and try again. + {:else if !loggedIn} + Logging in to game server... + {/if} +