### Configure Netty-socketio Server Source: https://github.com/mrniko/netty-socketio/wiki/Configuration-details Example of setting up a Netty-socketio server with custom hostname, port, and socket configurations. Ensure the Configuration object is instantiated before setting properties. ```java Configuration config = new Configuration(); config.setHostname("localhost"); config.setPort(1337); config.setCloseTimeout(30); SocketConfig socketConfig = new SocketConfig(); socketConfig.setReuseAddress(true); config.setSocketConfig(socketConfig); SocketIOServer server = new SocketIOServer(config); ``` -------------------------------- ### Basic Server Configuration and Startup Source: https://context7.com/mrniko/netty-socketio/llms.txt Configure server settings like hostname, port, timeouts, payload limits, transports, TCP options, thread pools, native epoll, and CORS. Then start the server. ```java import com.corundumstudio.socketio; import com.corundumstudio.socketio.Configuration; import com.corundumstudio.socketio.SocketConfig; import com.corundumstudio.socketio.SocketIOServer; import com.corundumstudio.socketio.Transport; // Basic configuration Configuration config = new Configuration(); config.setHostname("0.0.0.0"); // bind all interfaces (required for AWS/Docker) config.setPort(9092); // Tune timeouts (milliseconds) config.setPingInterval(25000); // heartbeat interval, default 25 000 ms config.setPingTimeout(60000); // heartbeat timeout, default 60 000 ms config.setUpgradeTimeout(10000); // transport upgrade timeout // Payload limits config.setMaxHttpContentLength(64 * 1024); // 64 KB config.setMaxFramePayloadLength(64 * 1024); // 64 KB WebSocket frame // Transport selection config.setTransports(Transport.WEBSOCKET, Transport.POLLING); // TCP socket options SocketConfig socketConfig = new SocketConfig(); socketConfig.setReuseAddress(true); socketConfig.setTcpNoDelay(true); socketConfig.setTcpKeepAlive(true); config.setSocketConfig(socketConfig); // Thread pool (0 = CPU count × 2) config.setBossThreads(1); config.setWorkerThreads(100); // Linux native epoll (better performance on Linux) config.setUseLinuxNativeEpoll(true); // CORS config.setEnableCors(true); config.setOrigin("https://myapp.example.com"); config.setAllowHeaders("Authorization, Content-Type"); // HTTP/WS compression config.setHttpCompression(true); config.setWebsocketCompression(true); SocketIOServer server = new SocketIOServer(config); server.start(); // server.stop() to shut down gracefully ``` -------------------------------- ### Store and Retrieve Client Data in Java Source: https://context7.com/mrniko/netty-socketio/llms.txt Utilize the `Store` interface implemented by `SocketIOClient` to manage per-session key-value data. Supports setting, getting, checking existence, and deleting data. ```java server.addConnectListener(client -> { // Store data client.set("role", "editor"); client.set("loginTime", System.currentTimeMillis()); }); server.addEventListener("get_role", Object.class, (client, data, ack) -> { String role = client.get("role"); boolean hasRole = client.has("role"); System.out.println("role=" + role + " exists=" + hasRole); // Delete a key client.del("loginTime"); if (ack.isAckRequested()) { ack.sendAckData(role); } }); ``` -------------------------------- ### SSL/TLS Configuration Source: https://context7.com/mrniko/netty-socketio/llms.txt Configure HTTPS/WSS by supplying a JKS keystore. Supports mutual TLS for client certificate authentication. ```java Configuration config = new Configuration(); config.setPort(443); config.setSSLProtocol("TLSv1.2"); config.setKeyStoreFormat("JKS"); config.setKeyStore( MyServer.class.getClassLoader().getResourceAsStream("keystore.jks") ); config.setKeyStorePassword("changeit"); // Mutual TLS (client certificate authentication) config.setTrustStoreFormat("JKS"); config.trustStore( MyServer.class.getClassLoader().getResourceAsStream("truststore.jks") ); config.setTrustStorePassword("changeit"); config.setNeedClientAuth(true); SocketIOServer server = new SocketIOServer(config); server.start(); ``` -------------------------------- ### Configure Hazelcast Store Factory for Clustering in Java Source: https://context7.com/mrniko/netty-socketio/llms.txt Set up Hazelcast as the store factory for Netty Socket.IO to enable distributed session management and event broadcasting across a cluster. Requires Hazelcast and Netty Socket.IO dependencies. ```java // --- Hazelcast clustering --- import com.corundumstudio.socketio.store.HazelcastStoreFactory; import com.hazelcast.core.Hazelcast; import com.hazelcast.core.HazelcastInstance; HazelcastInstance hz = Hazelcast.newHazelcastInstance(); config.setStoreFactory(new HazelcastStoreFactory(hz)); ``` -------------------------------- ### Namespace Management Source: https://context7.com/mrniko/netty-socketio/llms.txt Create and manage custom namespaces to multiplex different logical channels over a single server, each with its own event listeners and broadcast scope. ```APIDOC ## Namespace Operations ### Description Manages namespaces for multiplexing logical channels over a single Socket.IO server. ### Methods - **server.addNamespace(namespaceName)**: Creates and returns a new custom namespace. - **namespace.addConnectListener(listener)**: Adds a listener for client connections to the namespace. - **namespace.addEventListener(eventName, classOfData, eventHandler)**: Registers an event listener within the namespace. - **namespace.getBroadcastOperations().sendEvent(eventName, data)**: Broadcasts an event to all clients within the namespace. - **namespace.getAllClients()**: Returns a collection of all clients connected to the namespace. - **namespace.getClient(sessionId)**: Retrieves a specific client by its session UUID. - **namespace.addAuthTokenListener(listener)**: Adds a listener for authenticating clients using tokens. - **server.removeNamespace(namespaceName)**: Removes a namespace entirely from the server. ### Request Example ```java SocketIOServer server = new SocketIOServer(config); // Create a custom namespace SocketIONamespace chatNs = server.addNamespace("/chat"); SocketIONamespace adminNs = server.addNamespace("/admin"); chatNs.addConnectListener(client -> System.out.println("Connected to /chat: " + client.getSessionId()) ); chatNs.addEventListener("message", String.class, (client, msg, ack) -> { // Broadcast to every client in /chat chatNs.getBroadcastOperations().sendEvent("message", msg); }); adminNs.addConnectListener(client -> System.out.println("Admin connected: " + client.getSessionId()) ); // List all clients in a namespace Collection chatClients = chatNs.getAllClients(); System.out.println("Clients in /chat: " + chatClients.size()); // Look up a specific client by session UUID SocketIOClient specific = chatNs.getClient(someUUID); // Auth token listener for Socket.IO v4 namespace auth chatNs.addAuthTokenListener((authToken, client) -> { String jwt = authToken.toString(); boolean valid = validateJwt(jwt); return valid ? AuthTokenResult.SUCCESSFUL : AuthTokenResult.FAILED_AUTHORIZATION; }); // Remove a namespace entirely server.removeNamespace("/chat"); ``` ``` -------------------------------- ### Configure Redisson Store Factory for Redis Clustering in Java Source: https://context7.com/mrniko/netty-socketio/llms.txt Integrate Redisson with Socket.IO to use Redis for distributed session storage and event broadcasting across multiple server nodes. Requires Redisson and Netty Socket.IO dependencies. ```java // --- Redisson (Redis) clustering --- import com.corundumstudio.socketio.store.RedissonStoreFactory; import org.redisson.Redisson; import org.redisson.config.Config; Config redissonConfig = new Config(); redissonConfig.useSingleServer().setAddress("redis://127.0.0.1:6379"); RedissonClient redisson = Redisson.create(redissonConfig); Configuration config = new Configuration(); config.setPort(9092); config.setStoreFactory(new RedissonStoreFactory(redisson)); SocketIOServer server = new SocketIOServer(config); server.start(); // Any broadcast on this node will be propagated to all other nodes // via Redis pub/sub automatically. ``` -------------------------------- ### Configure Netty Socket.IO Cluster with Redisson Source: https://github.com/mrniko/netty-socketio/wiki/How-To:-create-a-cluster-of-netty-socketio-servers-for-broadcasting-messages Instantiate and configure Redisson, then use it to create a `RedissonStoreFactory` for your `SocketIOServer` configuration. This enables message broadcasting across server instances. ```java Config redissonConfig = new Config(); redissonConfig.useSingleServer().setAddress("127.0.0.1:6379"); RedissonClient redisson = Redisson.create(redissonConfig); RedissonStoreFactory redisStoreFactory = new RedissonStoreFactory(redisson); Configuration config = new Configuration(); config.setHostname("localhost"); config.setPort(9092); config.setStoreFactory(redisStoreFactory); SocketIOServer server = new SocketIOServer(config); ``` -------------------------------- ### Implement Authorization Listener Source: https://context7.com/mrniko/netty-socketio/llms.txt Handles client authorization on handshake. Can reject connections or pass data to the client store. Requires `handshakeData` to be available and methods like `isValidToken` and `resolveUserId` to be implemented. ```java config.setAuthorizationListener(handshakeData -> { String token = handshakeData.getSingleUrlParam("token"); HttpHeaders headers = handshakeData.getHttpHeaders(); String origin = headers.get("Origin"); if (token == null || !isValidToken(token)) { // Reject — server responds with HTTP 401 return AuthorizationResult.FAILED_AUTHORIZATION; } // Optionally pass data into the client store on connect Map storeParams = new HashMap<>(); storeParams.put("userId", resolveUserId(token)); return new AuthorizationResult(true, storeParams); }); ``` -------------------------------- ### Manage Namespaces Source: https://context7.com/mrniko/netty-socketio/llms.txt Multiplexes different logical channels over a single server. Each namespace has its own event listeners and broadcast scope. Supports client connection, event handling, and namespace removal. ```java SocketIOServer server = new SocketIOServer(config); // Create a custom namespace SocketIONamespace chatNs = server.addNamespace("/chat"); SocketIONamespace adminNs = server.addNamespace("/admin"); ``` ```java chatNs.addConnectListener(client -> System.out.println("Connected to /chat: " + client.getSessionId()) ); ``` ```java chatNs.addEventListener("message", String.class, (client, msg, ack) -> { // Broadcast to every client in /chat chatNs.getBroadcastOperations().sendEvent("message", msg); }); ``` ```java adminNs.addConnectListener(client -> System.out.println("Admin connected: " + client.getSessionId()) ); ``` ```java // List all clients in a namespace Collection chatClients = chatNs.getAllClients(); System.out.println("Clients in /chat: " + chatClients.size()); ``` ```java // Look up a specific client by session UUID SocketIOClient specific = chatNs.getClient(someUUID); ``` ```java // Auth token listener for Socket.IO v4 namespace auth chatNs.addAuthTokenListener((authToken, client) -> { String jwt = authToken.toString(); boolean valid = validateJwt(jwt); return valid ? AuthTokenResult.SUCCESSFUL : AuthTokenResult.FAILED_AUTHORIZATION; }); ``` ```java // Remove a namespace entirely server.removeNamespace("/chat"); ``` -------------------------------- ### Manage Client Rooms Source: https://context7.com/mrniko/netty-socketio/llms.txt Groups clients for broadcasting messages. Clients can join and leave rooms, and events can be sent to all members of a specific room. Retrieves all rooms a client belongs to. ```java server.addConnectListener(client -> { // Put each client in a room named by a query parameter String room = client.getHandshakeData().getSingleUrlParam("room"); if (room != null) { client.joinRoom(room); System.out.println(client.getSessionId() + " joined room: " + room); } }); ``` ```java server.addEventListener("send_to_room", ChatMessage.class, (client, data, ackRequest) -> { // Broadcast to every client in the room, including the sender server.getRoomOperations(data.getRoom()).sendEvent("chat_message", data); }); ``` ```java server.addEventListener("leave_room", String.class, (client, room, ackRequest) -> { client.leaveRoom(room); System.out.println(client.getSessionId() + " left room: " + room); System.out.println("Room size now: " + client.getCurrentRoomSize(room)); }); ``` ```java // Retrieve all rooms a client belongs to server.addConnectListener(client -> { client.joinRooms(new HashSet<>(Arrays.asList("global", "news"))); System.out.println("All rooms: " + client.getAllRooms()); }); ``` -------------------------------- ### Broadcast Messages to All Clients Source: https://context7.com/mrniko/netty-socketio/llms.txt Sends an event to all connected clients across all namespaces. Ensure the server instance is available. ```java server.getBroadcastOperations().sendEvent("server_announcement", "Maintenance in 5 min"); ``` -------------------------------- ### Broadcast with Acknowledgement Callback Source: https://context7.com/mrniko/netty-socketio/llms.txt Sends an event to clients in a specific room and provides a callback that executes once all clients have acknowledged receipt. Requires a `BroadcastAckCallback` implementation. ```java server.getRoomOperations("vip").sendEvent( "vip_notice", payload, new BroadcastAckCallback(String.class) { @Override public void onClientSuccess(SocketIOClient client, String result) { System.out.println(client.getSessionId() + " acked: " + result); } } ); ``` -------------------------------- ### Add Netty-SocketIO Maven Dependency Source: https://github.com/mrniko/netty-socketio/blob/master/README.md Include this dependency in your project's pom.xml to use the netty-socketio library. ```xml com.corundumstudio.socketio netty-socketio 2.0.13 ``` -------------------------------- ### Room Management Source: https://context7.com/mrniko/netty-socketio/llms.txt Group clients together so events can be sent to all members at once. Clients can join, leave, and broadcast messages within rooms. ```APIDOC ## Room Operations ### Description Manages client subscriptions to rooms for targeted event broadcasting. ### Methods - **client.joinRoom(roomName)**: Adds the client to the specified room. - **server.getRoomOperations(roomName).sendEvent(eventName, data)**: Broadcasts an event to all clients in a specific room. - **client.leaveRoom(roomName)**: Removes the client from the specified room. - **client.getCurrentRoomSize(roomName)**: Returns the number of clients in a room. - **client.joinRooms(Set rooms)**: Adds the client to multiple rooms. - **client.getAllRooms()**: Returns a set of all rooms the client belongs to. ### Request Example ```java server.addConnectListener(client -> { // Put each client in a room named by a query parameter String room = client.getHandshakeData().getSingleUrlParam("room"); if (room != null) { client.joinRoom(room); System.out.println(client.getSessionId() + " joined room: " + room); } }); server.addEventListener("send_to_room", ChatMessage.class, (client, data, ackRequest) -> { // Broadcast to every client in the room, including the sender server.getRoomOperations(data.getRoom()).sendEvent("chat_message", data); }); server.addEventListener("leave_room", String.class, (client, room, ackRequest) -> { client.leaveRoom(room); System.out.println(client.getSessionId() + " left room: " + room); System.out.println("Room size now: " + client.getCurrentRoomSize(room)); }); // Retrieve all rooms a client belongs to server.addConnectListener(client -> { client.joinRooms(new HashSet<>(Arrays.asList("global", "news"))); System.out.println("All rooms: " + client.getAllRooms()); }); ``` ``` -------------------------------- ### Sending Events to a Client Source: https://context7.com/mrniko/netty-socketio/llms.txt Push a named event to a specific connected client, optionally with an acknowledgement callback. ```APIDOC ## SocketIOClient.sendEvent ### Description Pushes a named event to a specific connected client, optionally with an acknowledgement callback. ### Method `client.sendEvent(eventName, data, ackCallback)` ### Parameters - **eventName** (string) - The name of the event to send. - **data** (Object) - The payload of the event. Can be a single object or varargs. - **ackCallback** (AckCallback) - Optional callback to handle acknowledgement from the client. ### Request Example ```java // Simple send (no ack) client.sendEvent("notification", "Your order has shipped!"); // Send with ack callback (waits up to 10 seconds for client confirmation) client.sendEvent("important_event", new AckCallback(String.class, 10) { @Override public void onSuccess(String result) { System.out.println("Client confirmed: " + result); } @Override public void onTimeout() { System.out.println("Ack timed out for " + client.getSessionId()); } }, "payload data" // varargs event data ); // Check writability before sending to avoid queuing on a slow consumer if (client.isWritable()) { client.sendEvent("live_update", somePayload); } ``` ``` -------------------------------- ### Annotation-Based Event Handlers Source: https://context7.com/mrniko/netty-socketio/llms.txt Uses annotations like `@OnConnect`, `@OnDisconnect`, and `@OnEvent` on POJO methods for handling events. Register the POJO using `server.addListeners()`. Ensure `ChatMessage` class has `getRoom()` method. ```java import com.corundumstudio.socketio.annotation.*; public class ChatEventHandler { private final SocketIOServer server; public ChatEventHandler(SocketIOServer server) { this.server = server; } @OnConnect public void onConnect(SocketIOClient client) { System.out.println("Connected: " + client.getSessionId()); } @OnDisconnect public void onDisconnect(SocketIOClient client) { System.out.println("Disconnected: " + client.getSessionId()); } @OnEvent("chat_message") public void onChatMessage(SocketIOClient client, AckRequest ackRequest, ChatMessage data) { server.getRoomOperations(data.getRoom()) .sendEvent("chat_message", client, data); // exclude sender if (ackRequest.isAckRequested()) { ackRequest.sendAckData("ok"); } } } // Register with the server SocketIOServer server = new SocketIOServer(config); server.addListeners(new ChatEventHandler(server)); server.start(); ``` -------------------------------- ### Maven Dependency for Netty SocketIO Source: https://context7.com/mrniko/netty-socketio/llms.txt Add this dependency to your Maven project to include the netty-socketio library. ```xml com.corundumstudio.socketio netty-socketio 2.0.13 ``` -------------------------------- ### Send Events to a Client Source: https://context7.com/mrniko/netty-socketio/llms.txt Pushes a named event to a specific connected client. Supports sending with or without an acknowledgement callback, and checks writability before sending to avoid queuing. ```java // Simple send (no ack) client.sendEvent("notification", "Your order has shipped!"); ``` ```java // Send with ack callback (waits up to 10 seconds for client confirmation) client.sendEvent("important_event", new AckCallback(String.class, 10) { @Override public void onSuccess(String result) { System.out.println("Client confirmed: " + result); } @Override public void onTimeout() { System.out.println("Ack timed out for " + client.getSessionId()); } }, "payload data" // varargs event data ); ``` ```java // Check writability before sending to avoid queuing on a slow consumer if (client.isWritable()) { client.sendEvent("live_update", somePayload); } ``` -------------------------------- ### Broadcast Messages to Specific Rooms Source: https://context7.com/mrniko/netty-socketio/llms.txt Sends an event to clients within a specified room or multiple rooms. Useful for targeted updates. ```java server.getRoomOperations("game-42").sendEvent("game_update", gameState); ``` ```java server.getRoomOperations("room-a", "room-b").sendEvent("alert", "Hello!"); ``` -------------------------------- ### Connection and Disconnection Listeners Source: https://context7.com/mrniko/netty-socketio/llms.txt Register listeners for client connection and disconnection events on the default namespace. Access handshake data and store session-specific information. ```java SocketIOServer server = new SocketIOServer(config); server.addConnectListener(client -> { HandshakeData hs = client.getHandshakeData(); System.out.println("Client connected: " + client.getSessionId() + " from " + hs.getAddress() + " transport=" + client.getTransport()); // Read URL query parameters supplied during connection String token = hs.getSingleUrlParam("token"); System.out.println("Auth token param: " + token); // Store arbitrary session data on the client client.set("userId", 42L); }); server.addDisconnectListener(client -> { Long userId = client.get("userId"); System.out.println("Client disconnected: sessionId=" + client.getSessionId() + " userId=" + userId); }); server.start(); ``` -------------------------------- ### Implement Custom Exception Listener in Java Source: https://context7.com/mrniko/netty-socketio/llms.txt Centralize error handling by implementing the ExceptionListener interface. This allows for custom logic for event, connection, and channel exceptions. ```java config.setExceptionListener(new ExceptionListenerAdapter() { @Override public void onEventException(Exception e, List args, SocketIOClient client) { log.error("Event handler error for client {}: {}", client.getSessionId(), e.getMessage(), e); } @Override public void onConnectException(Exception e, SocketIOClient client) { log.error("Connect error for client {}: {}", client.getSessionId(), e.getMessage(), e); } @Override public boolean exceptionCaught(ChannelHandlerContext ctx, Throwable e) { log.error("Channel exception: {}", e.getMessage(), e); return false; // return true to suppress further Netty error handling } }); ``` -------------------------------- ### Add Global Event Interceptor in Java Source: https://context7.com/mrniko/netty-socketio/llms.txt Attach a global listener to intercept all incoming events before they reach specific data listeners. Useful for logging, rate-limiting, or metrics. ```java server.addEventInterceptor((client, eventName, args, ackRequest) -> { // Logging, rate-limiting, or metrics collection System.out.printf("Event '%s' from %s args=%s%n", eventName, client.getSessionId(), args); }); ``` -------------------------------- ### Enable ReuseAddress in Netty-Socket.IO Configuration Source: https://github.com/mrniko/netty-socketio/wiki/java.net.BindException:-Address-already-in-use Set the reuseAddress option to true in the SocketConfig to prevent 'Address already in use' errors when the server restarts. This allows the server to bind to a port that is in a TIME_WAIT state. ```java Configuration configuration = new Configuration(); SocketConfig socketConfig = configuration.getSocketConfig(); socketConfig.setReuseAddress(true); ``` -------------------------------- ### Broadcast within a Namespace, Excluding Sender Source: https://context7.com/mrniko/netty-socketio/llms.txt Broadcasts a chat message to all clients in the sender's namespace, automatically excluding the sender. Requires a `ChatMessage` class with a `getRoom()` method. ```java sender.getNamespace() .getBroadcastOperations() .sendEvent("chat_message", sender, data); // 'sender' is excluded ``` -------------------------------- ### Spring Integration with SpringAnnotationScanner Source: https://context7.com/mrniko/netty-socketio/llms.txt Automatically detects and registers beans annotated with `@OnConnect`, `@OnDisconnect`, or `@OnEvent` using `SpringAnnotationScanner`. Requires Spring context configuration. ```java import com.corundumstudio.socketio.annotation.SpringAnnotationScanner; import org.springframework.context.annotation.*; @Configuration public class SocketIOConfig { @Bean public SocketIOServer socketIOServer() { Configuration config = new Configuration(); config.setPort(9092); return new SocketIOServer(config); } // Registers SpringAnnotationScanner as a BeanPostProcessor @Bean public SpringAnnotationScanner springAnnotationScanner(SocketIOServer server) { return new SpringAnnotationScanner(server); } } // Any Spring-managed bean with annotations is now auto-detected @Component public class GameEventHandler { @OnConnect public void onConnect(SocketIOClient client) { /* … */ } @OnEvent("move") public void onMove(SocketIOClient client, AckRequest ack, MovePayload move) { /* … */ } } ``` -------------------------------- ### Broadcast with Predicate-Based Exclusion Source: https://context7.com/mrniko/netty-socketio/llms.txt Sends an event to clients that satisfy a given condition, excluding those that do not. The predicate function receives a `SocketIOClient`. ```java server.getBroadcastOperations().sendEvent( "update", client -> client.get("role").equals("guest"), // exclude guests payload ); ``` -------------------------------- ### Registering Custom Event Listeners Source: https://context7.com/mrniko/netty-socketio/llms.txt Register a typed handler for a named Socket.IO event. The payload is automatically deserialized from JSON using Jackson. ```APIDOC ## addEventListener ### Description Registers a typed handler for a named Socket.IO event. The payload is automatically deserialized from JSON using Jackson. ### Method `server.addEventListener(eventName, classOfData, eventHandler)` ### Parameters - **eventName** (string) - The name of the event to listen for. - **classOfData** (Class) - The class of the incoming event payload for deserialization. - **eventHandler** (BiFunction) - A function that takes the client and the deserialized data as input. ### Request Example ```java // POJO for the incoming event payload public class ChatMessage { private String room; private String text; // getters / setters … } server.addEventListener("chat_message", ChatMessage.class, (client, data, ackRequest) -> { System.out.println("Received from " + client.getSessionId() + ": room=" + data.getRoom() + " text=" + data.getText()); // Echo the message back to the sender client.sendEvent("chat_message", data); // Acknowledge receipt if the client requested an ack if (ackRequest.isAckRequested()) { ackRequest.sendAckData("Message delivered", 200); } }); ``` ``` -------------------------------- ### Inspect HandshakeData on Client Connection in Java Source: https://context7.com/mrniko/netty-socketio/llms.txt Access `HandshakeData` from a connected `SocketIOClient` to retrieve details about the initial HTTP request, including headers, URL parameters, and client address. ```java server.addConnectListener(client -> { HandshakeData hs = client.getHandshakeData(); InetSocketAddress remoteAddr = (InetSocketAddress) client.getRemoteAddress(); System.out.println("Remote IP : " + remoteAddr.getAddress().getHostAddress()); System.out.println("Local EP : " + hs.getLocal()); System.out.println("URL : " + hs.getUrl()); System.out.println("Connected : " + hs.getTime()); System.out.println("X-Domain : " + hs.isXdomain()); // All URL query parameters Map> params = hs.getUrlParams(); String version = hs.getSingleUrlParam("v"); // HTTP headers from the initial request HttpHeaders headers = hs.getHttpHeaders(); String userAgent = headers.get("User-Agent"); System.out.println("UA: " + userAgent); }); ``` -------------------------------- ### Register Custom Event Listener Source: https://context7.com/mrniko/netty-socketio/llms.txt Registers a typed handler for a named Socket.IO event. The payload is automatically deserialized from JSON using Jackson. Ensure the POJO class matches the incoming event structure. ```java public class ChatMessage { private String room; private String text; // getters / setters … } server.addEventListener("chat_message", ChatMessage.class, (client, data, ackRequest) -> { System.out.println("Received from " + client.getSessionId() + ": room=" + data.getRoom() + " text=" + data.getText()); // Echo the message back to the sender client.sendEvent("chat_message", data); // Acknowledge receipt if the client requested an ack if (ackRequest.isAckRequested()) { ackRequest.sendAckData("Message delivered", 200); } }); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.