WebSocket côté serveur

Contenu destiné aux membres premiums

Devenir premium

Description Sommaire

Dans ce chapitre nous allons mettre en place la logique des WebSockets côté serveur pour gérer la synchronisation du jeu entre les joueurs. Pour cela nous allons nous reposer sur le package @fastify/websocket qui permettra une intégration facile avec ce que l'on a déjà fait.

Pour gérer nos parties et nos connexions nous allons utiliser un système de repository pour abstraire la logique de récupération et de création de partie.

  • Le ConnectionRepository mémorisera nos connexion en les organisant par id joueurs à l'aide d'une Map new Map<Player["id"], Map<GameId, SocketStream>>
  • Le GameRepository se chargera de sauvegarder les différentes parties des joueurs new Map<GameId, Machine>

Une fois ces 2 classes crées, elles pourront facilement être utilisées lors des connexions.

const connections = new ConnectionRepository()
const games = new GameRepository(connections)

fastify.register(FastifyWebsocket)
fastify.register(async (f) => {
  f.get('/ws', {websocket: true}, (connection, req) => {
    const query = req.query as Record<string, string>
    const playerId = query.id ?? ''
    const signature = query.signature ?? ''
    const playerName = query.name || 'John Doe'
    const gameId = query.gameId

    if (!gameId) {
      connection.end()
      f.log.error('Pas de gameId')
      return;
    }

    if (!verify(playerId, signature)) {
      f.log.error(`Erreur d'authentification`)
      connection.socket.send(JSON.stringify({
        type: 'error', code: ServerErrors.AuthError
      }))
      return;
    }

    const game = games.find(gameId) ?? games.create(gameId)
    connections.persist(playerId, gameId, connection)
    game.send(GameModel.events.join(playerId, playerName))
    publishMachine(game.state, connection)

    connection.socket.on('message', (rawMessage) => {
      const message = JSON.parse(rawMessage.toLocaleString())
      if (message.type === 'gameUpdate') {
        game.send(message.event)
      }
    })

    connection.socket.on('close', () => {
      connections.remove(playerId, gameId)
      game.send(GameModel.events.leave(playerId))
      games.clean(gameId)
    })
  })
})
Publié
Technologies utilisées
Auteur :
Grafikart
Partager