Tutorial: Use RCC Api from external Web Page

PBX Apis may be used from an external Web Page. This tutorial explains how to build a simple busy lamp field in an external web page, which uses the RCC API. The same mechanism can be applied for all PBX Json APIs

For demonstration purposes we implement a simple HTTP GET handler in our NewApp1 project to simulate the external web service. The webservice creates the login to the PBX, using the shared secret between the web service and a PBX App object. This functionality can then be transfered to the external web service to whatever technology (PHP, Go, Java, ...) is used there.

The tutorial is based on a newly created innovaphone App with the Visual Studio plugin.

The used file and class names in this example are based on a newly created App with the name NewApp1 and the company name innovaphone.

Simulation of external Web Service

To simulate the external web page, we add the files webservice.htm and webservice.js to the apps folder. This is an implementation of a very simple busy lamp field, using the RCC Api. It used HTTP GET request to retrieve a login to the PBX, which the web service can create with the shared secret.

webservice.htm

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Webservice</title>
    <script type="text/javascript" src="web/appwebsocket/innovaphone.appwebsocket.Connection.js"></script>
    <script type="text/javascript" src="webservice.js"></script>
</head>

<body onload="new Webservice()">
</body>
</html>

webservice.js

function Webservice() {
    var args = location.search.split("&");
    if (args[0].startsWith("?")) args[0] = args[0].slice(1);
    var pbx = args.find(function (e) { return e.startsWith("pbx=") });
    if (pbx) pbx = pbx.split("=")[1];
    var app = args.find(function (e) { return e.startsWith("app=") });
    if (app) app = app.split("=")[1];
    var users = [];

    if (pbx && app) {
        var body = document.getElementsByTagName("body");
        body[0].setAttribute("style", "margin:0px")
        var panel = document.createElement("div");
        panel.setAttribute("style", "position:absolute; width:100%; height:100%; background-color:black;" +
                                    "display:flex; flex-wrap:wrap; align-content:flex-start");
        body[0].appendChild(panel);

        var aws = new innovaphone.appwebsocket.Connection("ws://" + pbx + "/PBX0/APPS/websocket",
                                                          null, null, null,
                                                          connected, message, closed, closed, login);
    }

    function login(_app, challenge) {
        httpGet("login?mt=AppGetLogin&challenge=" + challenge + "&app=" + app, function (text) {
            var obj = JSON.parse(text);
            aws.login(obj);
        });
    }

    function connected() {
        aws.send({ mt: "Initialize", api: "RCC" });
    }

    function message(obj) {
        console.log(JSON.stringify(obj));
        if (obj.mt == "UserInfo") {
            var u = users.find(function (e) { return obj.guid == e.guid() });
            if (!u) {
                users.push(new User(obj));
            }
            else {
                if (obj.update == "del") {
                    users.splice(users.indexOf(u), 1);
                    u.del();
                }
                else {
                    u.update(obj);
                }
            }
        }
    }

    function closed() {
        while(users.length) {
            var u = users.pop();
            u.del();
        }
    }

    function User(info) {
        var element = document.createElement("div");
        element.setAttribute("style", "width:200px; height:20px; margin:10px; padding:10px");
        panel.appendChild(element);
        update();

        function update(i) {
            element.innerHTML = info.dn ? info.dn : info.cn;
            if (info.alert) element.style.backgroundColor = "yellow";
            else if (info.channel) element.style.backgroundColor = "red";
            else if (info.regs) element.style.backgroundColor = "green";
            else element.style.backgroundColor = "grey";
        }
        this.update = function (i) {
            info = i;
            update();
        }

        this.del = function () {
            panel.removeChild(element);
        }

        this.guid = function () { return info.guid };
    }

    function httpGet(url, funcComplete, funcFailed) {
        var xmlReq = new window.XMLHttpRequest();
        if (xmlReq) {
            xmlReq.open("GET", url, funcComplete ? true : false);
            xmlReq.send(null);
            if (funcComplete) {
                xmlReq.onreadystatechange = function () {
                    if (this.readyState == 4) {
                        if (this.status == 200) {
                            funcComplete(this.responseText, this.responseXML);
                        }
                        else {
                            if (funcFailed) funcFailed(this);
                            else funcComplete("{}");
                        }
                    }
                }
            }
        }
        return xmlReq;
    }
}

To add these files to the static files served by the App, we add the lines

    $(APPWEBPATH)/webservice.htm \
    $(APPWEBPATH)/webservice.js \
to the statement
APPWEBSRC_ZIP +=
in apps.mak

You can now build and run

You should be able to open the webservice.htm with your browser from the URL http://<AP>/newapp1/webservice.htm?app=rcc&pbx=<your PBX IP>. A blank, black page should be displayed

Simulation of Authentication Creation on the External Web Service

The authentication works with a shared secret between the PBX App object and the web service. In this example we use a static string "secret" for this.

For the login, the AppWebsocket library first reads a "challenge" from the PBX. This is then sent to the web service so that the webservice can use this to create a login together with the shared secret, which can be then used to call the login function of the AppWebsocket library.

We now add code the the NewApp1, which implements the handling of GET requests to create the login

Implement GET handler

Add the App object to the PBX

To use the RCC Api from your web page, you need an App object on the PBX, for the shared secret. Use the Advanced user interface to create an App object with the following properties:

Type
App
Long Name
RCC
Name
rcc
Password
secret
Grant access to APIs
Check RCC

You should now be able to open the busy lamp field with the URL http://<AP>/newapp1/webservice.htm?app=rcc&pbx=<your PBX IP> Still a blank black page should be displayed. If you use the Advanced User Interface to assign more users to the App "rcc", these users should appear. Users without phone registered grey, with phone green, with a call red and with an alerting call yellow.