Connection Sequence Design

As described in #17.

Overview

The feature can be broken down to the following major points:

  1. Create a session
  2. Participants join the session
  3. Participant setup
  4. Session start

Session management

Host ParticipantHost ParticipantMain ScreenMain ScreenServerServerOpen in browserRequest game sessionRespond with game sessionRedirect to session pageDisplay instructions to join

When the host participant opens the game on their main screen, the application creates a new game session and displays instructions on how to join.


Sessions are objects that have an ID and a list of participants that are currently in the session.

Session IDs are randomly generated, to ensure all IDs are unique. This property can be useful for scaling horizontally as well - instances can generate IDs for a shared storage independently of each other.

Participants in this case represent the user as part of the session. Participants do not exist outside of game sessions.

Participants also have a randomly generated ID, and in addition, a name and a readiness flag.

For convenience, participants may have globally unique IDs, but they must always belong to a game session.

Displays

Aside from participants, displays may also connect to game sessions, e.g. the main screen or TV the host is using. Displays don't interact with the game, they just present its state to users.

Displays are participants themselves, marked with an is_display flag.

Joining the session

When a participant opens the session - i.e. opens its link in a browser -, they connect to the game through WebSocket. This will be used to send actions to the server, and to receive state updates from it.

Initially, the server creates a Participant object, and sends its data to the browser. The browser can then use this data to authenticate as the participant itself.

On the server, the specified Session is validated ( i.e. does it exist? ), and if so, a Participant is created and added to the list of players in the Session. This event is broadcast to the Participants already in the session.

Data storage

For starters, we can keep Session and Participant objects in memory, in a simple dictionary and do lookups based on ID.

Later we can move on to keeping these objects in an actual database, so game data is not tied to a single running instance, enabling horizontal scaling.

WebSocket message routing

On the backend, nest.js has built-in support for WebSockets, through a socket.io adapter - see nest.js WS docs.

On the frontend, socket.io provides a high-level API similar to node's EventEmitter.

Participant setup

After successfully joining, participants are presented with the player setup screen. For the scope of this epic, participants can edit their own names and toggle their readiness.

NameParticipant nameReadyParticipant setup

During this phase, on the main screen, all Participants and their state is displayed next to the join instructions. This is updated in real-time, as participants join or update their settings.

https://dumber.dungeons/game/XXXXJoinNameReady?FooBarQuixBazParticipants

Participant actions ( changing name or readiness ) are submitted through WebSocket.

Authentication

  • WebSocket object
    • Participants can be associated with a specific WebSocket connection object
    • pros: Simple?
    • cons: Not scalable, Potentially hacky
  • Authentication tokens
    • Aside from IDs, Participant objects also get an Auth token
    • This auth token is only handed out to the Participant actor during creation
    • The auth token can be used to perform actions on the Participant object
    • pros: Relatively simple, Scalable
    • cons: Extra network traffic

Verdict: Participants are associated with WebSocket connections. An initial auth token is sent to the participant, but is not needed to be sent with every message.

Authentication tokens are generated and set as http-only cookies on join. These can be used on the server to determine if it's an existing participant reconnecting to a game or a new one.

Note that reconnecting is out of scope for now, authentication tokens will be useful later in development.

Session start

During every readiness change, the server checks if all Participants are ready in the affected session. If so, it broadcasts a session start event.

Clients lock the Participant settings and display a message that the session has started.

Data model

session   id81DCIQL9NqPWis_in_progressfalseparticipants            nameFooid841GIhHUw-iKis_readyfalseis_displayfalseauth_tokenWMAou-ECTaxyl5IbLlIxLp8lnX_yyQ9ZnameBaridteeDUHGoUTwyis_readytrueis_displayfalseauth_token_pQUp8F34t_HBjmp1jI6sRbOLSpv7AcAnameFoo's TVidacyLzh_Lab-Fis_readyfalseis_displaytrueauth_tokenGu6A4KRqcIQXi8t5Xuyh6JP2YzqPFLSx