Merge branch 'feat/96-add-getlobbystatus-command-on-server-side' into 'main'

Feat/96 add getlobbystatus command on server side

Closes #96

See merge request cs108-fs26/Gruppe-13!103
This commit was merged in pull request #259.
This commit is contained in:
Jona Walpert
2026-04-11 18:35:56 +00:00
5 changed files with 201 additions and 0 deletions
@@ -508,6 +508,67 @@ END
### Example Response (error)
```
-ERR
CODE=LOBBY_NOT_FOUND
MESSAGE=Lobby not found
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.
### Required pre-execution checks
None.
### Request Parameters
| Parameter Name | Type | Optional | Description |
| :------------- | :--- | :------: | :---------- |
| `ID` | `int` | no | Numeric id of the target lobby |
### Implementation notes
- Parser: `GetLobbyStatusParser` — reads the `ID` parameter and builds `GetLobbyStatusRequest`.
- Handler: `GetLobbyStatusHandler` — queries `LobbyManager` for the lobby and builds a `GetLobbyStatusResponse` containing player entries.
### Success Response
The response contains a `LOBBY` collection with nested `PLAYERS` and one or more `PLAYER` entries. Each `PLAYER` entry contains `USERNAME` and `READY` fields.
Example response structure:
```
+OK
LOBBY
ID=1
PLAYERS
PLAYER
USERNAME=Lars_001
READY=false
END
PLAYER
USERNAME=Anna
READY=true
END
END
END
END
```
### Error Response
| Code | Description |
| :--- | :---------- |
| `LOBBY_NOT_FOUND` | The specified lobby id does not exist |
### Example Request
```
GET_LOBBY_STATUS ID=1
```
### Example Response (error)
```
-ERR
CODE=LOBBY_NOT_FOUND
@@ -0,0 +1,62 @@
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.get_lobby_status;
import ch.unibas.dmi.dbis.cs108.casono.server.domain.lobby.LobbyId;
import ch.unibas.dmi.dbis.cs108.casono.server.domain.lobby.LobbyManager;
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserRegistry;
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandHandler;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.ErrorResponse;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher;
import java.util.Optional;
/** Handler for GET_LOBBY_STATUS: returns lobby details and player list. */
public class GetLobbyStatusHandler extends CommandHandler<GetLobbyStatusRequest> {
private final LobbyManager lobbyManager;
private final UserRegistry userRegistry;
public GetLobbyStatusHandler(
ResponseDispatcher responseDispatcher,
LobbyManager lobbyManager,
UserRegistry userRegistry) {
super(responseDispatcher);
this.lobbyManager = lobbyManager;
this.userRegistry = userRegistry;
// Only require logged-in session if the request does not provide an explicit ID
// or USERNAME
addCheck(
request -> {
if (!(request instanceof GetLobbyStatusRequest)) {
return Optional.empty();
}
GetLobbyStatusRequest r = (GetLobbyStatusRequest) request;
if (r.getId() != null || r.getUsername() != null) {
return Optional.empty();
}
var maybeUser = userRegistry.getBySessionId(r.getSessionId());
if (maybeUser.isPresent()) {
return Optional.empty();
}
return Optional.of(
new ErrorResponse(
r.getContext(),
"USER_NOT_LOGGED_IN",
"Request requires an associated logged-in user"));
});
}
@Override
public void execute(GetLobbyStatusRequest request) {
var lobby =
(request.getId() != null)
? lobbyManager.getLobby(LobbyId.of(request.getId()))
: lobbyManager.getLobbyByUsername(request.getUsername());
if (lobby == null) {
responseDispatcher.dispatch(
new ErrorResponse(request.getContext(), "LOBBY_NOT_FOUND", "Lobby not found"));
return;
}
responseDispatcher.dispatch(new GetLobbyStatusResponse(request.getContext(), lobby));
}
}
@@ -0,0 +1,21 @@
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.get_lobby_status;
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.CommandParser;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.PrimitiveRequest;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.accessor.RequestParameterAccessor;
public class GetLobbyStatusParser implements CommandParser<GetLobbyStatusRequest> {
@Override
public GetLobbyStatusRequest parse(PrimitiveRequest primitiveRequest) {
RequestParameterAccessor accessor =
new RequestParameterAccessor(primitiveRequest.parameters());
Integer id = null;
try {
id = accessor.optional("ID", null, Integer::parseInt);
} catch (Exception e) {
// parse error handled elsewhere
}
String username = accessor.optional("USERNAME", null);
return new GetLobbyStatusRequest(primitiveRequest.context(), id, username);
}
}
@@ -0,0 +1,23 @@
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.get_lobby_status;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext;
public class GetLobbyStatusRequest extends Request {
private final Integer id;
private final String username;
public GetLobbyStatusRequest(RequestContext context, Integer id, String username) {
super(context);
this.id = id;
this.username = username;
}
public Integer getId() {
return id;
}
public String getUsername() {
return username;
}
}
@@ -0,0 +1,34 @@
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.get_lobby_status;
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;
/** Response with lobby player listing and simple READY placeholders. */
public class GetLobbyStatusResponse extends SuccessResponse {
public GetLobbyStatusResponse(RequestContext context, Lobby lobby) {
super(
context,
ResponseBody.builder()
.block(
"LOBBY",
lb -> {
lb.param("ID", lobby.getId().value());
lb.param("NAME", lobby.getName());
lb.block(
"PLAYERS",
players -> {
for (String p : lobby.getPlayerNames()) {
players.block(
"PLAYER",
pb -> {
pb.param("USERNAME", p);
pb.param("READY", "false");
});
}
});
})
.build());
}
}