We’ve been working on a fun new library designed to make WebSockets easier for CFML (and BoxLang) developers. WebSockets are incredibly powerful for real-time applications and it’s honestly an area that CF developers have lagged far behind other languages in using. We’ve wanted something easy like Socket.io which can just be dropped into Node apps, but the problem with CF is how it’s deployed typically to a servlet and a library can’t easily modify the behavior of the HTTP listeners, which requires an integration embedded into the servlet itself.
Introducing SocketBox, a new approach to easy peasy websockets that comes in two parts:
- A new WebSocket handler implemented at the HTTP listener level which is now baked into the latest builds of CommandBox 6.1-rc AND the BoxLang MiniServer beta-16 builds. This provides the low-level logic required to negotiate the protocol upgrade and websocket handshake at the HTTP level.
- A new CF module that sits in your application to send and receive messages over the websocket connections.
The HTTP handler portion is quite simple. In CommandBox, you can configure 3 parts of it
- Whether it’s enabled or not (default disabled)
- What URI it will respond to. Default is
yoursite.com/ws
- The path inside your web root to the listener CFC to receive messages through (default
/WebSocket.cfc
Right now the BoxLang Miniserver uses the defaults above with the exception of being enabled by default.
The only hard requirement of using SocketBox is YOU MUST BE RUNNING YOUR SERVER ON COMMANDBOX OR THE BOXLANG MINISERVER! This is because of the special low-level HTTP WebSocket handler we’re providing there. Outside of that, you can use SocketBox on
- Lucee Server apps
- Adobe ColdFusion apps
- BoxLang apps
because there is no specific code or functionality to any particular CF engine. This is because all incoming messages are routed internally to look like a remote CFC method, which is a core feature of all 3 CF engines.
To configure the listener, install SocketBox
CommandBox> install socketbox
SocketBox is laid out as a ColdBox module, but does NOT require ColdBox to use. You can use SocketBox in any CF app.
Next, create your listener CFC in the web root (or whatever location you choose, so long as you configure CommandBox for the custom location)
/WebSocket.cfc
/**
* I facilitate receiving an sending all WebSocket messages.
* I need to be web-accessible, and extend the WebSocketCore class from SocketBox4.
*/
component extends="modules.socketbox.models.WebSocketCore" {
/**
* All incoming websocket messages flow through me.
*
* @message The text of the incoming message.
* @channel The Java channel object representing the user connection.
* Use this object to send messages back to the same channel later.
*/
function onMessage( required String message, required channel ) {
if( message EQ "Ping" ) {
sendMessage( "Pong", arguments.channel );
}
}
}
Your onMessage()
method does NOT need to be remote
. All incoming messages are funnelled through an existing remote method in the superclass and then funneled to your method.
The sendMessage()
method above can be used anywhere in your application, so long as yu have a reference to the channel object of an existing user connection. You can get those by listening to the onConnect()
listener method.
You can send a broadcast message to all connected users like so:
new WebSocket().broadcastMessage( "Don't forget to tip your waiters and waitresses" );
We have lots of plans for SocketBox, including addition of a STOMP core listener which will have topic subscription semantics, auth, and more, but for right now you can start playing around with basic websocket messaging as you wish.
Since any WebSocket discussion is not complete without the obligatory chat room, I have deployed a simple example of SocketBox for you to play with.
https://socketbox-demo.onrender.com/
It’s hosted for free on render.com, so please be patient if it takes a few seconds to spin up. It will go back to sleep after a few minutes if no one is hitting it. Please be polite in the chat-- your messages are visible to anyone using the demo at the same time, so don’t make me regret putting this public
The demo is
- Written in CFML
- Running on Render.com’s free hosting tier
- Using BoxLang 1.0.0-beta16+
- Running on our containerized MiniServer (
ortussolutions/boxlang:miniserver
) - Hosted in this code repo
- Using this SocketBox library
The code is all quite simple. I’m not using any special client side JS libraries, just the native browser support for WebSockets.
If you’re interested in hosting a site on render, check out the render.yml
and Dockerfile
in the root of the demo repo to see how I got it up and running with minimal configuration.
You can also play with this demo locally by cloning the code repo and starting up the site on the latest BoxLang MiniServer, or the latest CommandBox 6.1-rc builds with web.websocket.enable=true
in your server.json
.