-
Notifications
You must be signed in to change notification settings - Fork 6
Example Chat
This example shows how to write a multi-channel Chat Server using the Lucee WebSocket Extension. The example consists of 3 files, but its core is the file ChatListener.cfc
.
In this example we use the path-parameter {channel}
in the endpoint (/ws/chat/{channel}
), which automatically subscribes every incoming connection to the channel
specified by the URL's path parameter, e.g. a connection to /ws/chat/support
will be subscribed to the channel support
.
To run the example, call index.cfm
with a username URL parameter to set the username, e.g. index.cfm?username=Lucy
, and a an optional channel
parameter, e.g. index.cfm?username=Lucy&channel=support
.
Then use the JavaScript object wschat
according to the JavaScript WebSocket API
The main file in this example is ChatListener.cfc
which implements the Listener Component API:
/** ChatListener.cfc */
component {
/**
* Ensures that we have a valid Session.username, and notifies the channel
* subscribers that the user connected
*/
function onOpen(websocket, endpointConfig, sessionScope, applicationScope){
if (isEmpty(arguments.sessionScope.username ?: ""))
return false; // returing false will reject the connection
this.notifyChannel(
arguments.websocket
,{
from : "<server>"
,message: "#arguments.sessionScope.username# connected"
}
);
}
/**
* Notifies the channel subscribers to the channel that the user has disconnected
*/
function onClose(websocket, closeReason, sessionSCope, applicationScope){
this.notifyChannel(
arguments.websocket
,{
from : "<server>"
,message: "#arguments.sessionScope.username# disconnected"
}
);
}
/**
* Broadcasts the message to the channel's subscribers
*/
function onMessage(websocket, message, sessionScope, applicationScope){
this.notifyChannel(
arguments.websocket
,{
from : arguments.sessionScope.username
,message: arguments.message
}
);
}
/**
* This is a helper method that adds a timestamp to the data, serializes
* it as JSON, and broadcasts it to all of the subscribers to the channel
* of this websocket connection
*/
private function notifyChannel(websocket, data){
var chanId = arguments.websocket.getPathParameters().channel;
var connMgr = arguments.websocket.getConnectionManager();
arguments.data.channel = chanId;
arguments.data.timestamp = getTickCount();
connMgr.broadcast(chanId, serializeJson(arguments.data));
}
}
As before, we use Application.cfc's onApplicationStart() to register the websocket endpoint, /ws/chat/{channel}
, with an instance of ChatListener.cfc
.
component {
this.name = "websocket_chat";
function onApplicationStart(){
WebsocketRegister("/ws/chat/{channel}", new ChatListener());
}
}
This is a simple page that creates a JavaScript WebSocket client and connects to the server:
<cfscript>
/** ensure that we have Session.username and set a default channel */
if (!isNull(URL.username))
Session.username = URL.username;
if (isEmpty(Session.username ?: "")){
echo("<p>Session.username is not defined. Set it using the URL parameter username, e.g. ?username=Lucy");
abort;
}
param name="channel" default="default";
</cfscript>
<cfoutput>
<!--- JavaScript follows !--->
<script>
var channel = "#channel#";
var endpoint = "/ws/chat/" + channel;
var protocol = (document.location.protocol == "https:") ? "wss://" : "ws://";
var wschat = new WebSocket(protocol + document.location.host + endpoint);
var log = function(evt){
console.log(evt.data ? JSON.parse(evt.data) : evt);
};
wschat.onopen = log;
wschat.onmessage = log;
wschat.onerror = log;
wschat.onclose = log;
document.title = `#Session.username# on ${channel}`;
document.write(`<p>[wschat] connected to "${channel}" as "#Session.username#"`);
</script>
</cfoutput>
Watch Chat Server Example Video Tutorial at: