À propos de ce tutoriel
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 Mapnew Map<Player["id"], Map<GameId, SocketStream>>
- Le
GameRepository
se chargera de sauvegarder les différentes parties des joueursnew 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)
})
})
})