diff --git a/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoAdapter.java b/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoAdapter.java index f443cb9..41c7d8d 100644 --- a/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoAdapter.java +++ b/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoAdapter.java @@ -105,4 +105,13 @@ public void broadcast(Packet packet, String[] rooms) throws IllegalArgumentEx * @throws IllegalArgumentException If socket is null. */ public abstract String[] listClientRooms(SocketIoSocket socket) throws IllegalArgumentException; + + /** + * Check whether room is empty + * + * @param room Room name to list sockets in. + * @return boolean whether room is empty + * @throws IllegalArgumentException If room is null. + */ + public abstract boolean isEmptyRoom(String room) throws IllegalArgumentException; } \ No newline at end of file diff --git a/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoMemoryAdapter.java b/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoMemoryAdapter.java index 00eaf59..3f99b0d 100644 --- a/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoMemoryAdapter.java +++ b/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoMemoryAdapter.java @@ -139,4 +139,14 @@ public String[] listClientRooms(SocketIoSocket socket) throws IllegalArgumentExc return new String[0]; } } + + @Override + public boolean isEmptyRoom(String room) throws IllegalArgumentException { + if (room == null) { + throw new IllegalArgumentException("room must not be null."); + } + + Set socketsInRoom = mRoomSockets.get(room); + return socketsInRoom == null || socketsInRoom.isEmpty(); + } } \ No newline at end of file diff --git a/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoNamespace.java b/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoNamespace.java index 04b8dfb..9ff4ba6 100644 --- a/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoNamespace.java +++ b/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoNamespace.java @@ -71,5 +71,17 @@ public final void broadcast(String room, String event, Object... args) throws Il */ public abstract void broadcast(String[] rooms, String event, Object[] args) throws IllegalArgumentException; + /** + * Broadcast a message to all clients in this namespace that + * have joined specified rooms. Optionally, specify sockets to exclude from sending. + * + * @param rooms Rooms to send message to. + * @param event Name of event to raise on remote client. + * @param socketsExcluded List of sockets to exclude from sending or null. + * @param args Array of arguments to send. Supported types are: JSONObject, JSONArray, null + * @throws IllegalArgumentException If event is null or argument is not of supported type. + */ + public abstract void broadcast(String[] rooms, String event, SocketIoSocket[] socketsExcluded, Object[] args) throws IllegalArgumentException; + abstract Map getConnectedSockets(); } \ No newline at end of file diff --git a/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoNamespaceGroupImpl.java b/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoNamespaceGroupImpl.java index 5f38783..17b7075 100644 --- a/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoNamespaceGroupImpl.java +++ b/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoNamespaceGroupImpl.java @@ -2,9 +2,7 @@ import io.socket.engineio.server.Emitter; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; final class SocketIoNamespaceGroupImpl extends SocketIoNamespace { @@ -24,6 +22,13 @@ public void broadcast(String[] rooms, String event, Object[] args) throws Illega } } + @Override + public void broadcast(String[] rooms, String event, SocketIoSocket[] socketsExcluded, Object[] args) throws IllegalArgumentException { + for (SocketIoNamespaceImpl namespace : mChildNamespaces) { + namespace.broadcast(rooms, event, socketsExcluded, args); + } + } + @Override Map getConnectedSockets() { final Map sockets = new HashMap<>(); diff --git a/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoNamespaceImpl.java b/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoNamespaceImpl.java index ed6cc86..56b9874 100644 --- a/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoNamespaceImpl.java +++ b/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoNamespaceImpl.java @@ -4,7 +4,9 @@ import io.socket.socketio.server.parser.Packet; import io.socket.socketio.server.parser.Parser; +import java.util.Arrays; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; @@ -32,6 +34,24 @@ public void broadcast(String[] rooms, String event, Object[] args) throws Illega mAdapter.broadcast(packet, rooms); } + @Override + public void broadcast(String[] rooms, String event, SocketIoSocket[] socketsExcluded, Object[] args) throws IllegalArgumentException { + if (event == null) { + throw new IllegalArgumentException("event cannot be null."); + } + + final Packet packet = PacketUtils.createDataPacket(Parser.EVENT, event, args); + + String[] socketsExcludedIds = socketsExcluded == null ? null : + Arrays.stream(socketsExcluded) + .filter(Objects::nonNull) + .map(SocketIoSocket::getId) + .distinct() + .toArray(String[]::new); + + mAdapter.broadcast(packet, rooms, socketsExcludedIds); + } + @Override Map getConnectedSockets() { return mConnectedSockets; diff --git a/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoSocket.java b/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoSocket.java index 247a8ed..be23866 100644 --- a/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoSocket.java +++ b/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoSocket.java @@ -72,6 +72,7 @@ public interface ReceivedByLocalAcknowledgementCallback { private final HashMap mAcknowledgementCallbacks = new HashMap<>(); private boolean mConnected; + private Object customData; SocketIoSocket(SocketIoNamespaceImpl namespace, SocketIoClient client, Object connectData) { mNamespace = namespace; @@ -184,6 +185,33 @@ public void broadcast(String[] rooms, String event, Object[] args) throws Illega mAdapter.broadcast(packet, rooms, new String[] { getId() }); } + /** + * Broadcast a message to all clients in this namespace that + * have joined specified rooms. Optionally, specify sockets to exclude from sending. + * + * @param rooms Rooms to send message to. + * @param event Name of event to raise on remote client. + * @param socketsExcluded List of sockets to exclude from sending or null. + * @param args Array of arguments to send. Supported types are: JSONObject, JSONArray, null. + * @throws IllegalArgumentException If argument is not of supported type or socketsExcluded is null. + */ + public void broadcast(String[] rooms, String event, SocketIoSocket[] socketsExcluded, Object[] args) throws IllegalArgumentException { + if (event == null) { + throw new IllegalArgumentException("event cannot be null."); + } + + final Packet packet = PacketUtils.createDataPacket(Parser.EVENT, event, args); + + String[] socketsExcludedIds = socketsExcluded == null ? null : + Arrays.stream(socketsExcluded) + .filter(Objects::nonNull) + .map(SocketIoSocket::getId) + .distinct() + .toArray(String[]::new); + + mAdapter.broadcast(packet, rooms, socketsExcludedIds); + } + /** * Send data to remote client. * @@ -270,6 +298,20 @@ public synchronized void leaveAllRooms() { mRooms.clear(); } + /** + * Set customData object. + */ + public void setCustomData(Object customData) { + this.customData = customData; + } + + /** + * Get customData object. + */ + public Object getCustomData() { + return this.customData; + } + /** * Register listener for all user events. *