In this article we explore some of the WebSocket functionality within our very own XQi Engine. Particularly the WebSocket Server (wsServer) implementation.
In this example, we put innovaphone’s AppWebSocket API to good use (see: http://sdk.innovaphone.com/doc/appwebsocket/AppWebsocket.htm). In short, the API acts as a WebSocket Client connecting to a remote WebSocket Server. Innovaphone defines an API as being a pre-defined set of JSON messages being exchanged over an established WebSocket connection. So in fact it all boils down to exposing a WebSocket endpoint and figuring out the correct order of message types and their content.
Note: you can also write your own innovaphone back-end integration and apps yourself, but this requires good knowledge of C++. The XQi Engine might be a faster and easier alternative to create (back-end) PBX integrations.
Configuring the XQi Engine as WebSocket Server
Even though the WebSocket protocol is documented extensively throughout the Internet & implementations exist in any programming language, there can be still quite a lot of work involved: choosing a programming language and implementation, deciding on project architecture and deployment of the final solution.
And that’s it. We have now successfully setup a WebSocket Server listening for incoming connections on the ‘/’ (root) path of wherever the XQi Engine is hosted. The ‘script’ member indicates which processing script will be used to relay incoming connections (or disconnections) & messages to. We can add more routes to the collection if we want to expose other Endpoints for other client types, effectively handling them in a separate processing script.
Configuring innovaphone PBX
The configuration of the innovaphone PBX for an external application is not covered here as this takes us too far away from the subject. In short, an App object should be configured to point to the XQi Engine. Contact us if you need help to solve this. In the near feature, we will release an innovaphone v13 app for the XQi Engine that will allow you to manage this connection using myApps.
Processing API messages
Now that we have an exposed WebSocket Server Endpoint and a client able to connect to said endpoint, we can proceed with the processing of connected clients and the message exchange. Let’s begin by detecting clients connecting, disconnecting & sending messages to the WebSocket Server.
We can subscribe to the following events of the wsServer module in the XQi Engine:
- onClientConnected: fires when a new client connects to a configured endpoint
- onClientDisconnected: fires when a client disconnects
- onMessage: fires when a message is received from a client
Let’s continue with the message exchange between client & server. According to the API documentation, the client initiates communication by sending an AppChallenge message. With this, the client requests a challenge for the login. The client expects an AppChallengeResult containing the challenge (a random string of min 16 chars) back.
The wsServer module identifies connected clients by means of an assigned connectionId. Connection management is handled by the engine. Replying to a received message is made easy because the connectionId of the client is included in the onMessage function argument.
Next message received from the client during the ‘logon stage’ is AppLogin. This message contains a number of fields and a digest. Being the server, we could recalculate the digest based on the challenge we sent earlier and the other fields in the AppLogin message. But for the sake of progressing fast, we’re not going to ;-). As is to be expected, the reply to an AppLogin message is an AppLoginResult message.
The login stage is finalized by the client sending an AppInfo message. After this, the innovaphone SDK considers itself to be connected and will only reconnect (reinitiating the message exchange) when the connection expired for whatever reason. Suppose something goes wrong during the initial message exchange, the innovaphone SDK will automatically reconnect and reinitialize the entire conversation again.
Getting User Objects
Time to get some information from the Innovaphone Pbx. We can use the PbxTableUsers API in combination with what in the innovaphone SDK is called a Replicator. Replicator messages allow you to read table content one row at a time. For more information, refer to: http://sdk.innovaphone.com/doc/appwebsocket/PbxTableUsers.htm. This information can be used for example to synchronize your PBX users with other systems. Or to get notified if users get new devices, and take appropriate action. But, there are many API’s available in the innovaphone, so other integrations are equally easy to make (PBX Admin API, Remote Call Control, …).
We continue after receiving the AppInfo message by sending a ReplicateStart message for the PbxTableUsers API:
The correct response to a ReplicateStart message obviously is the ReplicateStartResult message. We can get the first row by sending a ReplicateNext command to the connected client. Naturally, the client responds with a ReplicateNextResult message. This message contains a single row.
Because a Replicator only returns one row per ReplicateNext message, we must keep sending ReplicateNext messages until the columns member in the ReplicateNextResult message is null. This indicates all data was received.
We have retrieved some useful information from the innovaphone SDK . We can use this info in subsequent requests to other exposed API’s. We can combine the info and expose it via a REST endpoint (using the httpServer module in the XQi Engine) or relay all incoming messages from the innovaphone SDK to WebSocket Clients connected to other endpoints in the XQi Engine (like a Windows Task Bar App monitoring Pbx activity). Or log all captured activity to a file, email certain information to an administrator, or…