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 7062252..e859056 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 @@ -24,6 +24,7 @@ import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingRequest; import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.send_message.SendMessageHandler; import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.send_message.SendMessageParser; import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.send_message.SendMessageRequest; +import ch.unibas.dmi.dbis.cs108.casono.server.domain.lobby.LobbyManager; import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserCleanupJob; import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserRegistry; import ch.unibas.dmi.dbis.cs108.casono.server.network.NetworkManager; @@ -44,97 +45,121 @@ import org.apache.logging.log4j.Logger; /** Application class for starting the server. */ public class ServerApp { - private static final int USER_CLEANUP_JOB_DELAY = 0; - private static final int USER_CLEANUP_JOB_PERIOD = 10; - private static final int USER_CLEANUP_JOB_RECONNECT_THRESHOLD = 10; - private static final int SESSION_DISCONNECT_JOB_DELAY = 0; - private static final int SESSION_DISCONNECT_JOB_PERIOD = 2; - private static final int SESSION_DISCONNECT_JOB_TIMEOUT = 5; + private static final int USER_CLEANUP_JOB_DELAY = 0; + private static final int USER_CLEANUP_JOB_PERIOD = 10; + private static final int USER_CLEANUP_JOB_RECONNECT_THRESHOLD = 10; + private static final int SESSION_DISCONNECT_JOB_DELAY = 0; + private static final int SESSION_DISCONNECT_JOB_PERIOD = 2; + private static final int SESSION_DISCONNECT_JOB_TIMEOUT = 5; - public static void start(String arg) { - int port = Integer.parseInt(arg); + public static void start(String arg) { + int port = Integer.parseInt(arg); - Logger logger = LogManager.getLogger(ServerApp.class); - logger.info("Starting server at port {}", port); + Logger logger = LogManager.getLogger(ServerApp.class); + logger.info("Starting server at port {}", port); - EventBus eventBus = new EventBus(); - CommandParserDispatcher dispatcher = new CommandParserDispatcher(); - SessionManager sessionManager = new SessionManager(eventBus, dispatcher); - ResponseDispatcher responseDispatcher = new ResponseDispatcher(sessionManager); - CommandHandlerExecutor handlerExecutor = new CommandHandlerExecutor(responseDispatcher); - CommandRouter router = new CommandRouter(handlerExecutor); + EventBus eventBus = new EventBus(); + CommandParserDispatcher dispatcher = new CommandParserDispatcher(); + SessionManager sessionManager = new SessionManager(eventBus, dispatcher); + ResponseDispatcher responseDispatcher = new ResponseDispatcher(sessionManager); + CommandHandlerExecutor handlerExecutor = new CommandHandlerExecutor(responseDispatcher); + CommandRouter router = new CommandRouter(handlerExecutor); - eventBus.subscribe(DisconnectEvent.class, event -> sessionManager.onDisconnect(event)); + eventBus.subscribe(DisconnectEvent.class, event -> sessionManager.onDisconnect(event)); - UserRegistry userRegistry = new UserRegistry(); - eventBus.subscribe( - DisconnectEvent.class, event -> userRegistry.onDisconnect(event.sessionId())); - ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - scheduler.scheduleAtFixedRate( - new UserCleanupJob( - userRegistry, Duration.ofSeconds(USER_CLEANUP_JOB_RECONNECT_THRESHOLD)), - USER_CLEANUP_JOB_DELAY, - USER_CLEANUP_JOB_PERIOD, - TimeUnit.SECONDS); - scheduler.scheduleAtFixedRate( - new SessionDisconnectJob( - sessionManager, - eventBus, - Duration.ofSeconds(SESSION_DISCONNECT_JOB_TIMEOUT)), - SESSION_DISCONNECT_JOB_DELAY, - SESSION_DISCONNECT_JOB_PERIOD, - TimeUnit.SECONDS); + UserRegistry userRegistry = new UserRegistry(); + eventBus.subscribe( + DisconnectEvent.class, event -> userRegistry.onDisconnect(event.sessionId())); + ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + scheduler.scheduleAtFixedRate( + new UserCleanupJob( + userRegistry, Duration.ofSeconds(USER_CLEANUP_JOB_RECONNECT_THRESHOLD)), + USER_CLEANUP_JOB_DELAY, + USER_CLEANUP_JOB_PERIOD, + TimeUnit.SECONDS); + scheduler.scheduleAtFixedRate( + new SessionDisconnectJob( + sessionManager, + eventBus, + Duration.ofSeconds(SESSION_DISCONNECT_JOB_TIMEOUT)), + SESSION_DISCONNECT_JOB_DELAY, + SESSION_DISCONNECT_JOB_PERIOD, + TimeUnit.SECONDS); - registerCommands(dispatcher, router, responseDispatcher, userRegistry); + LobbyManager lobbyManager = new LobbyManager(); + registerCommands(dispatcher, router, responseDispatcher, userRegistry, lobbyManager); - NetworkManager networkManager = new NetworkManager(port, sessionManager, router); - networkManager.start(); - } + NetworkManager networkManager = new NetworkManager(port, sessionManager, router); + networkManager.start(); + } - /** - * Registers command parsers and handlers. - * - * @param parserDispatcher the dispatcher responsible for parsing incoming commands - * @param commandRouter the router that dispatches parsed commands to appropriate handlers - * @param responseDispatcher the dispatcher responsible for sending responses back to clients - */ - private static void registerCommands( - CommandParserDispatcher parserDispatcher, - CommandRouter commandRouter, - ResponseDispatcher responseDispatcher, - UserRegistry userRegistry) { - parserDispatcher.register("PING", new PingParser()); - commandRouter.register(PingRequest.class, new PingHandler(responseDispatcher)); + /** + * Registers command parsers and handlers. + * + * @param parserDispatcher the dispatcher responsible for parsing incoming + * commands + * @param commandRouter the router that dispatches parsed commands to + * appropriate handlers + * @param responseDispatcher the dispatcher responsible for sending responses + * back to clients + */ + private static void registerCommands( + CommandParserDispatcher parserDispatcher, + CommandRouter commandRouter, + ResponseDispatcher responseDispatcher, + UserRegistry userRegistry, + LobbyManager lobbyManager) { + parserDispatcher.register("PING", new PingParser()); + commandRouter.register(PingRequest.class, new PingHandler(responseDispatcher)); - parserDispatcher.register("CHECK_USERNAME", new CheckUsernameParser()); - commandRouter.register( - CheckUsernameRequest.class, - new CheckUsernameHandler(responseDispatcher, userRegistry)); + parserDispatcher.register("CHECK_USERNAME", new CheckUsernameParser()); + commandRouter.register( + CheckUsernameRequest.class, + new CheckUsernameHandler(responseDispatcher, userRegistry)); - parserDispatcher.register("LOGIN", new LoginParser()); - commandRouter.register( - LoginRequest.class, new LoginHandler(responseDispatcher, userRegistry)); + parserDispatcher.register("LOGIN", new LoginParser()); + commandRouter.register( + LoginRequest.class, new LoginHandler(responseDispatcher, userRegistry)); - parserDispatcher.register("LOGOUT", new LogoutParser()); - commandRouter.register( - LogoutRequest.class, new LogoutHandler(responseDispatcher, userRegistry)); + parserDispatcher.register("LOGOUT", new LogoutParser()); + commandRouter.register( + LogoutRequest.class, new LogoutHandler(responseDispatcher, userRegistry)); - parserDispatcher.register("SEND_MESSAGE", new SendMessageParser()); - commandRouter.register( - SendMessageRequest.class, new SendMessageHandler(responseDispatcher, userRegistry)); + parserDispatcher.register("SEND_MESSAGE", new SendMessageParser()); + commandRouter.register( + SendMessageRequest.class, new SendMessageHandler(responseDispatcher, userRegistry)); - parserDispatcher.register("GET_MESSAGE_COUNT", new GetMessageCountParser()); - commandRouter.register( - GetMessageCountRequest.class, - new GetMessageCountHandler(responseDispatcher, userRegistry)); + parserDispatcher.register("GET_MESSAGE_COUNT", new GetMessageCountParser()); + commandRouter.register( + GetMessageCountRequest.class, + new GetMessageCountHandler(responseDispatcher, userRegistry)); - parserDispatcher.register("GET_NEXT_MESSAGE", new GetNextMessageParser()); - commandRouter.register( - GetNextMessageRequest.class, - new GetNextMessageHandler(responseDispatcher, userRegistry)); + parserDispatcher.register("GET_NEXT_MESSAGE", new GetNextMessageParser()); + commandRouter.register( + GetNextMessageRequest.class, + new GetNextMessageHandler(responseDispatcher, userRegistry)); - parserDispatcher.register("LIST_USERS", new ListUsersParser()); - commandRouter.register( - ListUsersRequest.class, new ListUsersHandler(responseDispatcher, userRegistry)); - } + parserDispatcher.register("LIST_USERS", new ListUsersParser()); + commandRouter.register( + ListUsersRequest.class, new ListUsersHandler(responseDispatcher, userRegistry)); + + // Lobby commands + parserDispatcher.register( + "JOIN_LOBBY", + new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.join_lobby.JoinLobbyParser()); + commandRouter.register( + ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.join_lobby.JoinLobbyRequest.class, + new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.lobby.join_lobby.JoinLobbyHandler( + responseDispatcher, lobbyManager, userRegistry)); + + + // Game state: allow client to request game snapshot for their lobby + parserDispatcher.register( + "GET_GAME_STATE", + new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.get_game_state.GetGameStateParser()); + commandRouter.register( + ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.get_game_state.GetGameStateRequest.class, + new ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.get_game_state.GetGameStateHandler( + responseDispatcher, lobbyManager, userRegistry)); + } } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/join_lobby/JoinLobbyHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/join_lobby/JoinLobbyHandler.java index 33ca37e..579c281 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/join_lobby/JoinLobbyHandler.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/join_lobby/JoinLobbyHandler.java @@ -13,12 +13,10 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatch /** * Handler for the `JOIN_LOBBY` command. * - *

- * Resolves the username from the session (requires {@link UserLoggedInCheck}), - * looks up the target lobby and attempts to add the user. On success an - * `+OK` response is dispatched; on failure an appropriate {@link ErrorResponse} - * with one of the error codes `LOBBY_NOT_FOUND`, `USER_NOT_LOGGED_IN` or - * `LOBBY_FULL_OR_ALREADY_IN` is returned. + *

Resolves the username from the session (requires {@link UserLoggedInCheck}), looks up the + * target lobby and attempts to add the user. On success an `+OK` response is dispatched; on failure + * an appropriate {@link ErrorResponse} with one of the error codes `LOBBY_NOT_FOUND`, + * `USER_NOT_LOGGED_IN` or `LOBBY_FULL_OR_ALREADY_IN` is returned. */ public class JoinLobbyHandler extends CommandHandler { private final LobbyManager lobbyManager; @@ -27,10 +25,9 @@ public class JoinLobbyHandler extends CommandHandler { /** * Create a new {@link JoinLobbyHandler}. * - * @param responseDispatcher dispatcher used to send responses back to the - * client - * @param lobbyManager manager providing lobby state and operations - * @param userRegistry registry to resolve session -> user mappings + * @param responseDispatcher dispatcher used to send responses back to the client + * @param lobbyManager manager providing lobby state and operations + * @param userRegistry registry to resolve session -> user mappings */ public JoinLobbyHandler( ResponseDispatcher responseDispatcher, diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/join_lobby/JoinLobbyParser.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/join_lobby/JoinLobbyParser.java index c7cb217..6f7b892 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/join_lobby/JoinLobbyParser.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/join_lobby/JoinLobbyParser.java @@ -7,15 +7,14 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.accessor. /** * Parser for the `JOIN_LOBBY` command. * - *

- * Expected request parameters: + *

Expected request parameters: + * *

* - *

- * The parser builds a {@link JoinLobbyRequest} containing the parsed lobby id - * and the original request context. + *

The parser builds a {@link JoinLobbyRequest} containing the parsed lobby id and the original + * request context. */ public class JoinLobbyParser implements CommandParser { /** @@ -26,7 +25,8 @@ public class JoinLobbyParser implements CommandParser { */ @Override public JoinLobbyRequest parse(PrimitiveRequest primitiveRequest) { - RequestParameterAccessor accessor = new RequestParameterAccessor(primitiveRequest.parameters()); + RequestParameterAccessor accessor = + new RequestParameterAccessor(primitiveRequest.parameters()); int id = accessor.require("ID", Integer::parseInt); return new JoinLobbyRequest(primitiveRequest.context(), id); } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/join_lobby/JoinLobbyRequest.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/join_lobby/JoinLobbyRequest.java index f667a66..4402707 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/join_lobby/JoinLobbyRequest.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/lobby/join_lobby/JoinLobbyRequest.java @@ -6,9 +6,8 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestCo /** * Request data for the `JOIN_LOBBY` command. * - *

- * Contains the lobby id the client wants to join and inherits the - * {@link Request} contextual information. + *

Contains the lobby id the client wants to join and inherits the {@link Request} contextual + * information. */ public class JoinLobbyRequest extends Request { private final int id; @@ -17,7 +16,7 @@ public class JoinLobbyRequest extends Request { * Create a new {@link JoinLobbyRequest}. * * @param context the request context - * @param id numeric lobby id to join + * @param id numeric lobby id to join */ public JoinLobbyRequest(RequestContext context, int id) { super(context);