Feat: Add addPlayer command on sever side #258
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
+7
-10
@@ -13,12 +13,10 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatch
|
||||
/**
|
||||
* Handler for the `JOIN_LOBBY` command.
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>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<JoinLobbyRequest> {
|
||||
private final LobbyManager lobbyManager;
|
||||
@@ -27,10 +25,9 @@ public class JoinLobbyHandler extends CommandHandler<JoinLobbyRequest> {
|
||||
/**
|
||||
* 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,
|
||||
|
||||
+7
-7
@@ -7,15 +7,14 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.accessor.
|
||||
/**
|
||||
* Parser for the `JOIN_LOBBY` command.
|
||||
*
|
||||
* <p>
|
||||
* Expected request parameters:
|
||||
* <p>Expected request parameters:
|
||||
*
|
||||
* <ul>
|
||||
* <li>`ID` (int) — numeric lobby identifier (required)
|
||||
* <li>`ID` (int) — numeric lobby identifier (required)
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* The parser builds a {@link JoinLobbyRequest} containing the parsed lobby id
|
||||
* and the original request context.
|
||||
* <p>The parser builds a {@link JoinLobbyRequest} containing the parsed lobby id and the original
|
||||
* request context.
|
||||
*/
|
||||
public class JoinLobbyParser implements CommandParser<JoinLobbyRequest> {
|
||||
/**
|
||||
@@ -26,7 +25,8 @@ public class JoinLobbyParser implements CommandParser<JoinLobbyRequest> {
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
|
||||
+3
-4
@@ -6,9 +6,8 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestCo
|
||||
/**
|
||||
* Request data for the `JOIN_LOBBY` command.
|
||||
*
|
||||
* <p>
|
||||
* Contains the lobby id the client wants to join and inherits the
|
||||
* {@link Request} contextual information.
|
||||
* <p>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);
|
||||
|
||||
Reference in New Issue
Block a user