SocketIONamespaceImpl.java 7.98 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  org.apache.sling.commons.json.JSONArray
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.granite.socketio.impl;

import com.adobe.granite.socketio.SocketIOEmitter;
import com.adobe.granite.socketio.SocketIONamespace;
import com.adobe.granite.socketio.SocketIOSocket;
import com.adobe.granite.socketio.impl.Packet;
import com.adobe.granite.socketio.impl.PacketType;
import com.adobe.granite.socketio.impl.SocketIOSocketImpl;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.sling.commons.json.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SocketIONamespaceImpl
implements SocketIONamespace {
    private static final Logger log = LoggerFactory.getLogger(SocketIONamespaceImpl.class);
    private final ConcurrentMap<String, SocketIOSocket> sockets = new ConcurrentHashMap<String, SocketIOSocket>();
    private final Map<String, Set<String>> rooms = new HashMap<String, Set<String>>();
    private final String name;
    private final EmitterImpl emitter;
    private final ReadWriteLock roomsLock;

    public SocketIONamespaceImpl(String name) {
        this.emitter = new EmitterImpl(null, null);
        this.roomsLock = new ReentrantReadWriteLock();
        this.name = name;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public Map<String, SocketIOSocket> getConnected() {
        return Collections.unmodifiableMap(this.sockets);
    }

    @Override
    public SocketIOSocket getSocket(String id) {
        return this.sockets.get(id);
    }

    @Override
    public /* varargs */ SocketIOEmitter emit(String eventName, Object ... arguments) throws IOException {
        return this.emitter.emit(eventName, arguments);
    }

    @Override
    public SocketIOEmitter emit(String eventName, JSONArray arguments) throws IOException {
        return this.emitter.emit(eventName, arguments);
    }

    @Override
    public /* varargs */ SocketIOEmitter to(String ... room) {
        return this.emitter.to(room);
    }

    public void bind(SocketIOSocketImpl socket) {
        if (this.sockets.put(socket.getId(), socket) == null) {
            log.debug("[{}] bind to '{}'. size={}", new Object[]{socket.getId(), this.name, this.sockets.size()});
        } else {
            log.warn("Socket {} was already bound to namespace {}.", (Object)socket.getId(), (Object)this.name);
        }
    }

    public void unbind(SocketIOSocketImpl socket) {
        if (this.sockets.remove(socket.getId()) == null) {
            log.warn("Socket {} was already unbound from namespace {}.", (Object)socket.getId(), (Object)this.name);
        } else {
            log.debug("[{}] unbind from '{}'. size={}", new Object[]{socket.getId(), this.name, this.sockets.size()});
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    public void join(SocketIOSocketImpl socket, String room) {
        this.roomsLock.writeLock().lock();
        try {
            Set<String> roomSet = this.rooms.get(room);
            if (roomSet == null) {
                roomSet = new HashSet<String>();
                this.rooms.put(room, roomSet);
            }
            if (roomSet.add(socket.getId())) {
                log.debug("[{}] joined '{}'. size={}", new Object[]{socket.getId(), room, roomSet.size()});
            }
        }
        finally {
            this.roomsLock.writeLock().unlock();
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    public void leave(SocketIOSocketImpl socket, String room) {
        this.roomsLock.writeLock().lock();
        try {
            Set<String> roomSet = this.rooms.get(room);
            if (roomSet != null && roomSet.remove(socket.getId())) {
                log.debug("[{}] left '{}'. size={}", new Object[]{socket.getId(), room, roomSet.size()});
                if (roomSet.isEmpty()) {
                    this.rooms.remove(room);
                }
            }
        }
        finally {
            this.roomsLock.writeLock().unlock();
        }
    }

    public SocketIOEmitter createEmitter(String id, boolean include) {
        if (include) {
            return new EmitterImpl(id, null);
        }
        return new EmitterImpl(id, Collections.emptySet());
    }

    private final class EmitterImpl
    implements SocketIOEmitter {
        private final String socketId;
        private final Set<String> selectedRooms;

        private EmitterImpl(String socketId, Set<String> selectedRooms) {
            this.socketId = socketId;
            this.selectedRooms = selectedRooms == null && socketId == null ? Collections.emptySet() : selectedRooms;
        }

        /*
         * WARNING - Removed try catching itself - possible behaviour change.
         */
        private SocketIOEmitter emit(Packet p) throws IOException {
            if (this.selectedRooms == null) {
                assert (this.socketId != null);
                SocketIOSocketImpl s = (SocketIOSocketImpl)SocketIONamespaceImpl.this.sockets.get(this.socketId);
                if (s != null) {
                    s.send(p);
                }
            } else {
                Set ids;
                if (this.selectedRooms.isEmpty()) {
                    ids = SocketIONamespaceImpl.this.sockets.keySet();
                } else {
                    SocketIONamespaceImpl.this.roomsLock.readLock().lock();
                    try {
                        ids = new HashSet();
                        for (String room : this.selectedRooms) {
                            Set roomSet = (Set)SocketIONamespaceImpl.this.rooms.get(room);
                            if (roomSet == null) continue;
                            ids.addAll(roomSet);
                        }
                    }
                    finally {
                        SocketIONamespaceImpl.this.roomsLock.readLock().unlock();
                    }
                }
                for (String id : ids) {
                    SocketIOSocketImpl s;
                    if (id.equals(this.socketId) || (s = (SocketIOSocketImpl)SocketIONamespaceImpl.this.sockets.get(id)) == null) continue;
                    s.send(p);
                }
            }
            return this;
        }

        @Override
        public /* varargs */ SocketIOEmitter emit(String eventName, Object ... arguments) throws IOException {
            JSONArray data = new JSONArray();
            data.put((Object)eventName);
            for (Object arg : arguments) {
                data.put(arg);
            }
            Packet p = new Packet(PacketType.EVENT, SocketIONamespaceImpl.this.name, -1, data, 0);
            return this.emit(p);
        }

        @Override
        public SocketIOEmitter emit(String eventName, JSONArray arguments) throws IOException {
            JSONArray data = new JSONArray();
            data.put((Object)eventName);
            for (int i = 0; i < arguments.length(); ++i) {
                data.put(arguments.opt(i));
            }
            Packet p = new Packet(PacketType.EVENT, SocketIONamespaceImpl.this.name, -1, data, 0);
            return this.emit(p);
        }

        @Override
        public /* varargs */ SocketIOEmitter to(String ... room) {
            HashSet<String> newRooms = new HashSet<String>();
            newRooms.addAll(Arrays.asList(room));
            if (this.selectedRooms == null) {
                return new EmitterImpl(null, newRooms);
            }
            newRooms.addAll(this.selectedRooms);
            return new EmitterImpl(this.socketId, newRooms);
        }
    }

}