AlexisTM / fun-together

Rust Pet project acting as a Websocket Proxy to make serverless Jackbox-like game. Used in https://github.com/AlexisTM/just-party

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

WMBP (Websocket multiplayer backend proxy)

This is a pet weekend project to learn & enjoy Rust. Use at your own risk.

Introduction

WMBP is a project is to help more party games to sprout by providing a backend implementation. The base implementation is a one (Game) to many (Clients) connection communication pattern, which is coordinated by the Server, allowing serverless party games.

The Game connects to the Server with a websocket and creates a room. Once the room is created, the Game will receive the Room Code which will be used by Clients to connect.

While the Game has a mandatory communication pattern with the Server, the Clients have a seemingly direct connection to the Game, both in binary and text.

Server example

Usage

  1. Spin this Server, cargo run --release
  2. Game creates a websocket connection to this server to create a game new WebSocket("ws://127.0.0.1:8081/CREATE")
  3. Game sends Prepare with a certain amount of players.
  4. Server sends to Game the Room Code and refuses players if there are too many
  5. Clients creates a websocket connection to this server to create a game new WebSocket("ws://127.0.0.1:8081/ROOM_CODE")
  6. Game sends Start once enough players are connected.
  7. Game sends data to Clients with To and ToStr messages.
  8. Clients sends data to Game with plain text or arraybuffer (for binary format).
  9. Game receives data from Clients with From and FromStr messages.

The game flow of the server

In depth

Game type:

  • http://127.0.0.1:8081/ROOM returns (in text/plain) the game type (started with Prepare)

Then endpoint of the websocket server is defining if you are a Host client (Game) or a Player client by the websocket you created.

  • ws://127.0.0.1:8081/CREATE creates a new game
  • ws://127.0.0.1:8081/ROOM connects to a room

Messages as a Game (host)

The messages for the Game are CBOR encoded with the following format: { "cmd": "snake_case_command", "data1": 1, "data2": "data2"}

For rust users, just take a look at the enum src/comm.rs#Commands. For Javascript users:

  • > Prepare: {"cmd": "prepare", "max_players": 8, "name": "test"} # Prepares the game with the maximum number of clients
  • < PrepareReply: {"cmd": "prepare_reply", "key": "ROOM"} # On successful game creation, provides the ROOM key
  • < PlayerJoined: {"cmd": "player_joined", "player": 12} # A new player joined
  • < PlayerLeft: {"cmd": "player_left", "player": 12} # A player left
  • > Start: {"cmd": "start"} # Starts the game, prevents the clients to connect from this point on.
  • < State: {"cmd": "state", "players": [5,2,3], "max_players": 8, "accept_conns": true} # Provides information about the game, players connected, etc.
  • > Kick: {"cmd": "kick", "player": 5} # Kicks player with id 5 (from the State message)
  • < Stop: {"cmd": "stop"} # Disconnect everybody
  • > To: {"cmd": "to", to: [2], "data": [1,2,3]} # Sends binary data to the user 1
  • > ToStr: {"cmd": "to_str", to: [3, 5], "data": "some string"} # Sends text data to the user 3 and 5
  • < From: {"cmd": "from", "from": 2, "data": [1,2,3]} # Received when user 2 sent binary data
  • < FromStr: {"cmd": "from", "from": 5, "data": "some string"} # Received when user 5 sent string data

Messages as a client

The Client has no specific message. Sending text (Text type for the websocket), the message will be transferred with FromStr to the Game, while sending binary data (such as CBOR encore data or images) will be forwarded with From to the Game.

Whenever Game sends data with To and ToStr, only the data will be forwarded to the client (as everything else would be redundant) as binary or text.

This means the Client has a connection that seems to be directly to the game.

Optional features

tls

In a wim, I quickly made a TLS feature based on rustls, following the example in hyper-rustls. Only later on I understood this was the responsibilty of the cloud service (or nginx or other) in most cases. I have no clue what I am doing 🙈

Deploy

Render.com

Either you try the blueprint (render.yaml provided) or you create a new app with:

  • Set the repo to this one
  • Define the PORT environment variable as 10000, this fasten the spinup of the machines
  • Set the build command as cargo build --release
  • Set the run command as cargo run --release 0.0.0.0:10000

Google Cloud

Create a new project, and, using the PROJECT_ID you created:

gcloud config set project PROJECT_ID
gcloud run deploy

You can Delete your ressources here

About

Rust Pet project acting as a Websocket Proxy to make serverless Jackbox-like game. Used in https://github.com/AlexisTM/just-party


Languages

Language:Rust 45.5%Language:JavaScript 35.5%Language:HTML 17.4%Language:Dockerfile 1.2%Language:CSS 0.4%Language:Shell 0.1%