Introduction to EWD’s Realtime Web APIs

So you’ve seen the screenshots and hopefully even tried out the demo application, and now you want to start writing realtime browser-based applications.  In this posting I’m going to summarise the main APIs that you use to perform all this realtime magic.

The first thing to understand is that this new capability is a set of extensions to EWD, so, if you’re not already familiar with EWD, you’re going to have to learn how to use it.  There’s a variety of ways to do that, including:

  • I run training courses from time to time, often as part of the WorldVistA Community Meetings
  • My EWD/ExtJS documentation is written, to a large degree, in tutorial format, so you should be able to be up and running with some ExtJS-based web applications pretty quickly

If you’re already familiar with EWD, then you should find that the realtime extensions are pretty straightforward.  In this article I’m going to assume familiarity with EWD.

The first key thing you must do is in your main first container pages, you must add an extra attribute (websockets=”true”) to either the <ewd:config> tag (ie in older-style EWD applications) or in your <ext4:container> or <st2:container> tags, eg at the top of the index-gtm.ewd and index-cache.ewd pages in the demo ewdGateway2 application, you’ll see:

      <ext4:container isFirstPage="true" title="ewdGateway2" webSockets="true">

This tells EWD’s compiler to add in all the necessary socket.io library calls and other EWD-related WebSocket APIs to your application.

In general, the WebSockets APIs work by one part of the overall stack invoking messages that you define and that are handled by another part of the stack by event-handling code that you write.  So, for example:

  • messages can be invoked from within the browser and handled by either the GT.M or Caché database, or by your own Javascript module running within the ewdGateway2 module.
  • messages can be triggered by GT.M or Caché processes (and those processes don’t need to have any connection with EWD or your web applications), and handled by one, some or all browsers

It’s up to you whether your messages are one-way only, or return a response.  The content of messages can be either simple text strings or JSON objects of any level of complexity.  The only limitation is that the JSON objects can only contain properties – ie they can’t include functions.

Let’s start with a simple example: you want to send a message from the browser to be handled within GT.M or Caché.  Everything at the browser-end is handled by Javascript.  Although you can add Javascript into your EWD pages, I always recommend that you keep it in a separate Javascript (.js) file, so you should add a <script> tag to load it in your EWD application’s container page, eg:

      <script type="text/javascript" src="/js/ewdGW2.js" />

So, you’ll have something in your UI that generates an event, eg a button that the user clicks:

  <ext4:button id="msgBtn" text="Test Message" handler="function() {sendMsg();}" />

So now you’ll define that sendMsg() function in your Javascript file, eg:

 
    var sendMsg = function() {
      EWD.sockets.sendMessage({type: "myTestMsg", message:  "hello"});
    };

The first thing to notice is that you use a pre-defined function called EWD.sockets.sendMessage which has a single argument that is a JSON object. That object must always have a type property defined. The type value is entirely up to you, and you can define as many types in each of your applications as you need. In the current build (960), any other information is conveyed as a string value in a property named message. Future builds will allow you to send complex JSON messages to GT.M or Caché. However, for now you can, of course, pack multiple “fields” into the string, using a character as a field delimiter.

This message is dispatched to the ewdGateway2 Node.js module which attempts to handle it at various layers within itself. If it’s a message type that it doesn’t recognise (which will be the case in this example), it is forwarded to one of the child processes which passes it to GT.M or Caché. Once there, EWD attempts to discover a handler for your message. It’s your responsibility to write and register any such EWD-side handlers. Writing a handler is very simple – it’s just a Mumps procedure that has the following signature:

 
  label(messageValue,sessid)
   ; do whatever you need to do here
  QUIT

Notice that EWD will automatically figure out the EWD Session Id for the user who sent the message, and will pass it to your message handler. Your handler can therefore use and manipulate the user’s EWD Session as required, just as you would in any EWD script.

messageValue will hold the value of the JSON object’s message property (ie ‘hello’ in the example above).

So how does EWD know how to invoke your procedure when a message with a type of ‘myTestMsg’ arrives? The answer is that you must register it by adding a reference to EWD’s message registration global:

 
  ^zewd("websocketHandler",lcAppName,msgType)) = procedureRef

   where: lcAppName is the EWD Application name in lower case;
          msgType is the message type value
          procedureCall is the reference to your procedure (label^routine format)

For example:

 
  set ^zewd("websocketHandler","mytestapp","myTestMsg")) = "testMsgHandler^myHandlers"

EWD will automatically recognise the name of the EWD application being used by the browser user.  You can see that you can define handlers for as many different message types as you wish for each of your EWD applications.

You’ll also notice that message handlers have no return value – they simply quit at the end. Often that’s all you’ll need – your message can be a “fire and forget” type that silently does something within the user’s EWD Session and/or in the GT.M or Caché database. However, in many situations, you’ll want to return a message back to the user. So how do you do that? Just invoke the EWD API:

 
  set ok=$$sendWebSocketMsg^%zewdNode(msgType,.array,sessid)

Once again you define the outgoing message type and pass in the EWD Session Id to ensure that the message is returned to the original user’s browser. The array reference is to a Mumps local array that you create that EWD maps into a corresponding JSON structure. So for example, the following message invocation:

 
   set array("p1")="hello"
   set array("p2")="world"
   set ok=$$sendWebSocketMsg^%zewdNode("myMsgResponse",.array,sessid)
   QUIT

would return the following JSON message to the user’s browser

 
   {type: 'myMsgResponse', json: {p1: 'hello', p2: 'world'}}

In fact, provided you know a user’s EWD Session Id, you can use the $$sendWebSocketMsg() API anywhere in any of your GT.M or Caché applications.

So now you’ve sent a message back to the browser, how does it get handled there?

The trick is that you must add a specifically-named function to your EWD application’s Javascript file:

 
    EWD.sockets.serverMessageHandler = function(messageObj) { 
      // handle all your incoming messages here
    };

For example, to handle the ‘myMsgResponse’ message you’re sending to users of your application, you’ll do something like this:

 
    EWD.sockets.serverMessageHandler = function(messageObj) { 
      if (messageObj.type === 'myMsgResponse') {
        console.log(messageObj.json.p1 + ' ' + messageObj.json.p2);
        return;
      }
    };

Obviously this is a trivial example, but it’s up to you how you handle your incoming messages. The ewdGateway2 demo application shows how sophisticated message handling can be.

On the GT.M or Caché side you have two useful APIs for sending messages where you don’t necessarily know their EWD Session Ids:

  • $$sendMsgToAppUsers^%zewdNode(msgType,.array,EWDAppName)
  • $$broadcastMsg^%zewdNode(msgType,.array)

The first one sends a message to all currently active users of the specified EWD Application name (which can be expressed case-insensitively).

The second sends a message to all currently active users of all EWD applications.

Of course, the applications must have a handler defined in their EWD container page’s Javascript file otherwise the message will be ignored by the application.

That’s really all there is to it.  It’s a very simple API, yet, as demonstrated by the ewdGateway2 demo application, provides you with all the power and flexibility you’ll need to do very sophisticated things in real-time.  Take a look at its source code and you’ll see lots of examples of the APIs described in this article.

EWD looks after all the complex bits, such as security and mapping users/browsers to EWD tokens and session IDs.  You have complete freedom in terms of defining message types and their associated handlers at either end.

In the next posting, I’m going to dive into how you can write your EWD applications entirely in Javascript, and we’ll look at how you can handle incoming WebSocket messages and send back messages from your Javascript onBeforeRender methods.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: