Websocket + Nestjs + this.server.of() 不是函数

问题描述 投票:0回答:1

我正在尝试使用nestjs和websockets创建一个浏览器多人游戏。该游戏的核心是 4 人纸牌游戏,我需要管理状态服务器端,以便 a) 玩家无法在请求中看到彼此的纸牌,b) 如果数据库被破坏,纸牌也不会存储在那里。

目前,我的用户单击一个播放按钮,他们会点击一个静态端点,该端点要么创建一个新的“游戏”,要么将它们添加到一个打开的游戏中。响应发送回一个游戏对象,我用它来连接 websocket

/game/:id

这是我的网络套接字:

@WebSocketGateway({
    namespace: /\/game\/[a-zA-Z0-9]+/, // Dynamically scoped by game ID
    cors: {
        origin: '*',
    },
})
export class GameGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
    @WebSocketServer() server: Server

    constructor(
        protected _jwtService: JwtService,
        protected _gameService: GameService,
    ) {}

    afterInit() {
        console.log('Gateway initialized')
    }

    // Handle player connection
    async handleConnection(@ConnectedSocket() client: Socket) {
        client.nsp.emit('player_connected', {})


    }

    // Handle player disconnection
    async handleDisconnect(@ConnectedSocket() client: Socket) {
        console.log('Disconnection')
    }

    // Emit an event to the specific game namespace when the registration is closed
    @OnEvent('game.registration-closed')
    handleGameReady(game: Game) {
        /**
            * TODO: Begin Setup of game
            */

            this.server.of(`game/${game._id}`).emit('pregame', game)
    }
}

我不想创建一个

/game
websocket 并分成房间,因为我需要为每个游戏都有范围状态,而且我认为它不能很好地管理 1 个对象内的所有房间状态。因此我选择了动态命名的网关
/\/game\/[a-zA-Z0-9]+/,

我的问题在我的服务中,当游戏已满时,我将状态更改为关闭并发出注册已关闭的事件,我们可以进入下一步

if (game.players.length === 4) {
    console.log('Hello')
    this._emitter.emit('game.registration-closed', game)
}

我可以在我的网关中看到此活动

@OnEvent('game.registration-closed')
handleGameReady(game: Game) {
    /**
     * TODO: Begin Setup of game
     */

        this.server.of(`game/${game._id}`).emit('pregame', game)
}

但是,当我尝试向已连接的玩家发送此消息时,我得到

this.server.of is not a function

我没有使用房间,所以我不能使用 this.server.to 或者我得到

this.children.forEach
无法读取未定义的属性

javascript node.js websocket nestjs
1个回答
0
投票

第一个原因,

您的代码的问题可能是您尝试使用动态创建的 this.server.of(...) 向 WebSocket 命名空间 (/game/:id) 发送消息。不管怎样,你遇到了一个错误:“this.server.of不是一个函数”,这个错误主要是因为方法.of()可能无法被识别或者在WebSocket版本中不可用您正在使用的服务器。

另一个可能的原因,

因为当您在事件侦听器内部发出时,this.server的上下文可能无法正确设置,或者也可能不包含动态创建的命名空间。因此,这可能会导致错误this.server.of作为不是一个函数。 为了解决问题,最好使用单个 Web Socket 网关中的房间来管理状态,并避免创建单独的命名空间。

我在下面提到了您想要的每个步骤的正确更正代码,请正确地从这里获取参考,并根据您的进一步要求进行新的更改。

首先创建一个WebSocket:


    import {
        WebSocketGateway,
        WebSocketServer,
        OnGatewayInit,
        OnGatewayConnection,
        OnGatewayDisconnect,
        ConnectedSocket,
        SubscribeMessage,
        MessageBody,
    } from '@nestjs/websockets';
    import { Server, Socket } from 'socket.io';
    import { GameService } from './game.service';
    import { OnEvent } from '@nestjs/event-emitter';
    
    @WebSocketGateway({
        namespace: '/game',
        cors: {
            origin: '*',
        },
    })
    export class GameGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
        @WebSocketServer() server: Server;
    
        constructor(private _gameService: GameService) {}
    
        afterInit() {
            console.log('Gateway initialized');
        }
    
        async handleConnection(@ConnectedSocket() client: Socket) {
            console.log('Player connected:', client.id);
        }
    
        async handleDisconnect(@ConnectedSocket() client: Socket) {
            console.log('Player disconnected:', client.id);
        }
    
        @SubscribeMessage('join_game')
        async handleJoinGame(@ConnectedSocket() client: Socket, @MessageBody() gameId: string) {
            console.log(`Player ${client.id} joining game ${gameId}`);
            client.join(gameId);
            this._gameService.addPlayerToGame(gameId, client.id);
        }
    
        @OnEvent('game.registration-closed')
        handleGameReady(game: any) {
            console.log(`Game ${game._id} registration closed. Emitting pregame.`);
            this.server.to(game._id).emit('pregame', game);
        }
    }

现在实施您的游戏服务,例如:


        import { Injectable } from '@nestjs/common';
        import { EventEmitter2 } from '@nestjs/event-emitter';
        
        @Injectable()
        export class GameService {
            private games: Map<string, any> = new Map();
        
            constructor(private _emitter: EventEmitter2) {}
        
            createGame(gameId: string) {
                if (!this.games.has(gameId)) {
                    this.games.set(gameId, {
                        id: gameId,
                        players: [],
                        status: 'open',
                    });
                    console.log(`Game ${gameId} created.`);
                }
            }
            addPlayerToGame(gameId: string, playerId: string) {
                const game = this.games.get(gameId);
                if (game && game.status === 'open') {
                    game.players.push(playerId);
                    console.log(`Player ${playerId} added to game ${gameId}.`);
                    if (game.players.length === 4) {
                        game.status = 'closed';
                        this._emitter.emit('game.registration-closed', game);
                        console.log(`Game ${gameId} registration closed.`);
                    }
                }
            }
        
            getGame(gameId: string) {
                return this.games.get(gameId);
            }
        
            removePlayerFromGame(gameId: string, playerId: string) {
                const game = this.games.get(gameId);
                if (game) {
                    game.players = game.players.filter(id => id !== playerId);
                    console.log(`Player ${playerId} removed from game ${gameId}.`);
                }
            }
        }
    

我还会建议您添加一个游戏控制器来管理游戏创建和新玩家的添加。如果您愿意,代码将类似于:


    import { Controller, Post, Body } from '@nestjs/common';
    import { GameService } from './game.service';
    
    @Controller('game')
    export class GameController {
        constructor(private readonly gameService: GameService) {}
    
        @Post('create')
        createGame(@Body('gameId') gameId: string) {
            this.gameService.createGame(gameId);
            return { message: `Game ${gameId} created.` };
        }
    
        @Post('add-player')
        addPlayerToGame(@Body('gameId') gameId: string, @Body('playerId') playerId: string) {
            this.gameService.addPlayerToGame(gameId, playerId);
            return { message: `Player ${playerId} added to game ${gameId}.` };
        }
    }

正确使用这些代码,它集成了您的所有功能并解决疑问,如果您遇到任何困难,请告诉我。

© www.soinside.com 2019 - 2024. All rights reserved.