HOME ABOUT
A way to turn a HTTP client into a service provider

AjaxSync C++ Connector Application

The example for writing a AjaxSync Connector application is the same chat client like in JavaScript, only written in C++.

In principle, it is possible to write AjaxSync Applications in every language; only a thin wrapper would be necessary to use the existing C++ library. That library is nearly system independent. It makes use of the cURL library, which has already support for most languages, and it needs multithread support. For the latter an interface was implemented so that it is easily possible to integrate the connector library with most common thread libraries and operating systems. An implementation for POSIX threads (pthreads) is shipped with the default AjaxSync Server installation.

We will use that shipped POSIX thread support in the following example. This starts with including this file:

#include "ajaxsyncThreads.h"

Besides this, only the stdlib is needed, especially for input/output support. Be aware that this is only a small example in order to show interacting with AjaxSync, so I will neither use the possibilities of C++ (STL) nor other frameworks and libraries.

#include <stdlib.h>

Like in the JavaScript example we will buffer the username in a variable in order to create a message prefix. Unlike in that example we will also buffer the password. Because our C++ example will be a simple command line tool without dialog support, we take the login credentials from command line parameters, store them in variables and present them to AjaxSync whenever the AjaxSync Server asks for them.

/**
 * Buffer for the username given by command line
 * argument and used for automatic login in
 * #displayLoginHandler.
 */
std::string user;

/**
 * Buffer for the users password given by command
 * line argument and used for automatic login in
 * #displayLoginHandler.
 */
std::string passwd;

The needed C++ string support already is included in the ajaxsyncThreads.h header file.

Now we define the error handler. This is a function which will be registered later in the AjaxSync object (named "as" in the main function). That object calls this handler every time AjaxSync encounters an error.

/**
 * Instead of displaying an error message in a div
 * element or window, it is simply printed on stdout
 * @param s Error message
 * @param container Pointer to the AjaxSync
 * container object. Unused here
 */
void errorHandler(std::string& s, void* container) {
    printf("ERROR %s\n", s.c_str());
}

Next step is the login mechanism. Be aware that in theory it is possible to initiate a logout on the server side. The framework would detect that with the next keepalive signal. If that happens, an automatic relogin with the stored credentials should be triggered. For that a handler function is required. It has to be registered in the AjaxSync object later.

The handler function immediately calls the login API function of the framework, using the stored credentials as parameters.

/**
 * Instead of displaying a login dialog, an
 * automatic (re-)login is performed
 * @param s Unused here
 * @param container Pointer to the AjaxSync
 * container object. Used for sending the credentials
 * to the server with the ajaxsync::login method
 */
void displayLoginHandler(std::string& s, void* container) {
    ajaxsync* as = (ajaxsync*) container;
    printf("Relogin\n");
    as->login(user, passwd);
}

The send message action is skipped in this example. We do not need an onclick handler, so we will call the AjaxSync frameworks API function directly in the main function.

Instead we create the handler function which displays received messages. It is (after registration) called by the AjaxSync framework automatically whenever a message is received - or exactly said, whenever this function is called from another AjaxSync client. Be aware that we have only one function in this chat client (as said before, named "chat"), but in a more complex application there could be many different functions.

/**
 * Instead of displaying a received chat message in
 * a div element or window, it is simply printed on
 * stdout
 * @param s Chat message
 * @param container Pointer to the AjaxSync container
 * object. Unused here
 */
void chat(std::string& s, void* container) {
    printf("MSG %s\n", s.c_str());
}

Now we define the main function. This starts with picking the credentials and the AjaxSync URL from the command line parameters.

By the way, the reason the AjaxSync URL was not necessary in the JavaScript example is simply that the webpage itself was loaded from this URL, therefore all calls to the AjaxSync controllers where simply made by relative paths. That is not possible with a standalone application.

int main(int argc, char** argv) {
    if (argc != 4) {
        printf("Usage: %s <URL of AjaxSync Server \
*with* trailing slash> <username> <password>\n",
                argv[0]);
        exit(0);
    }

    // base URL to the AjaxSync server:
    std::string baseURL = argv[1];
    user = argv[2]; // username
    passwd = argv[3]; // password
    ...

Another thing not needed in the JavaScript example is a cookie jar, because that is taken from the webbrowser. For a standalone application we have to use a local file which is writable by the application. Here I have hard wired a local file named ajaxsync.txt stored in the directory from which the application is started.

    ...
    // path to the cookie jar file:
    std::string cookieJar = "ajaxsync.txt";
    ...

The C++ API is somewhere restricted, so no function takes string call by value parameters. Therefore we need to store the name of the function to call / be called into a variable.

    ...
    // name of the callback function to register:
    std::string chatName = "chat";
    ...

While in the JavaScript example the API object was already created by including the library file, in the C++ version it has to be instantiated manually.

    ...
    // create framework object:
    ajaxsyncThreads as(NULL, baseURL, cookieJar);
    ...

Next we register the handlers ...

    ...
    // register the callback function:
    as.getRegistry()->addHandler(chatName, chat);
    // initialize framework:
    as.init(errorHandler, displayLoginHandler);
    ...

With the "init" command the event loop starts working in the background. That means the display login function is triggered which causes a call back to the server performing a login. After that (assumed that the credentials are correct - otherwise we would have a problem now, because each failure triggers the display login function immediately, which in turn triggers a relogin with the same wrong credentials in an endless loop) we can receive chat calls every time.

After initialising that event loop we start our own (parallel running) loop interactively asking for messages to be sent.

    ...
    // buffer for message to be sent:
    std::string param;
    while (1) {
        printf(": ");
        // buffer for the buffer :-), because
        // getline can't use a C++ string:
        char buf[20000];
        char *bufptr = (char*) buf;
        // length plus one stop byte (zero):
        size_t buflen = 19999;
        // read one line, max 19999 characters:
        getline(&bufptr, &buflen, stdin);
        ...

Like in the JavaScript example that messages are prefixed with the username.

        ...
        // adding user name and convert to C++ string:
        param = user + ": " + buf;
        ...

Like said before, we do not have an onclick handler or something similar. With pressing the return key, the string is read via getline, changed and converted, and sent with the next command:

        ...
        // send the line as message:
        as.send(chatName, param, 60, 10);
        ...

The two integer values are the client and the server timeout. If a network connection is broken between the AjaxSync server and one of its clients, there will be reconnection attempts every second till the connection is re-established. If a message is sent during such a network outage it will be buffered and sent as soon as the connection is re-established.

The first parameter (60) means that if the connection from our application to the AjaxSync server is broken, the application will try to deliver the message for 60 seconds before giving up and simply drop the message. Be aware that you will not be notified for such a dropping, but you can set the timeout as high as you want, limited only by the maximum UNIX timestamp of 19.01.2038.

The second parameter (10) means that if the connection from the AjaxSync server to one of the message receivers is broken, the server tries to deliver the message to that receiver for 10 seconds before giving up and simply drop the message. Here you can see why you aren't notified for a failure/dropping. It is because AjaxSync messages are broadcasts in theory sent to hundreds of receivers, and only the server is aware who is a receiver and who is not - the sender of the message does not know that.

As before, you can set the timeout as high as you want limited only by the maximum UNIX timestamp of 19.01.2038.

Because AjaxSync will not send a message back to its sender, we will have to display it ourselves:

        ...
        // and display it on stdout
        printf("(param)%s\n", param.c_str());
    }
}

The source code of the Connector Library, the POSIX Thread wrapper and the example above is shipped with your default AjaxSync Server installation. However it is not compiled by the Setup, nor are the requirements checked. Read Using C++ Example for details.

With that example program you can demonstrate sending messages in real time between a command line tool (binary application) and a webbrowser back and forth.