This is common practice in asynchronous code that runs outside of the regular requests. It is exactly the same as onSessionEnd(sessionScope, applicationScope)
is used, since it is also running async outside of the standard requests. See onSessionEnd
CFML developers have been using methods like that for about a decade now, and it may “feel” strange at first, but once you understand how it works it feels very natural coding that way.
Keep in mind that the WebSocket connections are not running inside any Servlet request, so you do not have a valid Request
or Session
, or even Application
object.
The extension is build on top of the JSR-356 standard - JSR 356, Java API for WebSocket - The Java Specification for WebSockets. That allows it to be small (the extension jar is about 30kb), and portable (because the fact that it is written in accordance with the specification it can be added easily to any Servlet container that adheres to the standards, e.g. Tomcat, Jetty, WildFly, etc).
Lucee is a Servlet (so is ACF, by the way), and it runs inside a Servlet container like Tomcat, Jetty, etc. The extension does not open the socket server by itself. Instead, it relies on the JSR-356 specification API and requests the Servlet container to open that socket connection.
From that point, any incoming WebSocket connection go directly to the Servlet container, and from there to the extension – completely bypassing Lucee. In order to still get the Session
and Application
scopes I had to do some “hacking” as I referred to it in a different thread.
The whole idea behind WebSockets is that they keep the connection open, not having to open a new connection (which requires http handshake, onRequestStart(), onSessionStart(), and a bunch of other overhead). That allows WebSocket messages to be sent and received very fast because the connection is kept opened from before.
The WebSocket API is therefore asynchronous, and event driven. That means that you can not have in a WebSocket event a direct access to the Request scope, or the Session scope. It also means that from your regular request processing, where you do have the Request
and Session
scope, you can not have a direct access to the WebSocket, because the events, e.g. onMessage()
can fire at any time.
You could (Don’t Do This) keep a reference to the WebSocket in your Session scope, but that would likely lead to a memory leak because it will probably maintain references to a lot of dead objects unless you really clean up behind you.
Adding WebSockets to the core will most likely only mean that you do not need to install the extension. WebSockets are separate connections and do not run in the same model to regular Requests.
What can help is to add an API to Lucee which will expose the Session store, so that I wouldn’t need to resort to “hacking”, but that will probably not change anything in the way that you use the WebSockets.
I’ve seen other implementations that use WebSockets in an Event Gateway. I’m not sure what the benefit is, but if you prefer the way they work then perhaps those implementations would work better for you.
That again has to do with the Session management. If Lucee will add an API as mentioned above then it will be much easier to implement this. Otherwise we will need a separate implementation for each Cluster implementation, which is not something that I have the resources to support.
There is no restriction for a single context. I have not experienced that issue myself, but TBH also didn’t have much time to spend on it as of yet.
There is a restriction on Application Names. You can not have the same Application Name in more than one context because of the way that I had to “hack” my way into the Session information. But:
That is actually something that I thought of too, but it has not been thoroughly tested so I didn’t even mention it in the documentation, so consider it experimental:
You can set for the endpoint the host + endpoint, e.g. WebsocketRegister("www.21solutions.net/ws/echo", someListener)
, and that should give you isolation between different contexts with the same Application Name.
Again, it has not been tested thoroughly, and I’m not sure, for example, if you need to add the port number to the hostname, e.g. 8080
or not, especially when you front your Servlet container with a Web server like httpd
or nginx
.