{@code
+ * public record uniqueEventResponse(String content, long identifier) implements ResponseToUniqueEvent {};
+ * public record uniqueEventResponse(long identifier) implements ResponseToUniqueEvent {};
+ * public record uniqueEventResponse(String content, int number, long identifier) implements ResponseToUniqueEvent {};
+ * }
+ *
+ */
public interface ResponseToUniqueEvent extends UniqueEvent {
default Map{@code
+ * public record uniqueEvent(String content, long identifier) implements UniqueEvent {};
+ * public record uniqueEvent(long identifier) implements UniqueEvent {};
+ * public record uniqueEvent(String content, int number, long identifier) implements UniqueEvent {};
+ * }
+ *
+ */
public interface UniqueEvent extends EventType {
default long getIdentifier() {
try {
diff --git a/framework/src/main/java/org/toop/framework/networking/NetworkingClientEventListener.java b/framework/src/main/java/org/toop/framework/networking/NetworkingClientEventListener.java
new file mode 100644
index 0000000..ef51a46
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/NetworkingClientEventListener.java
@@ -0,0 +1,150 @@
+package org.toop.framework.networking;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.toop.framework.SnowflakeGenerator;
+import org.toop.framework.eventbus.EventFlow;
+import org.toop.framework.networking.events.NetworkEvents;
+import org.toop.framework.networking.exceptions.ClientNotFoundException;
+import org.toop.framework.networking.interfaces.NetworkingClientManager;
+
+public class NetworkingClientEventListener {
+
+ private static final Logger logger = LogManager.getLogger(NetworkingClientEventListener.class);
+ private final NetworkingClientManager clientManager;
+
+ /** Starts a connection manager, to manage, connections. */
+ public NetworkingClientEventListener(NetworkingClientManager clientManager) {
+ this.clientManager = clientManager;
+ new EventFlow()
+ .listen(this::handleStartClient)
+ .listen(this::handleCommand)
+ .listen(this::handleSendLogin)
+ .listen(this::handleSendLogout)
+ .listen(this::handleSendGetPlayerlist)
+ .listen(this::handleSendGetGamelist)
+ .listen(this::handleSendSubscribe)
+ .listen(this::handleSendMove)
+ .listen(this::handleSendChallenge)
+ .listen(this::handleSendAcceptChallenge)
+ .listen(this::handleSendForfeit)
+ .listen(this::handleSendMessage)
+ .listen(this::handleSendHelp)
+ .listen(this::handleSendHelpForCommand)
+ .listen(this::handleCloseClient)
+ .listen(this::handleReconnect)
+ .listen(this::handleChangeAddress)
+ .listen(this::handleGetAllConnections)
+ .listen(this::handleShutdownAll);
+ }
+
+ void handleStartClient(NetworkEvents.StartClient event) {
+ long clientId = SnowflakeGenerator.nextId();
+ clientManager.startClient(
+ clientId,
+ event.networkingClient(),
+ event.networkingConnector(),
+ () -> new EventFlow().addPostEvent(new NetworkEvents.StartClientResponse(clientId, true, event.identifier())).postEvent(),
+ () -> new EventFlow().addPostEvent(new NetworkEvents.StartClientResponse(clientId, false, event.identifier())).postEvent()
+ );
+ }
+
+ private void sendCommand(long clientId, String command) {
+ try {
+ clientManager.sendCommand(clientId, command);
+ } catch (ClientNotFoundException e) {
+ logger.error(e);
+ }
+ }
+
+ private void handleCommand(NetworkEvents.SendCommand event) {
+ String args = String.join(" ", event.args());
+ sendCommand(event.clientId(), args);
+ }
+
+ private void handleSendLogin(NetworkEvents.SendLogin event) {
+ sendCommand(event.clientId(), String.format("LOGIN %s", event.username()));
+ }
+
+ private void handleSendLogout(NetworkEvents.SendLogout event) {
+ sendCommand(event.clientId(), "LOGOUT");
+ }
+
+ private void handleSendGetPlayerlist(NetworkEvents.SendGetPlayerlist event) {
+ sendCommand(event.clientId(), "GET PLAYERLIST");
+ }
+
+ private void handleSendGetGamelist(NetworkEvents.SendGetGamelist event) {
+ sendCommand(event.clientId(), "GET GAMELIST");
+ }
+
+ private void handleSendSubscribe(NetworkEvents.SendSubscribe event) {
+ sendCommand(event.clientId(), String.format("SUBSCRIBE %s", event.gameType()));
+ }
+
+ private void handleSendMove(NetworkEvents.SendMove event) {
+ sendCommand(event.clientId(), String.format("MOVE %d", event.moveNumber()));
+ }
+
+ private void handleSendChallenge(NetworkEvents.SendChallenge event) {
+ sendCommand(event.clientId(), String.format("CHALLENGE %s %s", event.usernameToChallenge(), event.gameType()));
+ }
+
+ private void handleSendAcceptChallenge(NetworkEvents.SendAcceptChallenge event) {
+ sendCommand(event.clientId(), String.format("CHALLENGE ACCEPT %d", event.challengeId()));
+ }
+
+ private void handleSendForfeit(NetworkEvents.SendForfeit event) {
+ sendCommand(event.clientId(), "FORFEIT");
+ }
+
+ private void handleSendMessage(NetworkEvents.SendMessage event) {
+ sendCommand(event.clientId(), String.format("MESSAGE %s", event.message()));
+ }
+
+ private void handleSendHelp(NetworkEvents.SendHelp event) {
+ sendCommand(event.clientId(), "HELP");
+ }
+
+ private void handleSendHelpForCommand(NetworkEvents.SendHelpForCommand event) {
+ sendCommand(event.clientId(), String.format("HELP %s", event.command()));
+ }
+
+ private void handleReconnect(NetworkEvents.Reconnect event) {
+ clientManager.startClient(
+ event.clientId(),
+ event.networkingClient(),
+ event.networkingConnector(),
+ () -> new EventFlow().addPostEvent(new NetworkEvents.ReconnectResponse(true, event.identifier())).postEvent(),
+ () -> new EventFlow().addPostEvent(new NetworkEvents.ReconnectResponse(false, event.identifier())).postEvent()
+ );
+ }
+
+ private void handleChangeAddress(NetworkEvents.ChangeAddress event) {
+ clientManager.startClient(
+ event.clientId(),
+ event.networkingClient(),
+ event.networkingConnector(),
+ () -> new EventFlow().addPostEvent(new NetworkEvents.ChangeAddressResponse(true, event.identifier())).postEvent(),
+ () -> new EventFlow().addPostEvent(new NetworkEvents.ChangeAddressResponse(false, event.identifier())).postEvent()
+ );
+ }
+
+ void handleCloseClient(NetworkEvents.CloseClient event) {
+ try {
+ this.clientManager.closeClient(event.clientId());
+ } catch (ClientNotFoundException e) {
+ logger.error(e);
+ }
+ }
+
+ void handleGetAllConnections(NetworkEvents.RequestsAllClients request) {
+// List+ * These events are used in conjunction with the {@link org.toop.framework.eventbus.GlobalEventBus} + * and {@link org.toop.framework.eventbus.EventFlow} to communicate between components + * such as networking clients, managers, and listeners. + *
* - *This class defines all the events that can be posted or listened to in the networking - * subsystem. Events are separated into those with unique IDs (UniqueEvent) and those without - * (GenericEvent). + *
This is a blocking event. The result will be delivered via the provided {@link - * CompletableFuture}. - * - * @param future CompletableFuture to receive the list of active {@link NetworkingClient} - * instances. + * Requests a list of all active networking clients. + *
+ * This is a blocking request that returns the list asynchronously
+ * via the provided {@link CompletableFuture}.
*/
public record RequestsAllClients(CompletableFuture Carries IP, port, and a unique event ID for correlation with responses.
- *
- * @param ip Server IP address.
- * @param port Server port.
- * @param eventSnowflake Unique event identifier for correlation.
- */
- public record StartClient(String ip, int port, long eventSnowflake) implements UniqueEvent {}
-
- /**
- * Response confirming a client was started.
- *
- * @param clientId The client ID assigned to the new connection.
- * @param identifier Event ID used for correlation.
- */
- @AutoResponseResult
- public record StartClientResponse(long clientId, long identifier) implements ResponseToUniqueEvent {}
-
- /** Generic server response. */
- public record ServerResponse(long clientId) implements GenericEvent {}
-
- /**
- * Request to send a command to a server.
- *
- * @param clientId The client connection ID.
+ * @param clientId The client ID to send the command from.
* @param args The command arguments.
*/
- public record SendCommand(long clientId, String... args) implements GenericEvent {}
+ public record SendCommand(long clientId, String... args)
+ implements GenericEvent {}
- /** WIP (Not working) Request to reconnect a client to a previous address. */
- public record Reconnect(long clientId) implements GenericEvent {}
+ /** Event fired when a message is received from the server. */
+ public record ReceivedMessage(long clientId, String message)
+ implements GenericEvent {}
+
+ /** Indicates that a client connection has been closed. */
+ public record ClosedConnection(long clientId)
+ implements GenericEvent {}
+
+ // ------------------------------------------------------
+ // Unique Request & Response Events (with identifier)
+ // ------------------------------------------------------
/**
- * Response triggered when a message is received from a server.
+ * Requests creation and connection of a new client.
+ *
+ * The {@code identifier} is automatically assigned by {@link org.toop.framework.eventbus.EventFlow}
+ * to correlate with its corresponding {@link StartClientResponse}.
+ *
+ * The {@code identifier} value is automatically propagated from
+ * the original {@link StartClient} request by {@link org.toop.framework.eventbus.EventFlow}.
+ *
+ * The {@code identifier} is automatically injected by {@link org.toop.framework.eventbus.EventFlow}.
+ *
+ * The {@code identifier} is automatically injected by {@link org.toop.framework.eventbus.EventFlow}.
+ * > future)
implements GenericEvent {}
- /** Forces all active client connections to close immediately. */
+ /** Signals all active clients should be forcefully closed. */
public record ForceCloseAllClients() implements GenericEvent {}
- /** Response indicating a challenge was cancelled. */
- public record ChallengeCancelledResponse(long clientId, String challengeId) implements GenericEvent {}
+ /** Indicates a challenge was cancelled by the server. */
+ public record ChallengeCancelledResponse(long clientId, String challengeId)
+ implements GenericEvent {}
- /** Response indicating a challenge was received. */
+ /** Indicates an incoming challenge from another player. */
public record ChallengeResponse(long clientId, String challengerName, String challengeId, String gameType)
implements GenericEvent {}
- /** Response containing a list of players for a client. */
- public record PlayerlistResponse(long clientId, String[] playerlist) implements GenericEvent {}
+ /** Contains the list of players currently available on the server. */
+ public record PlayerlistResponse(long clientId, String[] playerlist)
+ implements GenericEvent {}
- /** Response containing a list of games for a client. */
- public record GamelistResponse(long clientId, String[] gamelist) implements GenericEvent {}
+ /** Contains the list of available game types for a client. */
+ public record GamelistResponse(long clientId, String[] gamelist)
+ implements GenericEvent {}
- /** Response indicating a game match information for a client. */
+ /** Provides match information when a new game starts. */
public record GameMatchResponse(long clientId, String playerToMove, String gameType, String opponent)
implements GenericEvent {}
- /** Response indicating the result of a game. */
- public record GameResultResponse(long clientId, String condition) implements GenericEvent {}
+ /** Indicates the outcome or completion of a game. */
+ public record GameResultResponse(long clientId, String condition)
+ implements GenericEvent {}
- /** Response indicating a game move occurred. */
- public record GameMoveResponse(long clientId, String player, String move, String details) implements GenericEvent {}
+ /** Indicates that a game move has been processed or received. */
+ public record GameMoveResponse(long clientId, String player, String move, String details)
+ implements GenericEvent {}
- /** Response indicating it is the player's turn. */
+ /** Indicates it is the current player's turn to move. */
public record YourTurnResponse(long clientId, String message)
implements GenericEvent {}
- /** Request to send login credentials for a client. */
- public record SendLogin(long clientId, String username) implements GenericEvent {}
+ /** Requests a login operation for the given client. */
+ public record SendLogin(long clientId, String username)
+ implements GenericEvent {}
- /** Request to log out a client. */
- public record SendLogout(long clientId) implements GenericEvent {}
+ /** Requests logout for the specified client. */
+ public record SendLogout(long clientId)
+ implements GenericEvent {}
- /** Request to retrieve the player list for a client. */
- public record SendGetPlayerlist(long clientId) implements GenericEvent {}
+ /** Requests the player list from the server. */
+ public record SendGetPlayerlist(long clientId)
+ implements GenericEvent {}
- /** Request to retrieve the game list for a client. */
- public record SendGetGamelist(long clientId) implements GenericEvent {}
+ /** Requests the game list from the server. */
+ public record SendGetGamelist(long clientId)
+ implements GenericEvent {}
- /** Request to subscribe a client to a game type. */
- public record SendSubscribe(long clientId, String gameType) implements GenericEvent {}
+ /** Requests a subscription to updates for a given game type. */
+ public record SendSubscribe(long clientId, String gameType)
+ implements GenericEvent {}
- /** Request to make a move in a game. */
- public record SendMove(long clientId, short moveNumber) implements GenericEvent {}
+ /** Sends a game move command to the server. */
+ public record SendMove(long clientId, short moveNumber)
+ implements GenericEvent {}
- /** Request to challenge another player. */
- public record SendChallenge(long clientId, String usernameToChallenge, String gameType) implements GenericEvent {}
+ /** Requests to challenge another player to a game. */
+ public record SendChallenge(long clientId, String usernameToChallenge, String gameType)
+ implements GenericEvent {}
- /** Request to accept a challenge. */
- public record SendAcceptChallenge(long clientId, int challengeId) implements GenericEvent {}
+ /** Requests to accept an existing challenge. */
+ public record SendAcceptChallenge(long clientId, int challengeId)
+ implements GenericEvent {}
- /** Request to forfeit a game. */
- public record SendForfeit(long clientId) implements GenericEvent {}
+ /** Requests to forfeit the current game. */
+ public record SendForfeit(long clientId)
+ implements GenericEvent {}
- /** Request to send a message from a client. */
- public record SendMessage(long clientId, String message) implements GenericEvent {}
+ /** Sends a chat or informational message from a client. */
+ public record SendMessage(long clientId, String message)
+ implements GenericEvent {}
- /** Request to display help to a client. */
- public record SendHelp(long clientId) implements GenericEvent {}
+ /** Requests general help information from the server. */
+ public record SendHelp(long clientId)
+ implements GenericEvent {}
- /** Request to display help for a specific command. */
- public record SendHelpForCommand(long clientId, String command) implements GenericEvent {}
+ /** Requests help information specific to a given command. */
+ public record SendHelpForCommand(long clientId, String command)
+ implements GenericEvent {}
- /** Request to close a specific client connection. */
- public record CloseClient(long clientId) implements GenericEvent {}
+ /** Requests to close an active client connection. */
+ public record CloseClient(long clientId)
+ implements GenericEvent {}
+
+ /** A generic event indicating a raw server response. */
+ public record ServerResponse(long clientId)
+ implements GenericEvent {}
/**
- * Event to start a new client connection.
+ * Sends a raw command string to the server.
*
- *