JavaScript


I’ll be heading to GUADEC this year thanks to the generous support the GNOME Foundation Travel Committee but that won’t be my first stop in my mega marathon travelling month of July.

  • I will first be travelling to NY around the 8th for the God Street Wine reunion concerts and will be making a pit stop at the Long Island Linux Users Group to give a dry run of my GUADEC talk entitled “The Future is JavaScript” which will continue with my theme from last year of continuing to meld the GNOME Desktop with the web platform (this year focusing on what JavaScript brings to the table)
  • I fly out of JFK Airport on the 17th for Lyon France where I am taking the week long Robert Ash cooking course at Rue du Lac in Macon, Burgundy
  • The class ends on the 23rd and my Hotel is booked for the 25th in The Hague so I am not quite sure if I will stay in Lyon or start my way up.  I know I have some GNOME friends living between Lyon and The Hague so I am offering to cook dinner for anyone who will let me crash at their place for a couple of days before GUADEC.
  • And then there is the main event – GUADEC.  My talk is on Wednesday the 28th at noon.  It shouldn’t be missed.
  • To relax a bit more, save money on airfare and because I love Germany, I am heading to Berlin for a couple of days before flying back to the US

If anyone is going to be in any of the areas I will be in and wants to hang out.  Let me know and I’ll see if I can make time.

[read this post in: ar de es fr it ja ko pt ru zh-CN ]

Due to a name clash with another JavaScript project I have renamed my project to J5tester and released version 0.2. This version has the rename and a jsio wrapper which will fix the need for a patch to jsio. There are still some fixes that are being added to jsio’s git module and should show up some time tomorrow. The j5tester git repo will also take a bit of time to move over. Sorry for the brief inconvenience.

Introducing Jester. Jester is a JavaScript unit tester based around GNOME’s Gjs JavaScript engine. I wrote it because I needed a stand alone tester for testing non-DOM JavaScript code in my AMQP Bindings (kamaloka-js). I also wanted to learn the ins and outs of Gjs and GLib Introspection while making it relevant to my friends in the GNOME Community. By utilizing a separate run time for non-DOM code I hope to encourage the separation of browser and generic JavaScript code for the sake of reuse across browser and desktop platforms.

Jester has a couple of components and can be used indirectly or directly by Gjs applications. The first component is the jester standalone application which can load and run a JavaScript file from the command line. Use this to integrate with test workflows such as make check or to simply test out some quick JavaScript. The second component is the jester.js module which can be loaded directly in a Gjs application. This module contains the Test class which is used to write unit tests.

Here is a simple example of how to use Jester:

test.js

const Jester = imports.jester;

let test = {
    testExample: function() {
        this.assertEquals(1, 1, "This test should always pass");
        this.assertEquals(1, 2, "This test should fail");
    }
}

this.info("Jester Example");
let test_suite = new Jester.Test({"Simple Test": test});
test_suite.run();

To run this code you would enter this on the command line:

jester test.js

Home Page: http://live.gnome.org/Jester
0.1 Tarball: http://live.gnome.org/Jester?action=AttachFile&do=view&target=jester-0.1.tar.bz2
Git:

  • anonymous – git://git.gnome.org/jester
  • commit access – ssh://USERNAME@git.gnome.org/git/jester

Since kamaloka-js is built on top of js.io, I have create a patch for js.io which makes the importer work when used with Jester.

[read this post in: ar de es fr it ja ko pt ru zh-CN ]

Those who are following AMQP know that work on version 1.0 of the protocol spec is happening right now. Previous versions of the API were heavily dependent on the protocol itself but with 1.0 around the corner a new messaging API has come along to help bridge the gap between 0.10 and 1.0 for the most common use cases.

In kamaloka-js, the JavaScript AMQP bindings, I have been working on implementing this API along with cleaning up the codebase significantly. Today I put the final touches on multi-part frame decoding as well as the dispatching code and hope to have a brand new release next week. Here is a look at both the old and new API:

Old kamaloka-js API as used in release 0.1.0

<script src="/static/Orbited.js"></script>
<script src="/javascript/amqp.protocol.js"></script>
<script src="/javascript/amqp.protocol_0_10.js"></script>
<script src="/javascript/qpid_amqp.js"></script>

<script>
    amqp_conn = new amqp.Connection({host: 'localhost',
                                     port: 9000});
    amqp_conn.start();

    // You should have your server generate a UUID since browser methods
    // are unreliable at best
    session = amqp_conn.create_session('not_a_great_id' +
                                       (new Date().getTime() +
                                        Math.random()));
    var remote_queue =  settings.remote_queue + session.name;
    session.Queue('declare', {queue: remote_queue});

    var queue = session.create_local_queue({name: '0'});
    var output_cb = function(msg) {
        console.log(msg.header.delivery_properties.routing_key +
                    ' sent ' + msg.body);
    }

    queue.subscribe({exchange: 'amq.topic',
                                remote_queue: remote_queue,
                                binding_key: 'com.j5live.#',
                                callback: output_cb});
    queue.start();

    // test a multi segment transfer
    setTimeout(function(){
        session.Message('transfer',{accept_mode: 1,
                                    acquire_mode: 1,
                                    destination: 'amq.topic',
                                    _body: 'Test Transfer From Browser',
                                    _header: {delivery_properties:{
                                                 routing_key:'com.j5live.test'
                                              }
                                             }
                                    });
         }, 10000);
</script>

New kamaloka-js API as used in the upcoming 0.9.1 release

<script src="/static/Orbited.js"></script>
<script src="/javascript/jsio/jsio.js"></script>
<script>
   jsio("import qpid_amqp as amqp");
   jsio("from amqp.protocol import register");
   // load the 0.10 version of the protocol
   register("amqp.protocol_0_10");

    amqp_conn = new amqp.Connection({host: 'localhost',
                                     port: 9000,
                                     socket_cls: Orbited.TCPSocket
                                    });
    amqp_conn.start();

    // You should have your server generate a UUID since browser methods
    // are unreliable at best
    session = amqp_conn.session('not_a_great_id' + (new Date().getTime() + Math.random()));

    var output_cb = function() {
        msg = this.fetch();
        console.log(msg.get('_header').delivery_properties.routing_key +
                    ' sent ' + msg.get('_body'));
    }

    var receiver = session.receiver('amq.topic/com.j5live.*');
    receiver.onReady = output_cb;
    receiver.capacity(0xFFFFFFFF);

     // test a multi segment transfer
     var sender = session.sender('amq.topic/com.j5live.test');
     sender.send('Test Transfer From Browser');
</script>

The new API will offer a lot more control, better dispatching and a simplified interface. Further integration with js.io is planned as well as full support for transactions and flow control.

[read this post in: ar de es fr it ja ko pt ru zh-CN ]

If there is one thing I learned when working on D-Bus is that if you build a decent API, people will use it. Right now I am working on Kamaloka-js – JavaScript bindings for building JavaScript native AMQP clients. As AMQP starts moving towards 1.0 a new high level API, based loosely on JMS, is emerging to bridge the gap between 0.10 and 1.0. Previously with AMQP you pretty much worked with patterns on the protocol level which meant when the new specification came out you would pretty much have to rewrite to the new API. The new messaging based API seeks to decouple the protocol from the API for the most common use cases.

As I implement the JavaScript API there are some decisions I must make regarding how closely I stick to this new API as implemented in other bindings. Lets look at how the new API receives messages in Python:

...

conn = Connection.open(url.host, url.port)
ssn = conn.session()
rcv = ssn.receiver('amq.topic/org.j5live.demo')

while True:
    try:
        msg = rcv.fetch(timeout=timeout)
        process_message(msg)
        ssn.acknowledge()
    except Empty:
        break
    except ReceiveError, e:
        print e
        break

If you notice the API is very much mainloop based. With every loop we fetch a message off the local queue. If there are no messages, fetch works very similar to the way poll does for sockets – sleep until woken up by network traffic or a timeout. The issue is if we did this in JavaScript we would block the UI and event propagation (newer browsers do expose threading but that feature can not be relied upon in all browsers). If you have ever mistakenly created an infinite loop in JavaScript you will understand how bad this is.

There are two options I see here, keep the fetch method and require the programmer to use timers to read from the local queue or, as currently implemented in my own high level API, attach callbacks to receivers.

The timer/fetch method has a couple of advantages. First it more closely resembles the API of the other bindings. Also it allows tighter management of the local queue. Since each time the timer is triggered we can determine how many messages we wish to process we can give some performance guarantees based on how long it takes to run operations in response to the messages. In this way we can dictate when a message is processed and tweak applications to run smoother. This comes at the price of added complexity which could be even more of a detriment to performance when in the wrong hands.

The callback API has the advantage of being more in line to what JavaScript developers expect. JavaScript is highly event/callback based with onFoo handlers everywhere. We currently work this way. When a message is decoded from the socket we dispatch it immediately to any callback registered to listen for it. The issue here is an application can get hammered with messages with no way to defer processing (except by implementing their own processing queue).

Why not implement both? This is an option but that doesn’t mean it is a good option. Multiple ways of doing the same thing often confuse new users. Understanding the differences between the API’s and the nuances between usecases are often more complex than either API alone. This could be daunting to a new user.

The trick is to make the API’s build on one another. For instance I could add an onReady handler which then allows the user to use the fetch API to grab any messages inside the handler. We would then set up an internal timer if the queue was not completely drained. This would require users be familiar with the fetch API without having to set up their own timer. If they wanted to have more control, they could set up their own timers instead of using the handler.

Any JavaScript developers have any insight as to the best way forward?

[read this post in: ar de es fr it ja ko pt ru zh-CN ]

I am proud to announce version 0.1.0 of the kamaloka-js AMQP bindings. This initial release is considered to be an alpha quality release. It is there for you to break and give feedback so we can continue to improve the bindings and eventually get them to the point where they can be used to run mission critical applications.

In the next few days I will be concentrating on documenting the design of the bindings so anyone who wants to can easily jump in and contribute patches as well as suggestions. Please visit the project page to find out more and see how you can help out.

What’s in store for the future?

  • High level bindings for each of the major AMQP client patterns to get developers up and running with AMQP in the browser fast
  • QMF bindings for working with the QMF management console

Where can I find this release?

What’s in this release?

  • Initial release
  • Connection handshaking works
  • AMQP lowlevel bindings for version 0.10 of the AMQP Protocol mostly complete
  • Higher level bindings implementing the publisher/subscriber pattern is ready for use

How can I find out more?

Kamaloka-js is an implementation of the AMQP messaging protocol (http://amqp.org/) in native JavaScript released under the MIT license. It is setup to be used with Orbited (http://orbited.org/) but can be used with any library which produce TCPSockets in the browser similar to Orbited. Kamaloka bindings are generated from qpid XML protocol description files.

[read this post in: ar de es fr it ja ko pt ru zh-CN ]