Feat/94 add get lobby list command on server side #261
@@ -50,6 +50,12 @@ This document describes the protocol for client-server communication in our appl
|
|||||||
- [Error Response](#error-response-6)
|
- [Error Response](#error-response-6)
|
||||||
- [Example Request](#example-request-4)
|
- [Example Request](#example-request-4)
|
||||||
- [Example Response](#example-response-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)
|
- [SEND_MESSAGE command](#send_message-command)
|
||||||
- [Required pre-execution checks](#required-pre-execution-checks)
|
- [Required pre-execution checks](#required-pre-execution-checks)
|
||||||
- [Request Parameters](#request-parameters)
|
- [Request Parameters](#request-parameters)
|
||||||
@@ -535,6 +541,60 @@ END
|
|||||||
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
|
## 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.
|
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.
|
||||||
|
|||||||
@@ -140,6 +140,20 @@ public class ServerApp {
|
|||||||
commandRouter.register(
|
commandRouter.register(
|
||||||
ListUsersRequest.class, new ListUsersHandler(responseDispatcher, userRegistry));
|
ListUsersRequest.class, new ListUsersHandler(responseDispatcher, userRegistry));
|
||||||
|
|
||||||
|
// 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
|
// GET_LOBBY_STATUS registration
|
||||||
parserDispatcher.register(
|
parserDispatcher.register(
|
||||||
"GET_LOBBY_STATUS",
|
"GET_LOBBY_STATUS",
|
||||||
@@ -155,6 +169,7 @@ public class ServerApp {
|
|||||||
.get_lobby_status.GetLobbyStatusHandler(
|
.get_lobby_status.GetLobbyStatusHandler(
|
||||||
responseDispatcher, lobbyManager, userRegistry));
|
responseDispatcher, lobbyManager, userRegistry));
|
||||||
|
|
||||||
|
|
||||||
// JOIN_LOBBY registration
|
// JOIN_LOBBY registration
|
||||||
parserDispatcher.register(
|
parserDispatcher.register(
|
||||||
"JOIN_LOBBY",
|
"JOIN_LOBBY",
|
||||||
|
|||||||
+28
@@ -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.
|
||||||
|
*
|
||||||
|
* <p>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<GetLobbyListRequest> {
|
||||||
|
private final LobbyManager lobbyManager;
|
||||||
|
|
||||||
|
public GetLobbyListHandler(ResponseDispatcher responseDispatcher, LobbyManager lobbyManager) {
|
||||||
|
super(responseDispatcher);
|
||||||
|
this.lobbyManager = lobbyManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(GetLobbyListRequest request) {
|
||||||
|
Collection<ch.unibas.dmi.dbis.cs108.casono.server.domain.lobby.Lobby> l =
|
||||||
|
lobbyManager.getAllLobbies();
|
||||||
|
responseDispatcher.dispatch(new GetLobbyListResponse(request.getContext(), l));
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
@@ -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.
|
||||||
|
*
|
||||||
|
* <p>Parses the incoming primitive request and produces a {@link GetLobbyListRequest}. This command
|
||||||
|
* takes no parameters.
|
||||||
|
*/
|
||||||
|
public class GetLobbyListParser implements CommandParser<GetLobbyListRequest> {
|
||||||
|
@Override
|
||||||
|
public GetLobbyListRequest parse(PrimitiveRequest primitiveRequest) {
|
||||||
|
return new GetLobbyListRequest(primitiveRequest.context());
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
@@ -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.
|
||||||
|
*
|
||||||
|
* <p>Contains only the request context; this command does not require parameters.
|
||||||
|
*/
|
||||||
|
public class GetLobbyListRequest extends Request {
|
||||||
|
public GetLobbyListRequest(RequestContext context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
+37
@@ -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`.
|
||||||
|
*
|
||||||
|
* <p>Builds a `LOBBIES` collection with repeated `LOBBY` blocks containing `ID`, `NAME` and
|
||||||
|
* `PLAYER_COUNT`.
|
||||||
|
*/
|
||||||
|
public class GetLobbyListResponse extends SuccessResponse {
|
||||||
|
public GetLobbyListResponse(RequestContext context, Collection<Lobby> 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-21
@@ -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 ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/** Handler for GET_LOBBY_STATUS: returns lobby details and player list. */
|
||||||
* Handler for the `GET_LOBBY_STATUS` command.
|
|
||||||
*
|
|
||||||
* <p>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.
|
|
||||||
*/
|
|
||||||
public class GetLobbyStatusHandler extends CommandHandler<GetLobbyStatusRequest> {
|
public class GetLobbyStatusHandler extends CommandHandler<GetLobbyStatusRequest> {
|
||||||
private final LobbyManager lobbyManager;
|
private final LobbyManager lobbyManager;
|
||||||
private final UserRegistry userRegistry;
|
private final UserRegistry userRegistry;
|
||||||
@@ -53,22 +46,10 @@ public class GetLobbyStatusHandler extends CommandHandler<GetLobbyStatusRequest>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(GetLobbyStatusRequest request) {
|
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 =
|
var lobby =
|
||||||
(request.getId() != null)
|
(request.getId() != null)
|
||||||
? lobbyManager.getLobby(LobbyId.of(request.getId()))
|
? lobbyManager.getLobby(LobbyId.of(request.getId()))
|
||||||
: (targetUsername != null
|
: lobbyManager.getLobbyByUsername(request.getUsername());
|
||||||
? lobbyManager.getLobbyByUsername(targetUsername)
|
|
||||||
: null);
|
|
||||||
|
|
||||||
if (lobby == null) {
|
if (lobby == null) {
|
||||||
responseDispatcher.dispatch(
|
responseDispatcher.dispatch(
|
||||||
|
|||||||
-15
@@ -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;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.accessor.RequestParameterAccessor;
|
||||||
|
|
||||||
public class GetLobbyStatusParser implements CommandParser<GetLobbyStatusRequest> {
|
public class GetLobbyStatusParser implements CommandParser<GetLobbyStatusRequest> {
|
||||||
/**
|
|
||||||
* Parse the incoming primitive request into a {@link GetLobbyStatusRequest}.
|
|
||||||
*
|
|
||||||
* <p>Supported optional parameters:
|
|
||||||
*
|
|
||||||
* <ul>
|
|
||||||
* <li>`ID` (int) — numeric lobby id to query
|
|
||||||
* <li>`USERNAME` (String) — username to lookup the lobby for
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* 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
|
@Override
|
||||||
public GetLobbyStatusRequest parse(PrimitiveRequest primitiveRequest) {
|
public GetLobbyStatusRequest parse(PrimitiveRequest primitiveRequest) {
|
||||||
RequestParameterAccessor accessor =
|
RequestParameterAccessor accessor =
|
||||||
|
|||||||
-9
@@ -7,25 +7,16 @@ public class GetLobbyStatusRequest extends Request {
|
|||||||
private final Integer id;
|
private final Integer id;
|
||||||
private final String username;
|
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) {
|
public GetLobbyStatusRequest(RequestContext context, Integer id, String username) {
|
||||||
super(context);
|
super(context);
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the optional lobby id. */
|
|
||||||
public Integer getId() {
|
public Integer getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the optional username. */
|
|
||||||
public String getUsername() {
|
public String getUsername() {
|
||||||
return username;
|
return username;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-12
@@ -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.SuccessResponse;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.ResponseBody;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.ResponseBody;
|
||||||
|
|
||||||
/**
|
/** Response with lobby player listing and simple READY placeholders. */
|
||||||
* Success response for `GET_LOBBY_STATUS`.
|
|
||||||
*
|
|
||||||
* <p>Builds a response with a single `LOBBY` block containing `ID`, `NAME` and a nested `PLAYERS`
|
|
||||||
* collection with repeated `PLAYER` blocks (`USERNAME`, `READY`).
|
|
||||||
*/
|
|
||||||
public class GetLobbyStatusResponse extends SuccessResponse {
|
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) {
|
public GetLobbyStatusResponse(RequestContext context, Lobby lobby) {
|
||||||
super(
|
super(
|
||||||
context,
|
context,
|
||||||
|
|||||||
Reference in New Issue
Block a user