Pages

Showing posts with label Websocket. Show all posts
Showing posts with label Websocket. Show all posts

Tuesday, April 24, 2012

ColdFusion WebSocket Part5 : Publish Workflow

Channel Listener CFC is the Control Panel for your ColdFusion WebSocket application.
All the data that is published in your channel passes through your Channel Listener CFC. In this blog post I will  explain the various Channel Listener functions that are called when a data is published.

A Channel Listener CFC is associated with a  channel. All the sub-channels of that channel also will be controlled by the same Channel Listener CFC.To see sample code on how to associate  a channel  with a Channel Listener CFC check my previous blog entry
Consider a scenarios where you have four clients C1 , C2, C3 and C4.

Consider a case where News is the main channel. Sports and Politics are sub-channels of News. Tennis is a sub-channel of sports.
C1 is subscribed to News
C2 is subscribed to News.Sports
C3 is subscribed to News.Sports.Tennis
C4 is subscribed to News.Politics.



Whenever data has to be published over the channel, four Channel Listener functions are called internally.

  1. AllowPublish - Verifies if the publisher has the right to publish. If this function returns true, the message is eligible to be published.
  2. BeforePublish- This method can be used to format the message.
  3. CanSendMessage- This method is executed for each client. This function validates if each of the clients is eligible to receive the message.
  4. BeforeSendMessage-This method is executed for each client. This method can be used to format the message differently for each client.
These functions are called in a predefined order and a developer or user has no control over the order of function call. Developers can customize the logic inside these channel Listener functions to implement any business logic.

See the following diagram which shows the flow of data as well as the order of function calls during a data publish.





























The above diagram also explains how different clients receive data.
For example C2 - subscribed to  News sports will receive any data that comes on News.Sports and its sub-channels(In this case News.Sports.Tennis).
C2 will not receive data on any sibling channel(News.Politics) or parent channel(News).
Also you can see that C1 subscribed to News will receive data on all channels.

For more reference and code samples on ColdFusion WebSocket see the previous entries in this ColdFusion WebSocket blog series



Sunday, March 11, 2012

ColdFusion WebSocket Part4:Restricting Right to Publish


The very first and easy step to setup WebSocket is to use the default Channel Listener as I described in my first blog entry. But if you need to implement business logic to control the WebSocket system in your application you will have to use a custom Channel Listener CFC. Channel Listener has six methods which can be used to control who will publish/receive data as well as how to present data to different users.
In this blog I am explaining about how to control who all can publish data.
Consider the case of a forum. You have three types of users-Moderators, Members and Guests. Mostly you don't want guests to publish messages.
Let’s try to implement this restriction in your WebSocket Application.
You need a custom Channel Listener CFC. So let’s specify that in your Application.cfc



component
{
 this.name="forumapp";
 this.wschannels=[{name="forum",cfclistener="forumListener"}];
        
}

In a real-life application you might associate the type of user based on the credentials given during authentication. Here in my index.cfm, I am specifying the membership type of the user as a custom option while subscribing to the channel(See highlighted code).

<script type="text/javascript">
 function mymessagehandler( msgobj)
 {
  var message = ColdFusion.JSON.encode(msgobj);

  if(msgobj.data!= null)
   message=msgobj.data;
  else
  switch(msgobj.reqType)
  {
   case "welcome":
      message="Socket Connection established";
      break;
    case "subscribe" :
     message ="Subscription successful";
      document.getElementById("subscribeme").disabled=true;
      break;
       case "publish" :
     message ="Message Published";
      break;
   }
     var txt=document.getElementById("myDiv");
     txt.innerHTML +=message  +"<br>";
 }
 
 function publishmessage()
 {
  var msg = document.getElementById("message").value;
  mycfwebsocketobject.publish("forum",msg );
 }
 
 function subscribe()
 {
  
   var usertype= document.getElementById("usertype").value;
   // Type of user is Guest/Moderator/Member as user chooses in the form
   mycfwebsocketobject.subscribe("forum",{utype:usertype});
 }
 
 function myerrhndler(errobj)
 {
  var message=ColdFusion.JSON.encode(errobj);
  switch(errobj.reqType)
  {
   case "welcome":
      message="Socket Connection not established";
       break;
    case "subscribe" :
     message ="Subscription Failed";
      break;
       case "publish" :
     message ="Publish Failed";
      break;
   }
     var txt=document.getElementById("myDiv");
     txt.innerHTML +=message  +"<br>";
 }

</script>

<cfwebsocket name="mycfwebsocketobject"onmessage="mymessagehandler" onerror="myerrhndler">

<cfform >
Status:  <select id= "usertype">
 <option value="Guest">Guest</option>
 <option value="Moderator">Moderator</option>
 <option value="Member">Member</option>
</select>
<input id="subscribeme" type="button" value="Connect ME to Forum" onclick="subscribe();"><br>
  
Message: <input id ="message" type="text" >
 <input type="button" onclick="publishmessage();" value="Publish Message">
 
</cfform>
<cfdiv id="myDiv"></cfdiv>

We have specified forumListener as the name of ChannelListnter for the channel forum in our Application.cfc Let’s try  to implement the logic to restrict the right to publish in the forumListener.CFC. Here we are overriding two methods- allowSubscribe,allowPublish of the default Channel Listener to implement this restriction
component extends="CFIDE.websocket.ChannelListener"
{
  public boolean function allowSubscribe(Struct subscriberInfo)
   {
     if(structKeyExists(subscriberInfo,"utype"))
       {
        //Validating if a user has publish right & adding a new key to ConnectionInfo 
          if(subscriberInfo.utype eq "Moderator" or subscriberInfo.utype eq "Member" )
         subscriberInfo.connectioninfo.havepublishright="true";
       return true;
       }
   
    return false;
   }
  
   public boolean function allowPublish(Struct publisherInfo)
   {
       if(structKeyExists(publisherInfo.connectioninfo,"havepublishright"))
         if(publisherInfo.connectioninfo.havepublishright)
            return true;
    return false;
   }
 
}

You can download this complete example from here

We have implemented these functions keeping in my mind many application scenarios. If you are stuck at some point as to how to implement particular business logic, it would be worth a look at the ChannelListener functions. In the next blog I will try to explain more on the usage of different Channel Listener functions

For more reference and code samples on ColdFusion WebSocket see the previous entries in this ColdFusion WebSocket blog series



Tuesday, February 28, 2012

ColdFusion WebSocket Part3: Interpreting response

In the previous blog, we discussed how to publish messages. Here, let me explain how to interpret ColdFusion WebSocket responses.

Most of the ColdFusion WebSocket responses are asynchronous, which essentially means that  the response to your WebSocket method calls (such as getSubscriberCount, getSubscriptions, publish, invokeAndPublish, or invoke) come to message handler.
Look at the sample snippet:
var cnt= mywsobj.getSubscriberCount(channelname);
Here, if you expect to get the value of number of subscribers on the channel in the variable "cnt", you are wrong. The response to this WebSocket call comes to your message handler and you have to extract data from there.
Since there are different types of responses and all of them come to the message handler. The application developer has to interpret each response, figure out the operation that triggered, and show the response appropriately.
Let us now try to crack the responses received.
In the examples given in my previous blog post, I used ColdFusion.JSON.encode inside message handler to convert the JavaScript object to a string so that you can see all keys and values of the messageobject.Here we are going to categorize the responses received.
Firstly, let us divide the messages that come to your WebSocket object in two ways depending on the value of code key.
  • If code key is a 0 , it's a successful message.
  • If the code key is -1 or 4001, it's a failure message.
All responses with code 0 will come to the message handler. If you have specified an error handler, all responses with code -1 and 4001 go to the error handler. If  error handler is not specified, all responses go to the message handler.

In the example, we have both message handler and error handler. You can use this code in the message handler. Here messageobj is the argument of message handler function.

if(messageobj.type == "data")
      message=messageobj.data;
else
if (messageobj.type == "response") {
switch(messageobj.reqType)
{
case 'welcome' : 
message="Websocket connection Established";
        break;

case "subscribe" : 
message="Subscription successfull";
        break;

   case "getSubscriberCount" : 
message="No:of subscribers= " + messageobj.subscriberCount;
        break;

   case "getSubscriptions" : 
       if (messageobj.channels.length >= 1) {
message=" You have subscribed to "
for (var j = 0; j < messageobj.channels.length; j++)
{
if(j>0) message +=", ";
message +=   messageobj.channels[j].id;
}
}else message ="You have not subscribed to any channels"
       break;

   case "publish":
       message="Message successfully published";
break;

   case "invokeAndPublish":
       message="Method invoked and message successfully published";
break;

   case "invoke":
        message="Method invoked <br />" ;
message=messageobj.data +"<br />";
break;

   default: message = ColdFusion.JSON.encode(messageobj);
break;
}
}

In the code, I have just customized the message that needs to be displayed for each kind of response.
Instead, you can call different JavaScript functions to update your UI controls with appropriate data.
Also, you can use similar code in error handler to handle error situations.
Download this basic code sample which you can use to perform almost all  WebSocket operations. It also displays customized message for each response.

Hope you are more and more convinced that ColdFusion WebSocket is easy and effective. I will try to post some advanced concepts in the next few blogs.




Wednesday, February 22, 2012

ColdFusion WebSocket Part2:How do I publish Messages?

One major advantage of using ColdFusion WebSocket  is that it enables you to send data to multiple clients at one go.That is, the server can publish message to multiple clients and each client can publish message to multiple clients.
So lets get familiar with the different ways to publish data.

  • Publish from server: If you want to do a publish from ColdFusion server you need a CFML function, and that function is wsPublish.
  • Publish from Client:When a client wants to publish a data, you need a JavaScript function.This can either be publish or invokeAndPublish methods associated with a ColdFusion WebSocket object.


Using ColdFusion Function:
Here is a sample code to publish a simple message from Server to the channel -publishdemochannel.
Wspublish("publishdemochannel","Welcome to publishdemochannel");
Instead of the simple message you can also publish different types of data, like array, struct and query using wspublish.

Using JavaScript Methods:
ColdFusion WebSocket object has got two methods- publish and invokeAndPublish which can be used to publish message from client side. If you are using a simple JavaScript publish, you should have the message that needs to be published. You can use  invokeAndPublish, if you have a function defined  in your cfc which will be able to provide the message that needs to be published.

JavaScript  publish:
Once you have created your JavaScript websocket object using cfwebsocket tag you can invoke Javascript publish method to publish a messages over channel/subchannel.
This can be done in your JavaScript code block For example,
mycfwebsocketobject.publish("publishdemochannel","My test message to publishdemochannel" );

Here we are publishing a simple String. You can also pass a string variable,a javascript array or even javascript object as argument to the publish method.
For example you could publish an array to a channel like below inside a JavaScript code block.

mycfwebsocketobject.publish("publishdemochannel",["Jan","Feb"] );

or you can use a Javascript array variable like below
var myarr= new Array();
myarr[1]="Jan";
myarr[2]="Feb";
myarr[3]="Mar";
mycfwebsocketobject.publish("publishdemochannel",myarr);


You can also publish a JavaScript object using the publish method.
var myobj= new Object();
myobj.fname="Evelin";
myobj.lname="Varghese";
myobj.age=28;
myobj.gender="Female";
mycfwebsocketobject.publish("publishdemochannel",myobj);


Using invokeAndPublish:
As I mentioned earlier invokeAndPublish is used to call a CFC function.The value returned by the function is published over the channel.
For example you have the employee id of the person, but you don't have the name of the person, you can use invokeAndPublish method of websocket to invoke the cfc method that will take the empid and will return the  message that needs to be published.
mycfwebsocketobject.invokeAndPublish("publishdemochannel", "employee",      "processMessage",[389,"Hello "]);
The value that the fucntion returns will be published to the channel specified:
component
{
public function processMessage(eid,msg)
{
            //Write your logic to get the empname based on empid
    var empname="Evelin";
    return msg & " " & empname;
}
}

Download this code sample which publishes different types of messages.

With the description here I hope you will be able to get started with your application to manage real time data. In the next few blogs I will try to explain more scenarios that you will come across in your ColdFusion WebSocket  application  development.
For more on How to handle responses from server checkout my next blog entry 

Saturday, February 18, 2012

ColdFusion WebSocket Part1:Getting Started

ColdFusion Websockets?What can I do with it?
                 You can write real-time Web applications and handle data with high efficiency but less complexity. Consider the case of a simple collaboration app that you use to chat. It is a simple task to build it using ColdFusion WebSocket. Yes, you could have done this without WebSocket, but that demands complex architecture and some hacks. Likewise you can create  bidding apps, a stock ticker etc in very short amount of time with ColdFusion WebSockets.

But how is it different?
    I know, you are used to HTTP. WebSocket is different from normal HTTP request response way of communication. In simple terms, if you want any data from your app server you have to send an http request in the form of form submit or some page request,but with  WebSocket you can keep receiving data from the app server without any action. Yes, I mean no action. In fact, you can have a two-way communication between client and server without page reloads.

So how do I implement it?
     You need to have ColdFusion 10 to make use of WebSocket. If you have not  installed it yet, get it from here .
Here is a very simple websocket channel implementation with  minimal lines of code

Step1:  Specify the channelname in  Application.cfc file
            This is absolutely mandatory if you need to establish websocket channel communication.
So your simplest Application.cfc will have the below code.
component
{
   this.name="wsdemoapp";
   this.wschannels=[{name="stocks"}];
}
Note that the above code is in ColdFusion Script syntax. We have specfied the name of the websocket channel as stocks

Step2: Use the new cfwebsocket tag to establish connection from your cfm page to your channel

<cfwebsocket name="mycfwebsocketobject"  onmessage="mymessagehandler" subscribeto="stocks" >

Here we have given mycfwebsocketobject as the value for name attribute, which will create a reference to a javascript websocket object.What this implies is that you can use mycfwebsocketobject as a Javascript object inside javascript code .This object has certain methods associated with it which can be used to  perform various operations over websocket.

Also note that in the above code sample I have specified mymessagehandler as the value of onmessage attribute. mymessagehandler should be a Javascript method .This is the method that will recieve all communications over the channel.

Step3:Define the message handler
<script type="text/JavaScript">
   function mymessagehandler(messageobj)
    {
         //Converting the JS object to a string and display  in "myDiv"
           var message = ColdFusion.JSON.encode(messageobj);
           var txt=document.getElementById("myDiv");
           txt.innerHTML +=message  +"<br>";
 }

</script>
Don't forget include a div with id "myDiv"  in your cfm page to display the messages .

Step4:Run your cfm page.
If you see a string of below format in your cfm page the WebsSocket Connection is successful

{"clientid":41244233,"ns":"coldfusion.websocket.channels","reqType":"welcome","code":0,"type":"response","msg":"ok"}

You can write application specific logic in your message handler to display the messages coming over websockets  in appropriate way.You can download the example described here.

This example just establishes a connection of websocket .For more on how to transfer data, keep watching for more posts. In the next few blogs, I will explain more advanced scenarios.
Happy playing with ColdFusion 10!!!

For more on how to publish messages check out  ColdFusion WebSocket Part2: How do I publish Message?