Step
The following procedures let you create a broadcast setup:
|
Procedure |
Description |
---|---|---|
1 |
Define communication channels in the Application.cfc |
Client can subscribe or publish to a pre-defined set of channels. To listen to the channel, first register it at the application level. |
2 |
Create WebSocket object using the cfwebsocket tag in your CFM template |
Creates WebSocket connection with all required properties automatically, and wraps it in a JavaScript object that can invoke various JavaScript methods. The tag internally identifies the IP address and port of the server. |
3 |
Implement the business logic using the JavaScript functions provided by the WebSocket object |
On runtime, you can make use of the supported JavaScript functions for example, subscribe or publish to achieve your business goals. |
Defining a communication channel
Specify the following settings in the Application.cfc to define the communication channel:
{ this.name="testapp"; this.wschannels=[{name = channelName,cfclistener= channel_listener_CFC}]; }
Description
Specify the channel name.
Though you can use any number of sub-channels, you do not specify them. They are dynamically created.
- If necessary, specify the ColdFusion channel listener CFC, the component responsible for creating the channel. If not specified, the default ChannelListener.cfc, available in wwwroot\CFIDE\websocket directory is called.For further details, see Using channel listener functions below.
Creating WebSocket object using cfwebsocket
The new ColdFusion tag {{cfwebsocket }}lets you create the WebSocket object in your CFM template. The tag creates a reference to the WebSocket JavaScript object at the client-side.
Syntax
name="websocketName" onMessage="JavaScript function name" onOpen="JavaScript function name" onClose="JavaScript function name" onError="JavaScript function name" useCfAuth=true|false subscribeTo="channel_list">
Attribute
Attribute |
Req/Opt |
Descriptions |
---|---|---|
name |
Required |
The name of the WebSocket object. This is the reference to the JavaScript objects that are used to call WebSocket JavaScript functions. |
onMessage |
Required |
The JavaScript function that is called when the WebSocket receives a message from the server. The function requires one argument. |
onOpen |
Optional |
The JavaScript function that is called when the WebSocket establishes a connection.The function does not require any arguments. |
onClose |
Optional |
The JavaScript function that is called when the WebSocket closes a connection.The function does not require any arguments. |
onError |
Optional |
The JavaScript function that is called if there is an error while performing an action over the WebSocket connection. The function requires one argument. |
usecfAuth |
Optional |
If set to true (default), authentication is not required for WebSocket connection (provided they have already logged in to the application). This is the default value.If false, to authenticate, you have to use the javaScript function authenticate. |
subscribeTo |
Optional |
Comma-separated list of channels/subchannels to subscribe to. You can specify any or all channels set in the Application.cfc. |
Usage
By specifying the attribute name, for example, mycfwebsocketobject (as in the following example), you create a JavaScript object. The JavaScript object can be used to call various JavaScript functions which you use for the WebSocket communication.
Example
In the following example,
- The user is automatically subscribed to the channel stocks.
- You have specified the channel name in the Application.cfc.
- Uses the default channel listener (as you have not specified a custom channel listener).
In the Index.cfm, you specify the channels to which the user can automatically subscribe to (using the attribute subscribeTo) and also define the message handler.
Application.cfc
{ this.name="websocketsampleapp1"; this.wschannels=[{name="stocks"}]; }
Index.cfm
<script type="text/javascript"> /* mymessangehandler function recieves all messages that comes via WebSocket. This function requires one argument. */ function mymessagehandler(messageObject) { //JavaScript messageobject is converted to a string. var message = ColdFusion.JSON.encode(messageObject); var txt=document.getElementById("myDiv"); txt.innerHTML +=message +"<br>"; } </script> <cfwebsocket name="mycfwebsocketobject" onmessage="mymessagehandler" subscribeto="stocks" > <cfdiv id="myDiv"></cfdiv>
The code creates a JavaScript WebSocket object named mycfwebsocketobject. If the server sends a message, it calls mymessagehandler function.Since you have specified subscribeTo in the cfwebsocket tag, the WebSocket object automatically subscribes you to the channel stocks.
Using the WebSocket JavaScript functions
After you create a JavaScript WebSocket object using the cfwebsocket tag, you can use it to call the following JavaScript functions:
Function |
Description |
Syntax |
Parameters |
|
---|---|---|---|---|
authenticate |
Authenticates the user to a specific channel. Returns true if the connection is open. |
authenticate(id, password)
mycfwebsocketobject.authenticate("Ben", "password") |
|
|
subscribe |
Lets the client subscribe to a specific channel. You can send additional information such as age of the user (in the form of custom_header JavaScript object) to the server. This information can be used to take a decision on whether to let the client subscribe or not. Returns true if the connection is open. |
subscribe(channel[, custom_header][, messageHandler])
mycfwebsocketobject.subscribe(channel) |
|
|
publish |
Publishes the message to the channel. If the message is not available use the function invokeAndPublish.Message can be passed in any JavaScript data type (such as array, string, int, or a key-value pair) as a JavaScript object.You can send additional information (in the form of custom_header). The information can be used to decide if to allow the client to publish, for example Only platinum members have rights to publish. Returns true if the connection is open. |
For example,
publish(channel, message [, custom_header]) mycfwebsocketobject.publish("stocks",msg) |
|
|
invokeAndPublish |
Invokes a specified method in a CFC file to generate the message that has to be published. Used in scnearios where you have raw data (that needs to be processed) to create a message. Returns true if the connection is open. |
For example,
invokeAndPublish(channel, cfcName, functionName [, argumentsArray] [, custom_header]) mycfwebsocketobject.invokeAndPublish(ch, "employee", "getEmployeeDetails", ["eid_1"]) |
|
|
getSubscriberCount |
Provides the number of subscribers for a specific channel. Returns true if the connection is open. |
For example,
getSubscriberCount(channel) mycfwebsocketobject.getSubscriberCount("stocks") |
|
|
getSubscriptions |
Provides all channels the client is subscribed to, as a JavaScript array. Returns true if the connection is open. |
getSubscription() |
Supports inline call back functionality to receive asynchronous response. |
|
openConnection |
Opens a WebSocket connection (if not already open). Returns undefined on successful completion. |
openConnection() |
|
|
isConnectionOpen |
Verifies whether the WebSocket connection is open. Returns true if the connection is open. |
isConnectionOpen() |
|
|
closeConnection |
Closes a WebSocket connection. Returns undefined on successful completion. The boolean value represents the status of the call only for openConnection and closeConnection. |
closeConnection() |
|
|
unsubscribe |
Unsubscribes a client from the specified channel. After the client unsubscribes, the messages in the channel are not published to the client. Returns true if the connection is open. |
For example,
unsubscribe(channel) mycfwebsocketobject.unsubscribe(channel) |
|
When you use these functions, a boolean value indicating the status of the call or connection is returned. But the result of the call is acknowledged at the message handler side. You can categorize the responses at the message handler using the request type token as shown in the following example: if (token.reqType =="getSubscriberCount). |
Example
The following example illustrates how to use various JavaScript functions.Application.cfc
component { this.name="websocketsampleapp3"; this.wschannels=[{name="stocks"}]; }
Index.cfm
<script> //messagehandler recieves all the messages from websocket function mycbHandler( messageobj) { var message = ColdFusion.JSON.encode(messageobj); var txt=document.getElementById("myDiv"); txt.innerHTML +=message +"<br>"; } //openhandler is invoked when socket connection is function openHandler() { var txt=document.getElementById("myDiv"); txt.innerHTML +="open Handler invoked <br>"; } function subscribeMe() { var channelname = document.getElementById("channelname").value; mywsobj.subscribe(channelname); } function getSubscribers() { var channelname = document.getElementById("channelname").value; mywsobj.getSubscriberCount(channelname); } function unsubscribe_Me() { var channelname = document.getElementById("channelname").value; mywsobj.unsubscribe(channelname); } function publishClient() { var channelname = document.getElementById("channelname").value; var message = document.getElementById("msg").value; mywsobj.publish(channelname,message); } function get_Subscriptions() { mywsobj.getSubscriptions(); } function invokenpublish() { cfcname = document.getElementById("cfcname").value; fnname = document.getElementById("fnname").value; channelname = document.getElementById("channelname").value; mywsobj.invokeAndPublish(channelname, cfcname, fnname); } function invokefn() { cfcname = document.getElementById("cfcname").value; fnname = document.getElementById("fnname").value; channelname = document.getElementById("channelname").value; mywsobj.invoke(cfcname, fnname); } function opensocket() { var txt=document.getElementById("myDiv"); txt.innerHTML+="opening socket"+"<br >"; x=mywsobj.openConnection(); } function stopsocket() { var txt=document.getElementById("myDiv"); txt.innerHTML+="closing socket"+"<br >"; x=mywsobj.closeConnection(); } function checksocket() { var x=mywsobj.isConnectionOpen(); var txt=document.getElementById("myDiv"); txt.innerHTML+=x+"<br >"; } </script> <form name="f"> <!---Define JS websocket object name and messagehandler and openhandler ---> <cfwebsocket name="mywsobj" onMessage="mycbHandler" onOpen="openHandler"/> <br> Subscribe to: <input id="channelname" name="channelname" type="text" value="stocks" > <input id="stocksSubscribe" type="button" value="stocksSubscribe" onclick="subscribeMe();"> <input id="unsubscribeMe" type="button" value="unsubscribeMe" onclick="unsubscribe_Me();"> <input id="getSubscribersCF" type="button" value="getSubscribersCF" onclick="getSubscribers();"> <input id="getSubscriptions" type="button" value="getSubscriptions" onclick="get_Subscriptions();"> <br> Message :<input id="msg" type="text" > <input id="publishMe" type="button" value="publishMe" onclick="publishClient();"> <br> CFC Name: <input id="cfcname" name="cfcname" type="text" value="invokeandpublish" > Function Name: <input id="fnname" name="fnname" type="text" value="publishall" > <input id="invoke_publish" type="button" value="invoke_publish" onclick="invokenpublish();"> <input id="invoke" type="button" value="invoke" onclick="invokefn();"> <br> <input id="stop" name ="Close" type="button" value ="stop" onclick="stopsocket()" > <input id="open" name ="Open" type="button" value ="open" onclick="opensocket()" > <input id="check" name ="Check" type="button" value="check" onclick="checksocket()" > <br> <div id="myDiv"></div> </form>
invokeandpublish.cfc
component
{
public function publishall()
{
return "All Clients";
}
}
Scenarios: Subscribing and publishing
If the users subscribe to a parent channel, automatically they subscribe to all subchannels. If users subscribe to a child channel, they are not subscribed to its parent channel.
The following table elaborates the conditions.
The table shows four clients Client 1, Client 2, Client 3, and Client 4 subscribed to the following channels: Stocks, Stocks.Finance, Stocks.Banks, and Stocks.Finance.Adobe.
Client |
Channel subscribed to |
Receives messages when publishing to Stocks |
Receives messages when publishing to Stocks.Finance |
Receives messages when publishing to Stocks.Banks |
Receives messages when publishing to Stocks. Finance.Adobe |
---|---|---|---|---|---|
Client 1 |
Stocks |
Yes |
Yes |
Yes |
Yes |
Client 2 |
Stocks.Finance |
No |
Yes |
No |
Yes |
Client 3 |
Stocks.Banks |
No |
No |
Yes |
No |
Client 4 |
Stocks.Finance.Adobe |
No |
No |
No |
Yes |
Scenarios: Getting subscriber list
The following table explains the conditions on which you receive the subscriber list when you use the function getSubscribers.
Assume that there are four clients. Each client is subscribed to only one of the following channels (and no client is subscribed to the same channel): Stocks, Stocks.Finance, Stocks.Banks, and Stocks.Finance.Adobe.
Function getSubscribers called with the channel |
Returns the ID of clients subscribed to the following channels |
---|---|
Stocks |
Stocks |
Stocks.Finance |
Stocks.Finance and Stocks |
Stocks.Banks |
Stocks.Banks and Stocks |
Stocks.Finance.Adobe |
Stocks.Finance.Adobe, Stocks.Finnance, and Stocks |
Using channel listener functions
Channel listener is a set of functions that decide the folow of messages to a channel. When a WebSocket object's JavaScript function is called, in turn functions in the channel listener are called. For example, when you call the subscribe function, it calls the allowSubscribe function from the listener CFC.
A channel listener can be:
- Default channel listener: Used if no channel listener is specified while defining the channel in the Application.cfc.
- User-defined channel listener: Used if a channel listener CFC is specified while creating a channel. Update the methods in the channel listener file to implement a specific business logic. Specify a custom channel listener to restrict subscription to a channel or right to publish. You can also use custom channel listener to format messages and decide if the client is eligible to receive message.
Setting up user-defined channel listener
- (You must) Extend the default listener present in webroot/cfide/websocket/ChannelListener as shown in the following code:component extends="CFIDE.websocket.ChannelListener"
- A user-defined channel listener CFC must be in the same directory or subdirectory of the application.
- You can only override the functions specified in the default listener CFC to implement the business logic. All custom functions are ignored.
How the listener functions receive/provide information
The functions in the listener receive or provide information in the following three structs. You can use these three structs to add custom information.
- clientInfo: Information about the client. The following are the values:
- channelName
- clientId: A unique client ID.It can be used for setting additional properties, such as roles.
- connectionTime: Connection time as date object.
- subscriberInfo: A struct that contains custom options passed in the subscribe request. Also contains the object ConnectionInfo as subkey connectionInfo.
- publisherInfo: A struct that contains custom options passed in the publish request. Also contains the object ConnectionInfo as subkey connectionInfo.
The following table lists the WebSocket JavaScript functions and the corresponding function in the channel listener CFC:
WebSocket object JavaScript function |
Function(s) called in the channel listener CFC |
---|---|
subscribe |
allowSubscribe |
unsubscribe |
afterUnsubscribe |
publish |
allowPublish |
invokeAndPublish |
allowPublish |
getSubscribers |
None |
getSubscriptions |
None |
invoke |
None |
openConnection |
None |
isConnectionOpen |
None |
closeConnection |
None |
Channel listener functions
The following table lists the functions in the listener file:
Function |
Descriptions |
Syntax |
Parameters |
---|---|---|---|
allowSubscribe |
Invoked before subscribing to a channel/sub-channel. Used to check if the requested client can be allowed to subscribe to the given channel. If returns true, allows the requested client to subscribe.Properties defined in the object subscriberInfo can be used decide on authorization. |
allowSubscribe(subscriberInfo) |
|
allowPublish |
Called before publishing to a channel/sub-channel. Used to check whether the requested client can be allowed to publish to the given channel. Properties defined in the publisherInfo struct can be used to take the authorization decision. If returns true, allows the requested client to publish. |
allowPublish(publisherInfo) |
|
beforePublish |
Invoked before publishing the message on requested channel/sub-channel. Used to execute a business logic if required and to format messages. |
beforePublish(message, publisherInfo) |
|
canSendMessage |
Invoked before sending the message to a subscribed client.Used to decide whether the message should be sent to a specific client. Called for all clients subscribed to a channel separately. Properties defined in the object subscriberInfo and publisherInfo help you find client's interest in the message. |
canSendMessage(message, subscriberInfo, publisherInfo) |
|
beforeSendMessage |
Invoked before sending the message to a subscribed client. Can be used to format the message as per client requirement before sending. This function is executed for each client. |
beforeSendMessage(message, subscriberInfo) |
|
afterUnsubscribe |
Called after you unsubscribe from a channel/sub-channel. Used to clear the settings if necessary.. |
afterUnsubscribe (subscriberInfo) |
|
Using channel-specific message handler
When you create a WebSocket object, you can define a message handler to manage responses from the server. The handler can manage messages from all the channels. Additionally, while subscribing to a channel, you can define channel-specific message handler.
Example
Application.cfccomponent
{ this.name = "channelspecifichandlerexample"; this.wschannels = [{name="stocks"}, {name="news"}, {name="products"}]; }
index.cfm
<script type="text/javascript"> function stockhandler(stocksmessageobj){ //write appropriate logic here to handle data coming on stock channel if (stocksmessageobj.data != null) { var message = stocksmessageobj.data; var datadiv = document.getElementById("myDiv"); datadiv.innerHTML += "Stock Handler: " + message + "<br />"; } } function newshandler(newsmessageobj){ //write appropriate logic here to handle data coming on news channel if (newsmessageobj.data != null) { var message = newsmessageobj.data; var datadiv = document.getElementById("myDiv"); datadiv.innerHTML += "News Handler: " + message + "<br />"; } } function productshandler(productsmessageobj){ //write appropriate logic here to handle data coming on products channel if (productsmessageobj.data != null) { var message = productsmessageobj.data; var datadiv = document.getElementById("myDiv"); datadiv.innerHTML += "Product Handler: " + message + "<br />"; } } function subscribeMe(){ var channel = document.getElementById("channeloption").value; switch (channel) { case "stocks": mysock.subscribe("stocks", {}, stockhandler); break; case "news": mysock.subscribe("news", {}, newshandler); break; case "products": mysock.subscribe("products", {}, productshandler); break; } } function mycbHandler(messageobj){ var message = ColdFusion.JSON.encode(messageobj); var datadiv = document.getElementById("myDiv"); datadiv.innerHTML += "Message Handler : " + message + "<br />"; } </script> <cfwebsocket name="mysock" onmessage="mycbHandler"/> <form> <select id="channeloption"> <option> stocks </option> <option> news </option> <option> products </option> </select> <input id="subscribe" name="subscribe" value="Subscribe" type="button" onclick="subscribeMe();"> </form> <div id="myDiv"> </div>
PublishMessage.cfm
<cfscript> if(isdefined("form.publish")) WsPublish(#form.channel#, #form.message#); </cfscript> <cfform method="post"> <cfselect name="channel"> <option> stocks </option> <option> news </option> <option> products </option> </cfselect> Message: <input id="message" name="message" type="text"> <cfinput id="publish" name="publish" value="publish" type="submit"> </cfform>
Specifying custom information
The following JavaScript functions subscribe, publish, invokeandpublish and the serverside function WSPublish let you pass custom information (for example age or status) in the form of key-value pairs.
You can use these custom data in the subscriberInfo in the channel listener.
Example 1: Custom information using subscribe
In the following example,
- In the subscribe function, specify the age of the client.
- In the channel listener, specify the age restriction in the allowSubscribe method.
Application.cfc
component { this.name = "customoptionexample"; this.wschannels = [{name="Testchannel", cfclistener="TestListener"}]; }
Index.cfm
<script type = "text/javascript"> function msgHandler(messageobj) { var ouputdiv=document.getElementById("myDiv"); var message = ColdFusion.JSON.encode(messageobj); ouputdiv.innerHTML+=message +"<br >" +"<br>"; } function subscribeMe() { var clientAge = document.getElementById("age").value; TestSocket.subscribe("Testchannel", {age: clientAge}); }</script> <cfwebsocket name="TestSocket" onMessage="msgHandler"/> <br> Age <input id="age" name="age" type="text"> <br> <input id="stocksSubscribe" type="button" value="Subscribe" onclick="subscribeMe();"> <div id="myDiv"></div>
TestListener.cfc
component extends="CFIDE.websocket.ChannelListener" { public boolean function allowSubscribe(Struct subscriberInfo) { if(structKeyExists(subscriberInfo, "age")) if((subscriberInfo.age gt 18)) { return true; } else { return false; } else return false; } }
Example 2: Custom information using publish
The following example illustrates how you communicate bid value data.
- In the function publish, specify the bid value as custom information.
- In the channel listener, specify a condition to validate the bid by comparing it with the current bid value. The message is broadcasted only if the bid is valid.
Application.cfc
component { this.name = "customoptionexample1"; this.wschannels = [{name="bidchannel", cfclistener="bidListener"}]; boolean function onApplicationStart() { application.bidvalue = 1; } }
Index.cfm
<script type="text/javascript"> function msgHandler(messageobj){ if (messageobj.data != null) { var ouputdiv = document.getElementById("myDiv"); var message = messageobj.data; ouputdiv.innerHTML += message + "<br >" + "<br>"; } if (messageobj.code == -1 && messageobj.reqType == "publish") { var ouputdiv = document.getElementById("myDiv"); var message = "Bid amount is less than current bid value"; ouputdiv.innerHTML += message + "<br >" + "<br>"; } } function publishme(){ var bidvalue = document.getElementById("amount").value; var clname = document.getElementById("name").value; var message = "Bid placed by " + clname + " Amount " + bidvalue; TestSocket.publish("bidchannel", message, { value: bidvalue }); } </script> <cfwebsocket name="TestSocket" onmessage="msgHandler" subscribeto="bidchannel"/><br> Bid Amount: <input id="amount" name="amount" type="text"> Name: <input id="name" type="text"> <input id="publishmessage" type="button" value="Publish" onclick="publishme();"> <div id="myDiv"> </div>
bidListener.cfc
component extends="CFIDE.websocket.ChannelListener"{ public boolean function allowPublish(Struct publisherInfo) { if(structKeyExists(publisherInfo, "value")) if((publisherInfo.value gt application.bidvalue)) { application.bidvalue = publisherInfo.value; return true; } else { return false; } else return false; } }
Using selectors
Selectors provide filtering logic when you subscribe to a channel or publish a message.
While subscribing to a channel, a selector is provided as part of the subscriber information struct. For example, a client is subscribed to a channel with a selector product eq abc. Only the messages that contain the publisher information product:abc are published to the subscriber.
Similarly, you can include a selector as part of the publisher information struct while publishing a message. The messages are published to only the subscribers who satisfy the criteria specified in the selector.
For a custom channel listener CFC, you cannot have the canSendMessage method (for the selector to work).
The following example shows how to subscribe to a channel with a selector:
-
Create a channel selectorchannel in the Application.cfc.
{ this.name = "websocketApp1"; this.wschannels = [{name="selectorchannel"}]; }
-
Create a CFM that allows the user to subscribe to the channel, with the selector condition value greater than the specified value, for example you want to see only the stock values above a particular threshold value.
<script type="text/javascript"> function msgHandler(messageobj) { if (messageobj.data != null) { var ouputdiv = document.getElementById("myDiv"); var message = messageobj.data; ouputdiv.innerHTML += message + "<br >" + "<br>"; } } function subscribeMe() { var amt = document.getElementById("amount").value; var selectstring="value gt "+ amt; TestSocket.subscribe("selectorchannel", {selector : selectstring}); document.getElementById("stocksSubscribe").style.display = 'none'; document.getElementById("l1").style.display = 'none'; document.getElementById("l2").style.display = 'block'; document.getElementById("publisme").style.display = 'block'; } function publishme() { var amt = document.getElementById("amount").value; TestSocket.publish("selectorchannel","Value is " +amt,{value: amt}) } </script> <cfwebsocket name="TestSocket" onMessage="msgHandler"/> <br /> <lablel id="l1">Stock value above which you want to recieve message</lablel> <label id="l2" style="display:none;">Value</label> <input id="amount" name="amount" type="text"> <br> <input id="stocksSubscribe" type="button" value="Subscribe" onclick="subscribeMe();"> <input id="publisme" type="button" value="Publish" onclick="publishme();" style="display:none;"> <div id="myDiv"></div>
Specifying WebSocket authentication details
You can specify the authentication details for WebSocket at the application level. An application method OnWSAuthenticate has been added to support application level authentication.
-
In the Application.cfc, define the function onWSAuthenticate.
-
Call the JavaScript function authenticate. This function calls the onWSAuthenticate function.
You cannot restrict authentication to a specific channel. If you do not want to authorize the client to any channels, it can be done using the allowSubscribe function of channel listener.
onWSAuthenticate
Description
Authenticates the user
Syntax
OnWSAuthenticate(username, password, connectionInfo)
Parameters
Parameter |
Description |
---|---|
username |
Name of the user that has to be authenticated. |
password |
Password for the user. |
connectionInfo |
A struct that contains the following keys:
|
Custom keys are also supported. For example, you can specify the user's role, status, or age.The connectionInfo is shared across all the channels for a given WebSocket client. Also, modifications are persisted across all the subscriptions for that client.|
Example
The following example uses the function onWSAuthenticate, validates the user, and associates a user role.
For this example to work, ensure that you implement the user-defined functions.
{ this.name="websocketsampleapp23"; this.wschannels=[{name="stocks",cfclistener="stocksListener"}]; function onWSAuthenticate(username, password, connectionInfo) { //write appropriate logic to fetch user password in funtion checkPassword If(checkPassword(username) eq password) { connectionInfo.authenticated="YES"; //Role is the custom information that you provide connectionInfo.role= "admin"; return true; } else{ connectionInfo.authenticated="NO"; return false; } writedump("#connectionInfo#","console"); } }
Enabling Single sign-on in WebSocket
If already authenticated to the ColdFusion server, you need not enter the credentials while subscribing to a WebSocket channel. You need only specify useCFAuth = "true" in the tag cfwebsocket.
In the following example, a login page is created using the tag cflogin. After authentication, the client is subscribed to a channel. That is, the client does not pass the login credentials while subscribing. Here, the function onWSAuthenticate need not be set up or called using the JavaScript function authenticate.
Example
-
Create a login page using the tag cflogin.
User: <input name="username" type="text" id="username" value="admin"><br> Pass: <input name="password" type="text" id="password"><br> <input type="submit" name="Submit" value="Submit"> </form> <cfif structKeyExists(form,"username")> <cflogout> <cfset r = "user"> <cfif FORM.username is "admin"> <cfset r = "admin"> </cfif> <cflogin idletimeout="1800"> <cfloginuser name = "#FORM.username#" password ="#FORM.password#" roles = #r#> </cflogin> <cfoutput>Authorized user: #getAuthUser()#</cfoutput><br> <cfoutput>Authorized role: #GetUserRoles()#</cfoutput><br> <cflocation url="index.cfm"> </cfif>
-
Create the Application.cfc with a channel shares, and listener channelListener.
{ this.name = "myssoexample"; this.wschannels = [ {name = "sso", cfclistener="ChannelListener"}]; }
-
Create a CFM that allows the user to subscribe to a channel and publish the message.
var mycbHandler = function(msg) { if(msg.data) { var messageObject = msg.data; var txt=document.getElementById("myDiv"); if((messageObject.indexOf("{")!=-1)){ var jsonValue = (new Function( "return( " + messageObject + " );" ))(); if(jsonValue){ txt.innerHTML+="<br>Authenticated : " + jsonValue.authenticated; txt.innerHTML+="<br>UserName : " + jsonValue.username; txt.innerHTML+="<br>Role : " + jsonValue.roles; } } } } var openHandler = function() { mysock.publish("sso","hii"); } </script> <form name="f"> <cfwebsocket name="mysock" onMessage="mycbHandler" subscribeto="sso" onOpen="openHandler" useCFAuth="yes"/> <div id="myDiv"></div> </form>
-
Create a ColdFusion listener file that returns the subscriber information while publishing.
{ public any function beforeSendMessage(any message, Struct subscriberInfo) { writedump(var=subscriberInfo.connectionInfo, output="console"); return subscriberInfo.connectionInfo; } }
Server- side APIs
WebSocket server-side APIs allow a CFC to communicate with a channel or a specific client. For example, when a message is received from the client, the server sends a specific message.
The following table details the server-side functions:
Function Name |
Syntax |
Description |
---|---|---|
WSgetSubscribers |
WSgetSubscribers (channel) |
Returns an array of struct with clientID and subcriberInfo as the keys. |
WSPublish |
WSPublish(channel, message [, filterCriteria]) |
Sends messages to a specific channel. Optionally, you can specify a filter criteria struct. |
WSGetAllChannels |
WSGetAllChannels () |
Provides all the channels defined in the Application.cfc as an array. |
Interpreting the Server response
The following is a sample response that you receive from the server:
{"clientid":2077108630,"ns":"coldfusion.websocket.channels","reqType":"subscribe","code":0,"type":"response","msg":"ok"}
The table explains the response keys:
Key |
Description |
---|---|
clientid |
Unique ID assigned to a client. |
ns |
ColdFusion WebSocket namespace |
reqType |
The type of request represented by the JavaScript functions (for example, publish, or invokeandpublish). |
code |
See <code section> |
type |
Either response or data.
|
msg |
Applies to responses; ok if successful. On failure, returns the cause of failure. |
subscriberCount |
An integer that stands for the subscriber count. |
channels |
Applies to getSubscriptions, list of all subscribed channels. |
data |
Message is conveyed through data. |
publisherID |
Client ID of the publisher. If the message is from WSPublish, the ID is 0. |
channelname |
Name of the channel. |
The following is a sample subscribeto response sent to the message handler:
{"clientid":2077108664,"ns":"coldfusion.websocket.channels","channelsnotsubscribedto":"stocks.a","reqType":"subscribeTo","code":0,"type":"response","msg":"Subscription failed for channel(s) 'stocks.a'.","channelssubscribedto":"stocks"}
In this case, you have the key channelssubscribedto and channelsnotsubscribedto which applies to scenarios related to the attribute subsscribeTo in the tag cfwebsocket.