Feat/ms 4 integration #282

Merged
jona.walpert merged 23 commits from feat/ms-4-integration into main 2026-04-13 03:07:52 +02:00
4 changed files with 230 additions and 193 deletions
Showing only changes of commit 0f8f1bb918 - Show all commits
@@ -24,10 +24,8 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
/** /**
* The ClientService class is responsible for managing the connection to the * The ClientService class is responsible for managing the connection to the server, sending
* server, sending * commands, and receiving responses. It uses a TcpTransport to communicate with the server and an
* commands, and receiving responses. It uses a TcpTransport to communicate with
* the server and an
* ExecutorService to handle asynchronous requests. * ExecutorService to handle asynchronous requests.
*/ */
public class ClientService { public class ClientService {
@@ -41,20 +39,20 @@ public class ClientService {
private final AtomicInteger idGenerator; private final AtomicInteger idGenerator;
private Logger logger; private Logger logger;
private final Map<Integer, ArrayBlockingQueue<ParsedResponse>> pendingResponses = new ConcurrentHashMap<>(); private final Map<Integer, ArrayBlockingQueue<ParsedResponse>> pendingResponses =
private final CopyOnWriteArrayList<Consumer<List<String>>> eventListeners = new CopyOnWriteArrayList<>(); new ConcurrentHashMap<>();
private final CopyOnWriteArrayList<Consumer<List<String>>> eventListeners =
new CopyOnWriteArrayList<>();
private Thread readerThread = null; private Thread readerThread = null;
private final AtomicBoolean running = new AtomicBoolean(false); private final AtomicBoolean running = new AtomicBoolean(false);
private static final int READER_JOIN_TIMEOUT_MS = 500; private static final int READER_JOIN_TIMEOUT_MS = 500;
/** /**
* Constructs a ClientService with the given server IP and port. It establishes * Constructs a ClientService with the given server IP and port. It establishes a socket
* a socket * connection to the server and initializes the TcpTransport and ExecutorService for
* connection to the server and initializes the TcpTransport and ExecutorService
* for
* communication. * communication.
* *
* @param ip The IP address of the server to connect to. * @param ip The IP address of the server to connect to.
* @param port The port number of the server to connect to. * @param port The port number of the server to connect to.
*/ */
public ClientService(String ip, int port) { public ClientService(String ip, int port) {
@@ -79,24 +77,25 @@ public class ClientService {
private void startReaderThread() { private void startReaderThread() {
running.set(true); running.set(true);
readerThread = new Thread( readerThread =
() -> { new Thread(
while (running.get()) { () -> {
try { while (running.get()) {
RawPacket rp = clienttcptransport.read(); try {
processRawPacket(rp); RawPacket rp = clienttcptransport.read();
} catch (IOException e) { processRawPacket(rp);
if (running.get()) { } catch (IOException e) {
logger.warn("IO error on transport reader", e); if (running.get()) {
logger.warn("IO error on transport reader", e);
}
break;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
} }
break; },
} catch (InterruptedException e) { "casono-client-reader");
Thread.currentThread().interrupt();
break;
}
}
},
"casono-client-reader");
readerThread.setDaemon(true); readerThread.setDaemon(true);
readerThread.start(); readerThread.start();
} }
@@ -170,8 +169,7 @@ public class ClientService {
} }
/** /**
* Constructs a ClientService in offline mode. No network connection will be * Constructs a ClientService in offline mode. No network connection will be attempted and calls
* attempted and calls
* to processCommand will throw a RuntimeException. * to processCommand will throw a RuntimeException.
* *
* @param offline true to create an offline (no-network) client service * @param offline true to create an offline (no-network) client service
@@ -184,21 +182,19 @@ public class ClientService {
this.executor = Executors.newSingleThreadExecutor(); this.executor = Executors.newSingleThreadExecutor();
} }
/** /** Returns true if this ClientService is running in offline mode (no network). */
* Returns true if this ClientService is running in offline mode (no network).
*/
public boolean isOffline() { public boolean isOffline() {
return offlineMode; return offlineMode;
} }
// Allow primitive values to contain hyphens (UUIDs) in addition to // Allow primitive values to contain hyphens (UUIDs) in addition to
// digits/words/colons // digits/words/colons
static Pattern responseRex = Pattern.compile( static Pattern responseRex =
"(?<key>\\w+)=(('(?<string>([^']|\\')+)')|(?<primVal>[+-]?[-\\d\\w:]+))"); Pattern.compile(
"(?<key>\\w+)=(('(?<string>([^']|\\')+)')|(?<primVal>[+-]?[-\\d\\w:]+))");
/** /**
* Removes escape characters from a string, specifically converting escaped * Removes escape characters from a string, specifically converting escaped single quotes (\')
* single quotes (\')
* back to regular single quotes ('). * back to regular single quotes (').
* *
* @param input The escaped string to process. * @param input The escaped string to process.
@@ -209,10 +205,8 @@ public class ClientService {
} }
/** /**
* Converts a list of raw string parameters into a list of * Converts a list of raw string parameters into a list of {@link RequestParameter} objects. It
* {@link RequestParameter} objects. It * uses a regex matcher to distinguish between quoted strings (which are unescaped) and
* uses a regex matcher to distinguish between quoted strings (which are
* unescaped) and
* primitive values. * primitive values.
* *
* @param input A list of raw strings to be parsed. * @param input A list of raw strings to be parsed.
@@ -237,12 +231,10 @@ public class ClientService {
.toList(); .toList();
} }
private static record ParsedResponse(boolean success, List<String> lines) { private static record ParsedResponse(boolean success, List<String> lines) {}
}
/** /**
* Register an event listener that receives unsolicited event payload lines (no * Register an event listener that receives unsolicited event payload lines (no status prefix).
* status prefix).
*/ */
public void addEventListener(Consumer<List<String>> listener) { public void addEventListener(Consumer<List<String>> listener) {
eventListeners.add(listener); eventListeners.add(listener);
@@ -253,18 +245,14 @@ public class ClientService {
} }
/** /**
* Sends a command to the server and processes the multi-line response. It * Sends a command to the server and processes the multi-line response. It handles the protocol
* handles the protocol * handshake (expecting +OK), strips leading tabs from response lines, and collects them until
* handshake (expecting +OK), strips leading tabs from response lines, and
* collects them until
* the "END" marker is reached. * the "END" marker is reached.
* *
* @param message The raw command string to be sent to the transport layer. * @param message The raw command string to be sent to the transport layer.
* @return A list of response lines received from the server (excluding protocol * @return A list of response lines received from the server (excluding protocol markers).
* markers). * @throws RuntimeException if the server responds with an error or if a communication failure
* @throws RuntimeException if the server responds with an error or if a * occurs.
* communication failure
* occurs.
*/ */
protected List<String> processCommand(String message) { protected List<String> processCommand(String message) {
if (offlineMode) { if (offlineMode) {
@@ -275,14 +263,15 @@ public class ClientService {
ArrayBlockingQueue<ParsedResponse> q = new ArrayBlockingQueue<>(1); ArrayBlockingQueue<ParsedResponse> q = new ArrayBlockingQueue<>(1);
pendingResponses.put(reqId, q); pendingResponses.put(reqId, q);
Future<?> writeFuture = executor.submit( Future<?> writeFuture =
() -> { executor.submit(
try { () -> {
clienttcptransport.write(new RawPacket(reqId, message)); try {
} catch (IOException e) { clienttcptransport.write(new RawPacket(reqId, message));
throw new RuntimeException(e); } catch (IOException e) {
} throw new RuntimeException(e);
}); }
});
try { try {
writeFuture.get(); writeFuture.get();
@@ -314,15 +303,11 @@ public class ClientService {
} }
/** /**
* Helper method to send a request to the server using the ExecutorService. It * Helper method to send a request to the server using the ExecutorService. It submits the
* submits the * request as a Runnable task and waits for its completion. If the task is interrupted or
* request as a Runnable task and waits for its completion. If the task is * encounters an execution exception, it throws a RuntimeException with the appropriate cause.
* interrupted or
* encounters an execution exception, it throws a RuntimeException with the
* appropriate cause.
* *
* @param request The Runnable task representing the request to be sent to the * @param request The Runnable task representing the request to be sent to the server.
* server.
*/ */
private void sendRequest(Runnable request) { private void sendRequest(Runnable request) {
Future<?> future = executor.submit(request); Future<?> future = executor.submit(request);
@@ -336,12 +321,9 @@ public class ClientService {
} }
/** /**
* Helper method to extract the cause of an exception and return it as a * Helper method to extract the cause of an exception and return it as a RuntimeException. If
* RuntimeException. If * the cause is null, it returns the original exception as a RuntimeException. If the cause is
* the cause is null, it returns the original exception as a RuntimeException. * already a RuntimeException, it returns it directly. Otherwise, it wraps the cause in a new
* If the cause is
* already a RuntimeException, it returns it directly. Otherwise, it wraps the
* cause in a new
* RuntimeException and returns it. * RuntimeException and returns it.
* *
* @param e The exception from which to extract the cause. * @param e The exception from which to extract the cause.
@@ -359,10 +341,8 @@ public class ClientService {
} }
/** /**
* Closes the socket connection to the server and shuts down the * Closes the socket connection to the server and shuts down the ExecutorService. It also closes
* ExecutorService. It also closes * the TcpTransport used for communication. If any IOException occurs during this process, it
* the TcpTransport used for communication. If any IOException occurs during
* this process, it
* prints the exception to the console. * prints the exception to the console.
*/ */
public void closeSocket() { public void closeSocket() {
@@ -28,6 +28,7 @@ public class LobbyButtonGridManager {
private static final int REFRESH_INTERVAL_SECONDS = 5; private static final int REFRESH_INTERVAL_SECONDS = 5;
private static final int INITIAL_DELAY_SECONDS = 5; private static final int INITIAL_DELAY_SECONDS = 5;
private static final int COLS = 4; private static final int COLS = 4;
private static final int MAX_BUTTONS = 8;
private static final Logger LOGGER = LogManager.getLogger(LobbyButtonGridManager.class); private static final Logger LOGGER = LogManager.getLogger(LobbyButtonGridManager.class);
@@ -66,79 +67,106 @@ public class LobbyButtonGridManager {
// Subscribe to server-initiated events so closed lobbies are removed // Subscribe to server-initiated events so closed lobbies are removed
// immediately // immediately
clientService.addEventListener( clientService.addEventListener(this::handleClientServiceEvent);
lines -> { }
List<RequestParameter> params = ClientService.convertToRequestParameters(lines);
String evt = null;
String lidStr = null;
for (RequestParameter p : params) {
if ("EVENT".equalsIgnoreCase(p.key())) {
evt = p.value();
} else if ("LOBBY_ID".equalsIgnoreCase(p.key())) {
lidStr = p.value();
}
}
if (evt != null && "LOBBY_CLOSED".equalsIgnoreCase(evt) && lidStr != null) {
int lid;
try {
lid = Integer.parseInt(lidStr);
} catch (NumberFormatException ex) {
return;
}
LOGGER.info("LOBBY_CLOSED event for lobby {} — mapping before: {}", lid,
translationManager.getButtonIdToLobbyId());
// find button id(s) for this lobby and remove mapping
Map<Integer, Integer> mapping = translationManager.getButtonIdToLobbyId();
Integer toRemove = null;
for (Map.Entry<Integer, Integer> e : mapping.entrySet()) {
if (e.getValue() != null && e.getValue().intValue() == lid) {
toRemove = e.getKey();
break;
}
}
if (toRemove != null) {
LOGGER.info("Removing mapping for button {} -> lobby {} (LOBBY_CLOSED event)", toRemove,
lid);
translationManager.removeLobbyButton(toRemove);
LOGGER.debug("Mapping after removal: {}", translationManager.getButtonIdToLobbyId());
javafx.application.Platform.runLater(this::renderLobbyButtons);
}
} else if (evt != null && "LOBBY_CREATED".equalsIgnoreCase(evt) && lidStr != null) {
int lid;
try {
lid = Integer.parseInt(lidStr);
} catch (NumberFormatException ex) {
return;
}
LOGGER.info("LOBBY_CREATED event for lobby {} — mapping before: {}", lid, private static record EventInfo(String event, String lobbyId) {}
translationManager.getButtonIdToLobbyId());
Map<Integer, Integer> mapping = translationManager.getButtonIdToLobbyId(); private EventInfo extractEventInfo(List<RequestParameter> params) {
String evt = null;
String lidStr = null;
for (RequestParameter p : params) {
if ("EVENT".equalsIgnoreCase(p.key())) {
evt = p.value();
} else if ("LOBBY_ID".equalsIgnoreCase(p.key())) {
lidStr = p.value();
}
}
return new EventInfo(evt, lidStr);
}
// If this lobby is already known, nothing to do private Integer tryParseInt(String s) {
if (mapping.containsValue(lid)) { try {
LOGGER.debug("Lobby {} already mapped, skipping", lid); return Integer.parseInt(s);
return; } catch (NumberFormatException ex) {
} return null;
}
}
// find next free button id (1..8) private void handleLobbyClosed(int lid) {
for (int candidate = 1; candidate <= 8; candidate++) { LOGGER.info(
if (!mapping.containsKey(candidate)) { "LOBBY_CLOSED event for lobby {} — mapping before: {}",
try { lid,
translationManager.addLobbyButton(candidate, lid); translationManager.getButtonIdToLobbyId());
LOGGER.info("Mapped new lobby {} to button {}", lid, candidate); // find button id(s) for this lobby and remove mapping
LOGGER.debug("Mapping after add: {}", translationManager.getButtonIdToLobbyId()); Map<Integer, Integer> mapping = translationManager.getButtonIdToLobbyId();
javafx.application.Platform.runLater(this::renderLobbyButtons); Integer toRemove = null;
break; for (Map.Entry<Integer, Integer> e : mapping.entrySet()) {
} catch (Exception ex) { if (e.getValue() != null && e.getValue().intValue() == lid) {
// grid full? try next candidate toRemove = e.getKey();
LOGGER.debug("Could not map created lobby {}: {}", lid, ex.getMessage()); break;
} }
} }
} if (toRemove != null) {
} LOGGER.info(
}); "Removing mapping for button {} -> lobby {} (LOBBY_CLOSED event)",
toRemove,
lid);
translationManager.removeLobbyButton(toRemove);
LOGGER.debug("Mapping after removal: {}", translationManager.getButtonIdToLobbyId());
javafx.application.Platform.runLater(this::renderLobbyButtons);
}
}
private void handleLobbyCreated(int lid) {
LOGGER.info(
"LOBBY_CREATED event for lobby {} — mapping before: {}",
lid,
translationManager.getButtonIdToLobbyId());
Map<Integer, Integer> mapping = translationManager.getButtonIdToLobbyId();
// If this lobby is already known, nothing to do
if (mapping.containsValue(lid)) {
LOGGER.debug("Lobby {} already mapped, skipping", lid);
return;
}
// find next free button id (1..MAX_BUTTONS)
for (int candidate = 1; candidate <= MAX_BUTTONS; candidate++) {
if (!mapping.containsKey(candidate)) {
try {
translationManager.addLobbyButton(candidate, lid);
LOGGER.info("Mapped new lobby {} to button {}", lid, candidate);
LOGGER.debug(
"Mapping after add: {}", translationManager.getButtonIdToLobbyId());
javafx.application.Platform.runLater(this::renderLobbyButtons);
break;
} catch (Exception ex) {
// grid full? try next candidate
LOGGER.debug("Could not map created lobby {}: {}", lid, ex.getMessage());
}
}
}
}
private void handleClientServiceEvent(List<String> lines) {
EventInfo info = extractEventInfo(ClientService.convertToRequestParameters(lines));
if (info.event() == null || info.lobbyId() == null) {
return;
}
Integer lid = tryParseInt(info.lobbyId());
if (lid == null) {
return;
}
if ("LOBBY_CLOSED".equalsIgnoreCase(info.event())) {
handleLobbyClosed(lid);
} else if ("LOBBY_CREATED".equalsIgnoreCase(info.event())) {
handleLobbyCreated(lid);
}
} }
private void startPeriodicRefresh(long initialDelay, long period) { private void startPeriodicRefresh(long initialDelay, long period) {
@@ -185,15 +213,15 @@ public class LobbyButtonGridManager {
int lobbyId = lobbyIdObj.intValue(); int lobbyId = lobbyIdObj.intValue();
CompletableFuture.supplyAsync( CompletableFuture.supplyAsync(
() -> { () -> {
try { try {
return lobbyClient.fetchLobbyStatusString(lobbyId); return lobbyClient.fetchLobbyStatusString(lobbyId);
} catch (Exception ex) { } catch (Exception ex) {
LOGGER.info("Lobby {} missing: {}", lobbyId, ex.getMessage()); LOGGER.info("Lobby {} missing: {}", lobbyId, ex.getMessage());
return null; return null;
} }
}, },
executor) executor)
.thenAccept( .thenAccept(
status -> { status -> {
// Do not remove a mapping just because the status fetch // Do not remove a mapping just because the status fetch
@@ -203,10 +231,12 @@ public class LobbyButtonGridManager {
if (status == null) { if (status == null) {
if (!serverIds.contains(lobbyId)) { if (!serverIds.contains(lobbyId)) {
translationManager.removeLobbyButton(buttonId); translationManager.removeLobbyButton(buttonId);
javafx.application.Platform.runLater(this::renderLobbyButtons); javafx.application.Platform.runLater(
this::renderLobbyButtons);
} else { } else {
// treat as created/running later; keep mapping // treat as created/running later; keep mapping
LOGGER.debug("Temporary missing status for lobby {} - keeping mapping", LOGGER.debug(
"Missing status for lobby {} - keeping mapping",
lobbyId); lobbyId);
} }
} }
@@ -241,7 +271,9 @@ public class LobbyButtonGridManager {
} }
} }
for (Integer bid : toRemove) { for (Integer bid : toRemove) {
LOGGER.info("Reconciling: removing mapping for button {} (server no longer lists lobby)", bid); LOGGER.info(
"Reconciling: removing mapping for button {} (server no longer lists lobby)",
bid);
translationManager.removeLobbyButton(bid); translationManager.removeLobbyButton(bid);
} }
@@ -250,16 +282,20 @@ public class LobbyButtonGridManager {
if (mapping.containsValue(li.id)) { if (mapping.containsValue(li.id)) {
continue; continue;
} }
// find next free button id (1..8) // find next free button id (1..MAX_BUTTONS)
for (int candidate = 1; candidate <= 8; candidate++) { for (int candidate = 1; candidate <= MAX_BUTTONS; candidate++) {
if (!mapping.containsKey(candidate)) { if (!mapping.containsKey(candidate)) {
try { try {
translationManager.addLobbyButton(candidate, li.id); translationManager.addLobbyButton(candidate, li.id);
LOGGER.info("Reconciling: added mapping button {} -> lobby {}", candidate, li.id); LOGGER.info(
"Reconciling: added mapping button {} -> lobby {}",
candidate,
li.id);
break; break;
} catch (Exception ex) { } catch (Exception ex) {
// grid full? try next candidate // grid full? try next candidate
LOGGER.debug("Could not add mapping for lobby {}: {}", li.id, ex.getMessage()); LOGGER.debug(
"Could not add mapping for lobby {}: {}", li.id, ex.getMessage());
} }
} }
} }
@@ -340,8 +376,9 @@ public class LobbyButtonGridManager {
statusStr -> { statusStr -> {
LobbyStatus status = parseLobbyStatus(statusStr); LobbyStatus status = parseLobbyStatus(statusStr);
String path = getImagePathForLobby( String path =
lobbyId, status == null ? LobbyStatus.CREATED : status); getImagePathForLobby(
lobbyId, status == null ? LobbyStatus.CREATED : status);
Image img = safeLoadImage(path); Image img = safeLoadImage(path);
@@ -428,14 +465,14 @@ public class LobbyButtonGridManager {
int lobbyId = lobbyIdObj.intValue(); int lobbyId = lobbyIdObj.intValue();
CompletableFuture.supplyAsync( CompletableFuture.supplyAsync(
() -> { () -> {
String statusStr = lobbyClient.fetchLobbyStatusString(lobbyId); String statusStr = lobbyClient.fetchLobbyStatusString(lobbyId);
LobbyStatus status = parseLobbyStatus(statusStr); LobbyStatus status = parseLobbyStatus(statusStr);
return status == null ? LobbyStatus.CREATED : status; return status == null ? LobbyStatus.CREATED : status;
}, },
executor) executor)
.thenAccept( .thenAccept(
status -> { status -> {
String path = getImagePathForLobby(lobbyId, status); String path = getImagePathForLobby(lobbyId, status);
@@ -445,13 +482,15 @@ public class LobbyButtonGridManager {
for (Node node : gridPane.getChildren()) { for (Node node : gridPane.getChildren()) {
boolean isButton = node instanceof Button; boolean isButton = node instanceof Button;
boolean idMatches = ("lobbyBtn-" + buttonId) boolean idMatches =
.equals(node.getId()); ("lobbyBtn-" + buttonId)
.equals(node.getId());
if (isButton && idMatches) { if (isButton && idMatches) {
Button btn = (Button) node; Button btn = (Button) node;
ImageView iv = new ImageView(safeLoadImage(path)); ImageView iv =
new ImageView(safeLoadImage(path));
iv.setPreserveRatio(true); iv.setPreserveRatio(true);
iv.fitWidthProperty() iv.fitWidthProperty()
@@ -496,7 +535,8 @@ public class LobbyButtonGridManager {
javafx.application.Platform.runLater( javafx.application.Platform.runLater(
() -> { () -> {
javafx.stage.Stage currentStage = (javafx.stage.Stage) gridPane.getScene().getWindow(); javafx.stage.Stage currentStage =
(javafx.stage.Stage) gridPane.getScene().getWindow();
currentStage.hide(); currentStage.hide();
@@ -94,7 +94,12 @@ public class ServerApp {
TimeUnit.SECONDS); TimeUnit.SECONDS);
LobbyManager lobbyManager = new LobbyManager(); LobbyManager lobbyManager = new LobbyManager();
registerCommands(dispatcher, router, responseDispatcher, userRegistry, lobbyManager, sessionManager); registerCommands(
dispatcher,
router,
responseDispatcher,
userRegistry,
new CommandContext(lobbyManager, sessionManager));
// Periodic cleanup: remove empty lobbies older than 30s and notify affected // Periodic cleanup: remove empty lobbies older than 30s and notify affected
// users // users
@@ -135,6 +140,9 @@ public class ServerApp {
networkManager.start(); networkManager.start();
} }
private static record CommandContext(
LobbyManager lobbyManager, SessionManager sessionManager) {}
/** /**
* Registers command parsers and handlers. * Registers command parsers and handlers.
* *
@@ -147,8 +155,7 @@ public class ServerApp {
CommandRouter commandRouter, CommandRouter commandRouter,
ResponseDispatcher responseDispatcher, ResponseDispatcher responseDispatcher,
UserRegistry userRegistry, UserRegistry userRegistry,
LobbyManager lobbyManager, CommandContext context) {
SessionManager sessionManager) {
parserDispatcher.register("PING", new PingParser()); parserDispatcher.register("PING", new PingParser());
commandRouter.register(PingRequest.class, new PingHandler(responseDispatcher)); commandRouter.register(PingRequest.class, new PingHandler(responseDispatcher));
@@ -195,7 +202,7 @@ public class ServerApp {
ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby
.get_lobby_list.GetLobbyListRequest>) .get_lobby_list.GetLobbyListRequest>)
new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.get_lobby_list new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.get_lobby_list
.GetLobbyListHandler(responseDispatcher, lobbyManager)); .GetLobbyListHandler(responseDispatcher, context.lobbyManager()));
// GET_GAME_STATE registration // GET_GAME_STATE registration
parserDispatcher.register( parserDispatcher.register(
@@ -210,7 +217,7 @@ public class ServerApp {
.get_game_state.GetGameStateRequest>) .get_game_state.GetGameStateRequest>)
new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.get_game_state new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.get_game_state
.GetGameStateHandler( .GetGameStateHandler(
responseDispatcher, lobbyManager, userRegistry)); responseDispatcher, context.lobbyManager(), userRegistry));
// BET registration // BET registration
parserDispatcher.register( parserDispatcher.register(
@@ -222,7 +229,8 @@ public class ServerApp {
ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.bet ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.bet
.PlayerBetRequest>) .PlayerBetRequest>)
new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.bet new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.bet
.PlayerBetHandler(responseDispatcher, userRegistry, lobbyManager)); .PlayerBetHandler(
responseDispatcher, userRegistry, context.lobbyManager()));
// RAISE registration // RAISE registration
parserDispatcher.register( parserDispatcher.register(
@@ -237,7 +245,7 @@ public class ServerApp {
.PlayerRaiseRequest>) .PlayerRaiseRequest>)
new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.raise new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.raise
.PlayerRaiseHandler( .PlayerRaiseHandler(
responseDispatcher, userRegistry, lobbyManager)); responseDispatcher, userRegistry, context.lobbyManager()));
// CALL registration // CALL registration
parserDispatcher.register( parserDispatcher.register(
@@ -251,7 +259,8 @@ public class ServerApp {
ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.call ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.call
.PlayerCallRequest>) .PlayerCallRequest>)
new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.call new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.call
.PlayerCallHandler(responseDispatcher, userRegistry, lobbyManager)); .PlayerCallHandler(
responseDispatcher, userRegistry, context.lobbyManager()));
// FOLD registration // FOLD registration
parserDispatcher.register( parserDispatcher.register(
@@ -265,7 +274,8 @@ public class ServerApp {
ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.fold ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.fold
.PlayerFoldRequest>) .PlayerFoldRequest>)
new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.fold new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.fold
.PlayerFoldHandler(responseDispatcher, userRegistry, lobbyManager)); .PlayerFoldHandler(
responseDispatcher, userRegistry, context.lobbyManager()));
// GET_LOBBY_STATUS registration // GET_LOBBY_STATUS registration
parserDispatcher.register( parserDispatcher.register(
@@ -280,7 +290,7 @@ public class ServerApp {
.get_lobby_status.GetLobbyStatusRequest>) .get_lobby_status.GetLobbyStatusRequest>)
new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby
.get_lobby_status.GetLobbyStatusHandler( .get_lobby_status.GetLobbyStatusHandler(
responseDispatcher, lobbyManager, userRegistry)); responseDispatcher, context.lobbyManager(), userRegistry));
// CREATE_LOBBY registration // CREATE_LOBBY registration
parserDispatcher.register( parserDispatcher.register(
@@ -293,8 +303,11 @@ public class ServerApp {
(ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandHandler< (ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandHandler<
ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby
.create_lobby.CreateLobbyRequest>) .create_lobby.CreateLobbyRequest>)
new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.create_lobby new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.create_lobby
.CreateLobbyHandler(responseDispatcher, lobbyManager, sessionManager)); .CreateLobbyHandler(
responseDispatcher,
context.lobbyManager(),
context.sessionManager()));
// JOIN_LOBBY registration // JOIN_LOBBY registration
parserDispatcher.register( parserDispatcher.register(
@@ -308,7 +321,8 @@ public class ServerApp {
ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.join_lobby ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.join_lobby
.JoinLobbyRequest>) .JoinLobbyRequest>)
new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.join_lobby new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.join_lobby
.JoinLobbyHandler(responseDispatcher, lobbyManager, userRegistry)); .JoinLobbyHandler(
responseDispatcher, context.lobbyManager(), userRegistry));
// START_GAME registration // START_GAME registration
parserDispatcher.register( parserDispatcher.register(
@@ -322,6 +336,7 @@ public class ServerApp {
ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.start_game ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.start_game
.StartGameRequest>) .StartGameRequest>)
new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.start_game new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.start_game
.StartGameHandler(responseDispatcher, lobbyManager, userRegistry)); .StartGameHandler(
responseDispatcher, context.lobbyManager(), userRegistry));
} }
} }
@@ -3,20 +3,22 @@ package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.create_lobby;
import ch.unibas.dmi.dbis.cs108.casono.server.domain.lobby.LobbyId; 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.lobby.LobbyManager;
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandHandler; import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandHandler;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.ErrorResponse; import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.ErrorResponse;
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;
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 ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.Session; import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.Session;
import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionManager; import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionManager;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext;
public class CreateLobbyHandler extends CommandHandler<CreateLobbyRequest> { public class CreateLobbyHandler extends CommandHandler<CreateLobbyRequest> {
private final LobbyManager lobbyManager; private final LobbyManager lobbyManager;
private final SessionManager sessionManager; private final SessionManager sessionManager;
public CreateLobbyHandler( public CreateLobbyHandler(
ResponseDispatcher responseDispatcher, LobbyManager lobbyManager, SessionManager sessionManager) { ResponseDispatcher responseDispatcher,
LobbyManager lobbyManager,
SessionManager sessionManager) {
super(responseDispatcher); super(responseDispatcher);
this.lobbyManager = lobbyManager; this.lobbyManager = lobbyManager;
this.sessionManager = sessionManager; this.sessionManager = sessionManager;