EventHandler

The EventHandler plugin is a type of web-service that sends data asynchronously from a client to the server. Unlike traditional web-services, the EventHandler can also send asynchronous events from the server to the client. Traditional web-services are constrained by the limitations of the HTTP protocol. The EventHandler may be considered more useful than traditional web-services for firmware developers since many embedded devices require real time updates of the user interface.

The EventHandler client initiates the connection by using standard HTTP. This connection is then morphed into a persistent connection, where both the client and server can send asynchronous messages to the peer side.

The EventHandler is a client server based messaging protocol and this protocol takes care of marshalling and unmarshalling the messages sent over the wire.

WebSocket Connection
EventHandler Interface Object

The application registers one or several interface objects on the client side and on the server side. These interface objects are similar to class instances. Each interface object has one or several callback functions that the peer side can call. For example, the client may register the interface "gui" with the callback function "vuMeter". The server can then call this function in the client as follows: gui.vuMeter(params)

The difference between a standard Remote Procedure Call (RPC) function and an EventHandler function is that the EventHandler function does not return a value. It's a one way call.

Each client connection is assigned a unique identification number which we call the connection id, or cid for short. When a client sends a message to the server, the server side EventHandler implementation receives the client's cid. The server side implementation can store the cid and at any time send asynchronous messages to the client by calling any of the available interface.functions(). Sending a message to one client using a cid is referred to as a unicast message. The server can also send multicast messages to all connected clients.

EventHandler Server in Lua

The following documentation is for users that want to design the server side of the EventHandler in the Lua scripting language. We also provide an EventHandler C/C++ server API, which is available to developers that have the complete Barracuda Web or Application Server SDK.

Creating an EventHandler Instance

An instance of the EventHandler is created and installed into the server's Virtual File System as follows:

eh=ba.create.eh("lua-eh-server", conlistener)
eh:insert()

Example 1: creating a server side EventHandler instance.

You can insert an EventHandler instance into any location in the Virtual File System. Keep in mind that the EventHandler is a type of directory object and directory objects are used when building the server's Virtual File System. We installed the EventHandler instance into the root of the Virtual File System in the above example. The fist parameter in the above example is the directory object name and the URL to this EventHandler instance will be http://server-name/lua-eh-server. The client side JavaScript EventHandler must connect to the server as follows:

eh = new EventHandler(conlistener, "/lua-eh-server");

Example 2: creating a client side JavaScript EventHandler instance.

The first argument 'conlistener' will be explained in detail later. The second argument is the URL to the server side EventHandler instance. We only need the path component of the URL since we are connecting to the origin server.

The Connection Listener Interface

The client and server EventHandler instance require a Connection Listener object. We use the name 'conlistener' in example 1 and 2 above. The Connection Listener object must provide a set of callbacks, which the EventHandler uses when reporting status information.

The server side Connection Listener object requires two callback functions, a connect() and a disconnect() function. The following example shows how you can construct such an object in Lua.

local conlistener={}
function conlistener.connect(cid, session)
   trace("New connection:",cid, "Session:", session and "yes" or "no")
end

function conlistener.disconnect(cid)
   trace("Connection terminated: ",cid)
end

Example 3: creating the server side Lua connection listener object.

The connect() callback function is called when a new client connects. We explained above that each client connection is assigned a unique identification number, which we call the connection id or cid for short. You would typically store the cid when a new client connects. You can later use this cid when sending asynchronous messages to this particular client. The second argument to connect() is the session object, which is nil if no session is created. The session object is automatically created for authenticated users -- i.e. if the EventHandler is protected by an authenticator.

The disconnect() callback function is called when the persistent connection terminates. The connection terminates if the user closes or refreshes the browser window. The connection may also close if the TCP connection goes down. Note, only a client can re-establish a connection.

The client side JavaScript Connection Listener object requires one additional callback function in addition to the onConnect() and onDisconnect() functions. The onError() callback function is typically called if the server side Lua code throws an exception. The server side Lua code may throw an exception if you for example make a program error. The onError() callback makes it convenient to trap and display the server side error on the client side. Notice that the naming convention is different for the client code where the functions start with the prefix 'on'.

var conlistener={
    onConnect: function(cid, pushConType) {
        alert("Connected and ready");
    },
    onDisconnect: function(e) {
        alert("Connection closed!");
    },
    onError: function(e) {
        alert(e.toString());
    }
};

Example 4: creating the client side JavaScript connection listener object.

The second argument to function onConnect() in example 4 is the EventHandler connection type. The connection type will be WebSocket for all modern browsers.

Example 4 shows how to create an object in JavaScript, with three properties onConnect, onDisconnect, and onError. Objects are called tables in Lua and example 3 above can be redesigned as follows:

local conlistener={
   connect=function(cid, session)
      trace("New connection:",cid, "Session:", session and "yes" or "no")
   end,
   disconnect=function(cid, session)
      trace("Connection terminated: ",cid)
   end
}

Example 5: shows an alternative to the Lua code in example 3.

The lua code in example 5 resembles the JavaScript code in example 4. Both Lua and JavaScript provides several ways for how you can create the Connection Listener objects.

Installing the EventHandler Interface and Callback Functions

You should now have an understanding in how to design and install the required connect() and disconnect() event callback functions for the client and server EventHandler instances. The next step is to design the client and server callback functions for the messages you want to send over the EventHandler connection. The way to do this is to register one or several interface objects with the EventHandler. Each interface object must have at least one callback function. The figure to the right illustrates how this works.

The following example creates and installs two interface objects for the client side and for the server side. Each interface has two callback functions the peer side can call.

EventHandler Interface Object

JavaScript Client Code

Lua Server Code

var intf1={
    func1:function(arg1) {
        alert("func1 called by server");
    },
    func2:function(arg1,arg2) {
        alert("func2 called by server");
    }
};

var intf2={
    func1:function(arg1,arg2,arg3) {
    },
    func2:function(arg1,arg2,arg3,arg4) {
    }
};

eh.addInterface(intf1,"intf1");
eh.addInterface(intf1,"intf2");
local intf1={
   func1=function(cid,arg1)
      trace(cid,arg1)
   end,
   func2=function(cid,arg1,arg2)
      trace(cid,arg1,arg2)
   end
}

local intf2={
   func1=function(cid,arg1,arg2,arg3)
   end,
   func2=function(cid,arg1,arg2,arg3,arg4)
   end
}

uni1, multi1 = eh:setintf("intf1", "intf1", intf1)
uni2, multi2 = eh:setintf("intf2", "intf2", intf2)

Example 6: shows how to create and install EventHandler interfaces for client and server side.

We construct the interfaces and their functions we want to make available to the peer side in the above JavaScript and Lua examples. We use the same interface names and function names for client and server, but you can use any name and there are no restriction on the number of interfaces or functions you can create. For example, you could have one function in the client and ten in the server.

Notice how the server's callback functions take an additional parameter. The first parameter, the Connection Id or cid for short, uniquely indentifies the client who sent the message. You use the cid when sending a unicast message from the server to one client.

The EventHandler protocol was initially designed for "C" code and defines the following types: int, long, double, string, and the following array types: int[], long[], double[], string[] and byte[]. Because script code is more free form than C code, the number of arguments you use or the argument type is not controlled. You can use strings, numbers, arrays of strings, or arrays of numbers as the argument type when sending data from Lua to JavaScript and vice versa. It is your responsibility to send the number of arguments required by the peer side. You can also design functions that accept a variable number of arguments.

When we install the two interfaces in the client by calling eh.addInterface(), we also pass in the name of the interface. The name makes it possible for the server to call the interface. The eh:setintf() method on the server also requires the peer's interface name. The first argument is the server's interface name and the second argument is the client's interface name, i.e. the peer's interface name. We use the same name for both client and server in the above Lua example. The eh.addInterface() returns two values, a unicast interface and a broadcast interface. The unicast interface is used when sending a message to one client and the broadcast interface is used if you want to send a message to all connected clients.

The interfaces we get on the server side by calling eh:setintf() are the peer's side interface objects. We can directly call the functions in these interfaces. For example, the server can send a broadcast message to all connected clients as follows:

multi1.func1("This is a broadcast message")

Example 7: server calls the callback function fun1() in interface intf1 in all connected clients.

The function "func1" in the above interface object multi1 is a so called stub function and this object is automatically created by the server side Lua EventHandler. Unfortunately, JavaScript code does not allow for such automatic construction so the peer's interface objects in the client must be created manually.

    var server={
        intf1:['func1','func2'],
        intf2:['func1','func2']
    };
    server=eh.buildServIntf(server);

Example 8: EH function eh.buildServIntf() builds the stub code for the server interfaces.

The client can now call any of the callbacks in the server. The following example calls the server's callback function func1() in interface intf1.

server.intf1.func1("Hello");

Example 9: client calling the server's callback function func1() in interface intf1.

The client or server EventHandler does not validate the API you construct so you must make sure you do not call any function that does not exist on the peer side. The EventHandler will throw an error if you call a non existing function.

Download the Example Program

The complete EventHandler example from the above tutorial can be downloaded.

Download EventHandler Example

This example is packaged as a ZIP file and can be directly executed, without unzipping, in one of the following servers:

You can load the EventHandler example using the above servers as follows:

EventHandler Reference Documentation

The server side Lua API and the client side JavaScript API:

Java EventHandler Stack

We also provide a client side Java EventHandler stack in addition to the client side JavaScript EventHandler stack. The JavaScript EventHandler stack is designed to run inside a browser by using the browser's JavaScript engine. The Java EventHandler stack is designed to be used by a Java application or an applet. A Java application and the Java EventHandler stack do not have the same origin policy restrictions as the JavaScript EventHandler stack and can therefore establish communication links with any number of devices. A Java application can be designed such that it can control hundreds and even thousands of devices simultaneously. This means that you can design applications that can update attributes in hundreds of devices by pressing one button in a Java GUI application.

Note: the Java EventHandler stack requires that you use the EventHandler stub compiler.