diff --git a/documents/docs/networking/commands/protocol-document.md b/documents/docs/networking/commands/protocol-document.md index 33b0220..86da90d 100644 --- a/documents/docs/networking/commands/protocol-document.md +++ b/documents/docs/networking/commands/protocol-document.md @@ -50,6 +50,12 @@ This document describes the protocol for client-server communication in our appl - [Error Response](#error-response-6) - [Example Request](#example-request-4) - [Example Response](#example-response-4) + - [GET_LOBBY_LIST command](#get_lobby_list-command) + - [Required pre-execution checks](#required-pre-execution-checks) + - [Request Parameters](#request-parameters) + - [Success Response](#success-response) + - [Example Request](#example-request) + - [Example Response](#example-response) - [SEND_MESSAGE command](#send_message-command) - [Required pre-execution checks](#required-pre-execution-checks) - [Request Parameters](#request-parameters) @@ -535,6 +541,60 @@ END END ``` +## GET_LOBBY_LIST command + +The `GET_LOBBY_LIST` command requests the server to return a list of currently available lobbies with basic metadata. + +### Required pre-execution checks +None. + +### Request Parameters +No parameters. + +### Implementation notes + +- Parser: `GetLobbyListParser` — creates `GetLobbyListRequest` (no parameters). +- Handler: `GetLobbyListHandler` — queries `LobbyManager#getAllLobbies()` and returns `GetLobbyListResponse`. +- Response: `GetLobbyListResponse` — builds a `LOBBIES` collection with repeated `LOBBY` blocks containing `ID`, `NAME`, `PLAYER_COUNT`. + +### Success Response + +The response contains a `LOBBIES` collection with nested `LOBBY` entries. + +Example response structure: + +``` ++OK + LOBBIES + LOBBY + ID=1 + NAME=Room 1 + PLAYER_COUNT=2 + END + LOBBY + ID=2 + NAME=Room 2 + PLAYER_COUNT=3 + END + END +END +``` + +### Example Request + +``` +GET_LOBBY_LIST +``` + +### Example Response (error) + +``` +-ERR + CODE=NO_LOBBIES_AVAILABLE + MESSAGE=No lobbies available +END +``` + ## GET_LOBBY_STATUS command The `GET_LOBBY_STATUS` command requests the server to return the current state of a lobby, including the list of players and their ready state. diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java index 694b81a..c00aa84 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java @@ -140,7 +140,21 @@ public class ServerApp { commandRouter.register( ListUsersRequest.class, new ListUsersHandler(responseDispatcher, userRegistry)); - // GET_LOBBY_STATUS registration + // GET_LOBBY_LIST registration + parserDispatcher.register( + "GET_LOBBY_LIST", + new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.get_lobby_list + .GetLobbyListParser()); + commandRouter.register( + ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.get_lobby_list + .GetLobbyListRequest.class, + (ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandHandler< + ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby + .get_lobby_list.GetLobbyListRequest>) + new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.get_lobby_list + .GetLobbyListHandler(responseDispatcher, lobbyManager)); + + // GET_LOBBY_STATUS registration parserDispatcher.register( "GET_LOBBY_STATUS", new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.get_lobby_status @@ -155,6 +169,7 @@ public class ServerApp { .get_lobby_status.GetLobbyStatusHandler( responseDispatcher, lobbyManager, userRegistry)); + // JOIN_LOBBY registration parserDispatcher.register( "JOIN_LOBBY", diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_list/GetLobbyListHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_list/GetLobbyListHandler.java new file mode 100644 index 0000000..49e49d8 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_list/GetLobbyListHandler.java @@ -0,0 +1,28 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.get_lobby_list; + +import ch.unibas.dmi.dbis.cs108.casono.server.domain.lobby.LobbyManager; +import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandHandler; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher; +import java.util.Collection; + +/** + * Handler for the `GET_LOBBY_LIST` command. + * + *

Queries the {@link LobbyManager} for all available lobbies and dispatches a {@link + * GetLobbyListResponse} containing basic metadata for each lobby (`ID`, `NAME`, `PLAYER_COUNT`). + */ +public class GetLobbyListHandler extends CommandHandler { + private final LobbyManager lobbyManager; + + public GetLobbyListHandler(ResponseDispatcher responseDispatcher, LobbyManager lobbyManager) { + super(responseDispatcher); + this.lobbyManager = lobbyManager; + } + + @Override + public void execute(GetLobbyListRequest request) { + Collection l = + lobbyManager.getAllLobbies(); + responseDispatcher.dispatch(new GetLobbyListResponse(request.getContext(), l)); + } +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_list/GetLobbyListParser.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_list/GetLobbyListParser.java new file mode 100644 index 0000000..e6dce38 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_list/GetLobbyListParser.java @@ -0,0 +1,17 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.get_lobby_list; + +import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.CommandParser; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.PrimitiveRequest; + +/** + * Parser for the `GET_LOBBY_LIST` command. + * + *

Parses the incoming primitive request and produces a {@link GetLobbyListRequest}. This command + * takes no parameters. + */ +public class GetLobbyListParser implements CommandParser { + @Override + public GetLobbyListRequest parse(PrimitiveRequest primitiveRequest) { + return new GetLobbyListRequest(primitiveRequest.context()); + } +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_list/GetLobbyListRequest.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_list/GetLobbyListRequest.java new file mode 100644 index 0000000..ec41e1d --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_list/GetLobbyListRequest.java @@ -0,0 +1,15 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.get_lobby_list; + +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext; + +/** + * Request object for the `GET_LOBBY_LIST` command. + * + *

Contains only the request context; this command does not require parameters. + */ +public class GetLobbyListRequest extends Request { + public GetLobbyListRequest(RequestContext context) { + super(context); + } +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_list/GetLobbyListResponse.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_list/GetLobbyListResponse.java new file mode 100644 index 0000000..3737189 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_list/GetLobbyListResponse.java @@ -0,0 +1,37 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.get_lobby_list; + +import ch.unibas.dmi.dbis.cs108.casono.server.domain.lobby.Lobby; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.SuccessResponse; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.ResponseBody; +import java.util.Collection; + +/** + * Success response for `GET_LOBBY_LIST`. + * + *

Builds a `LOBBIES` collection with repeated `LOBBY` blocks containing `ID`, `NAME` and + * `PLAYER_COUNT`. + */ +public class GetLobbyListResponse extends SuccessResponse { + public GetLobbyListResponse(RequestContext context, Collection lobbies) { + super( + context, + ResponseBody.builder() + .block( + "LOBBIES", + lobbies_block -> { + for (Lobby lobby : lobbies) { + lobbies_block.block( + "LOBBY", + lb -> { + lb.param("ID", lobby.getId().value()); + lb.param("NAME", lobby.getName()); + lb.param( + "PLAYER_COUNT", + lobby.getPlayerNames().size()); + }); + } + }) + .build()); + } +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_status/GetLobbyStatusHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_status/GetLobbyStatusHandler.java index 6ff4379..5e04fcd 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_status/GetLobbyStatusHandler.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_status/GetLobbyStatusHandler.java @@ -8,14 +8,7 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.ErrorRes import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher; import java.util.Optional; -/** - * Handler for the `GET_LOBBY_STATUS` command. - * - *

Resolves the target lobby either by the optional `ID` parameter or by `USERNAME`. If both are - * omitted the handler requires the session to be associated with a logged-in user (see the inline - * pre-execution check). On success a {@link GetLobbyStatusResponse} is dispatched, otherwise an - * {@link ErrorResponse} with code `LOBBY_NOT_FOUND` is sent. - */ +/** Handler for GET_LOBBY_STATUS: returns lobby details and player list. */ public class GetLobbyStatusHandler extends CommandHandler { private final LobbyManager lobbyManager; private final UserRegistry userRegistry; @@ -53,22 +46,10 @@ public class GetLobbyStatusHandler extends CommandHandler @Override public void execute(GetLobbyStatusRequest request) { - // Resolve username from request or session when no explicit ID/USERNAME - // provided - String targetUsername = request.getUsername(); - if (targetUsername == null) { - var maybeUser = userRegistry.getBySessionId(request.getSessionId()); - if (maybeUser.isPresent()) { - targetUsername = maybeUser.get().getName(); - } - } - var lobby = (request.getId() != null) ? lobbyManager.getLobby(LobbyId.of(request.getId())) - : (targetUsername != null - ? lobbyManager.getLobbyByUsername(targetUsername) - : null); + : lobbyManager.getLobbyByUsername(request.getUsername()); if (lobby == null) { responseDispatcher.dispatch( diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_status/GetLobbyStatusParser.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_status/GetLobbyStatusParser.java index 1f38f2a..e6aec4c 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_status/GetLobbyStatusParser.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_status/GetLobbyStatusParser.java @@ -5,21 +5,6 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Primitive import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.accessor.RequestParameterAccessor; public class GetLobbyStatusParser implements CommandParser { - /** - * Parse the incoming primitive request into a {@link GetLobbyStatusRequest}. - * - *

Supported optional parameters: - * - *

- * - * If both are omitted the handler may require a logged-in session. - * - * @param primitiveRequest raw request containing parameters and context - * @return parsed {@link GetLobbyStatusRequest} - */ @Override public GetLobbyStatusRequest parse(PrimitiveRequest primitiveRequest) { RequestParameterAccessor accessor = diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_status/GetLobbyStatusRequest.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_status/GetLobbyStatusRequest.java index 6baa338..5d73882 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_status/GetLobbyStatusRequest.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_status/GetLobbyStatusRequest.java @@ -7,25 +7,16 @@ public class GetLobbyStatusRequest extends Request { private final Integer id; private final String username; - /** - * Create a new GetLobbyStatusRequest. - * - * @param context request context (session id, source, etc.) - * @param id optional numeric lobby id to query, or null - * @param username optional username to query the lobby for, or null - */ public GetLobbyStatusRequest(RequestContext context, Integer id, String username) { super(context); this.id = id; this.username = username; } - /** Returns the optional lobby id. */ public Integer getId() { return id; } - /** Returns the optional username. */ public String getUsername() { return username; } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_status/GetLobbyStatusResponse.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_status/GetLobbyStatusResponse.java index 043eb3d..94bc690 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_status/GetLobbyStatusResponse.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/get_lobby_status/GetLobbyStatusResponse.java @@ -5,19 +5,8 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestCo import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.SuccessResponse; import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.ResponseBody; -/** - * Success response for `GET_LOBBY_STATUS`. - * - *

Builds a response with a single `LOBBY` block containing `ID`, `NAME` and a nested `PLAYERS` - * collection with repeated `PLAYER` blocks (`USERNAME`, `READY`). - */ +/** Response with lobby player listing and simple READY placeholders. */ public class GetLobbyStatusResponse extends SuccessResponse { - /** - * Create a new response for the provided {@link Lobby}. - * - * @param context request context to use for the response - * @param lobby lobby domain object containing id, name and players - */ public GetLobbyStatusResponse(RequestContext context, Lobby lobby) { super( context,