Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connection sequence #17

Open
4 of 8 tasks
elementbound opened this issue Nov 11, 2024 · 3 comments
Open
4 of 8 tasks

Connection sequence #17

elementbound opened this issue Nov 11, 2024 · 3 comments
Assignees
Labels
epic Tracks multiple features / issues

Comments

@elementbound
Copy link
Contributor

elementbound commented Nov 11, 2024

Goals

Players can open the game view on their main screen. Upon loading, a new game session is created. The view displays a QR code that can be scanned, to join the game. A link is also provided.

The QR code / link brings players to an URL. Upon joining, the player joins the game session. The first joiner becomes the owner of the session.

All players can confirm their readiness. Once all players confirm, the game starts. Once the game has started, no more players can join.

The game session is thrown away when all players leave.

Out of scope

  • Reconnection, i.e. what if someone temporarily disconnects
    • Server can hand out reconnect tokens
  • State persistence

Breakdown

Depends on #13

Notes

@elementbound elementbound added epic Tracks multiple features / issues draft Not final labels Nov 11, 2024
@elementbound elementbound self-assigned this Nov 11, 2024
@elementbound
Copy link
Contributor Author

I'll add a design doc so we can discuss the overall flow before doing the breakdown.

elementbound added a commit that referenced this issue Nov 24, 2024
@elementbound elementbound removed the draft Not final label Nov 24, 2024
@elementbound elementbound mentioned this issue Nov 30, 2024
7 tasks
@elementbound
Copy link
Contributor Author

Modules would be based on domains. Participants and sessions consist a single domain, since participants only exist in context of a session.

Modules consist of DAOs for data management, services implement business logic, and controllers expose these to external clients.

@elementbound
Copy link
Contributor Author

elementbound commented Dec 28, 2024

Notes on authentication

To simplify identity management, there will be only one endpoint for players: /play/:id. Having separate endpoints ( /play/:id/setup, /play/:id/game, etc. ) would unnecessarily complicate authentication, and would also mean that players could open invalid addresses. For example, open /play/:id/game, even though the session is still in the lobby, meaning the frontend would need to validate also the game state and redirect if needed.

Having a single endpoint means that players can't open games in the wrong stage, and the frontend can render the appropriate UI for the current stage.


When opening a game session ( at /play/:id ), the following happens:

  1. FE submits an HTTP request to join session by ID
  2. BE creates participant and adds it to the session
  3. FE receives session data, current participant, and auth token
  4. Session ID and auth token is saved to local storage
  5. FE connects over WS with auth token
  6. BE associates connection with participant

If for whatever reason the page is reloaded:

  1. FE checks Local Storage for stored Session ID and auth token
  2. Saved Session ID matches the one opened
  3. FE submits HTTP request to resume session by ID, with auth token
  4. FE receives session data, current participant, and auth token
  5. Session ID and auth token is saved to local storage
  6. FE connects over WS with auth token
  7. BE associates connection with participant

This logic can be stashed away in a dedicated component, possibly called DungeonAuthenticator. This is then used by DungeonClient, that would act similarly to a facade in this regard.

This also means that DungeonClient doesn't always have an active connection. Instead, extra calls ( join(session), close() ) would be needed to manage connections as appropriate.

type DungeonAuthResult = {
  session: Session;
  localParticipantId: string;
  socket: Socket;
};

class DungeonAuthenticator {
  public async join(sessionId: string): Promise<DungeonAuthResult> {
    const currentSessionId = localStorage.getItem('sessionId');
    const participant = localStorage.getItem('participant') as Participant;
    const authToken = localStorage.getItem('authToken');

    if (currentSessionId == sessionId && authToken) {
      // resume
      // Grab participant data with auth token over HTTP
      // Connect over WS
    } else {
      // join
      // Request participant over HTTP
      // Connect over WS
    }

    // Save auth token to LocalStorage
  }
}

The single play endpoint ( /play/:id ) would conditionally render the right component based on current lobby status. It would subscribe to lobby status changes and force re-render with the appropriate components.

One possible way to force re-render is to use a dummy state:

function useForce(): () => void {
  const [_, setEmpty] = useState<object>({});

  return () => setEmpty({});
}

export function PlayView(): JSX.Element {
  const sessionId = useParams().id;
  const dungeonClient = app.items.dungeonClient;
  const rerender = useForce();
  
  useEffect(() => {
    dungeonClient.join(sessionId) // pls throw on fail
    dungeonClient.onSessionStatus.add(() => rerender())
  }, []);

  return <>
    { dungeonClient.session.status == SessionStatus.IN_LOBBY && <ParticipantSetupView />}
  </>;
}

Note that when a client disconnects during lobby, the server can simply throw away that participant. When the client connects again, a new participant is created for it.

Once the session is active and the game has started, participants are retained, even if the WebSocket connection is lost. Clients can resume using their auth token. Simply joining the session is disabled.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
epic Tracks multiple features / issues
Projects
None yet
Development

No branches or pull requests

1 participant