isapir / lucee-websocket

Enables server WebSockets for Lucee via JSR-356 compliant servlet containers (e.g. Tomcat 8, Jetty 9.1, etc.)
GNU Lesser General Public License v2.1
17 stars 6 forks source link

getChannels returns an empty collection when called from onClose() #19

Open jjakob opened 4 years ago

jjakob commented 4 years ago

This should be documented in the Websocket API docs. As mentioned in #11, before #11 was fixed, onClose would return an error:

lucee.runtime.exp.NativeException: The WebSocket session [1] has been closed and no method (apart from close()) may be called on a closed session at org.apache.tomcat.websocket.WsSession.checkState(WsSession.java:782) at org.apache.tomcat.websocket.WsSession.getUserProperties(WsSession.java:727) at net.twentyonesolutions.lucee.websocket.WebSocket.getChannels(WebSocket.java:456) at net.twentyonesolutions.lucee.websocket.connections.ConnectionManager.unsubscribeAll(ConnectionManager.java:193) at 
...

This was due to onClose also calling unsubscribeAll (which is redundant?). It'd also be good to document all methods that can and can't be used from e.g. onClose and all other handlers.

jjakob commented 4 years ago

getChannels could be made to work in onClose, as the following works and gets me the channel id:

var channels = Variables.ws.connMgr.getChannels(); // connectionManager
var id = arguments.websocket.getId();

// keys are channel ids, value is the number of subscribers
for (chanId in channels) {
    if (channels[chanId] > 0) {
        var chan = Variables.ws.connMgr.getChannel(chanId);
        if (isNull(chan)){
            this.log("getchannel returned null!")
        } else {
            // we can't for loop over getsubscribers because it's a java.util.HashMap and lucee can't cast it to [collection], so we use java's iterator
            var wssetiter = chan.getSubscribers().iterator();
            while (wssetiter.hasNext()) {
                if (wssetiter.next().getId() == id){
                    // found our channel id
                    var myId = chanId;
                    break;
                } 
            }
            // no channel id found (not subscribed to any channels)
            var myId = null;
        }
    }
}
jjakob commented 4 years ago

By the way, this is the exception that's thrown when trying to for loop over what getSubscribers returns:

lucee.runtime.exp.CasterException: Can't cast Object type [java.util.HashSet] to a value of type
 [collection]. stack trace: lucee.runtime.exp.CasterException: Can't cast Object type [java.util.HashSet] to a value of type [collection]                                                                  
        at lucee.runtime.op.Caster.toCollection(Caster.java:3959)                                                                                                                                          
        at lucee.runtime.util.ForEachUtil.forEach(ForEachUtil.java:65)                                                                                                                                     

This is probably a bug too, as getSubscribers is unusable without resorting to Java trickery as in the code above. Code that should work (place it in the above post's code), but throws the above exception:

    var wsset = chan.getSubscribers()
    for (ws in wsset) {
        if (ws.getId() == id){
            // found our channel id
            var myId = chanId;
            break;
        } 
    }