Qpid Proton JavaScript Language Bindings ======================================== The code contained herein provides JavaScript language bindings for working with the Qpid Proton AMQP 1.0 protocol engine and messenger library. Important Note - Modern Browser Needed ====================================== The JavaScript binding requires ArrayBuffer/TypedArray and WebSocket support. Both of these are available in most "modern" browser versions. The author has only tried running on FireFox and Chrome, though recent Safari, Opera and IE10+ *should* work too - YMMV. It might be possible to polyfill for older browsers but the author hasn't tried this. Important Note - WebSocket Transport!!! ======================================= Before going any further it is really important to realise that the JavaScript bindings to Proton are somewhat different to the bindings for other languages because of the restrictions of the execution environment. In particular it is very important to note that the JavaScript bindings by default use a WebSocket transport and not a TCP transport, so whilst it's possible to create Server style applications that clients can connect to (e.g. recv.js and send.js) note that: JavaScript clients cannot *directly* talk to "normal" AMQP applications such as qpidd or (by default) the Java Broker because they use a standard TCP transport. This is a slightly irksome issue, but there's no getting away from it because it's a security restriction imposed by the browser environment. At the moment even for Node.js we are limited to using a WebSocket transport, but it is on the author's "TODO" list to look at providing a means to use either a WebSocket transport or a native TCP transport (via node's net library). It should also be possible to use native TCP for Chrome "packaged apps", but again this is only on the TODO list so if you want to talk to a "normal" AMQP application you must live with the WebSocket constraints. Option 1. proxy from WebSockets to TCP sockets. The application /examples/messenger/javascript/proxy.js is a simple Node.js WebSocket<->TCP Socket proxy, simply doing: node proxy.js will stand up a proxy listening by default on WebSocket port 5673 and forwarding to TCP port 5672 (this is configurable, for options do: node proxy.js -h) Rather than using a stand-alone proxy it is possible to have applications stand up their own proxy (where lport = listen port, thost = target host and tport = target port): var proxy = require('./ws2tcp.js'); proxy.ws2tcp(lport, thost, tport); For talking to the C++ broker unfortunately proxying is currently the only option as qpidd does not have a WebSocket transport. Option 2. The Java Broker's WebSocket transport. Recent releases of the Qpid Java Broker provide a native WebSocket transport which means that the JavaScript binding can talk to it with no additional requirements. It is necessary to configure the Java Broker as the WebSocket transport is not enabled by default. In /config.json in the "ports" array you need to add: { "authenticationProvider" : "passwordFile", "name" : "AMQP-WS", "port" : "5673", "transports" : [ "WS" ] } This sets the JavaBroker to listen on WebSocket port 5673 similar to the proxy. One gotcha that still bites the author *** DO NOT FORGET *** that you will be using ports that you are not used to!! If you are not connecting check that the proxy is running and that you are specifying the right ports. I still mess up :-( WebRTC Transport ================ A WebRTC Transport is supported by emscripten, though the author has not tried it. If you wan to play with this you are very much on your own at the moment YMMV. This is configured by adding to the LINK_FLAGS in CMakeLists.txt -s \"SOCKET_WEBRTC=1\" /* WebRTC sockets supports several options on the Module object. * Module['host']: true if this peer is hosting, false otherwise * Module['webrtc']['broker']: hostname for the p2p broker that this peer should use * Module['webrtc']['session']: p2p session for that this peer will join, or undefined if this peer is hosting * Module['webrtc']['hostOptions']: options to pass into p2p library if this peer is hosting * Module['webrtc']['onpeer']: function(peer, route), invoked when this peer is ready to connect * Module['webrtc']['onconnect']: function(peer), invoked when a new peer connection is ready * Module['webrtc']['ondisconnect']: function(peer), invoked when an existing connection is closed * Module['webrtc']['onerror']: function(error), invoked when an error occurs */ If you wanted to play with these you'd likely have to tweak the module.js code in /proton-c/bindings/javascript The emscripten documentation is a bit light on the WebRTC Transport too, though emscripten/tests/test_sockets.py emscripten/tests/sockets/webrtc_host.c emscripten/tests/sockets/webrtc_peer.c emscripten/tests/sockets/p2p/broker/p2p-broker.js emscripten/tests/sockets/p2p/client/p2p-client.js Look like they provide a starting point. Very much TODO...... Creating The Bindings ===================== To generate the JavaScript bindings we actually cross-compile from proton-c You will need to have emscripten (https://github.com/kripken/emscripten) installed to do the cross-compilation and in addition you will require a few things that emscripten itself depends upon. http://kripken.github.io/emscripten-site/docs/building_from_source/index.html#installing-from-source http://kripken.github.io/emscripten-site/docs/building_from_source/toolchain_what_is_needed.html provide instructions for installing emscripten and the "fastcomp" LLVM backend. This approach lets users use the "bleeding edge" version of emscripten on the "incoming" branch (pretty much analogous to building qpid/proton off svn trunk). This is the approach that the author of the JavaScript Bindings tends to use. http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html provides some fairly easy to follow instructions for getting started on several platforms the main dependencies are as follows (on Windows the SDK includes these): * The Emscripten code, from github (git clone git://github.com/kripken/emscripten.git). * LLVM with Clang. Emscripten uses LLVM and Clang, but at the moment the JavaScript back-end for LLVM is off on a branch so you can't use a stock LLVM/Clang. http://kripken.github.io/emscripten-site/docs/building_from_source/LLVM-Backend.html http://kripken.github.io/emscripten-site/docs/building_from_source/building_fastcomp_manually_from_source.html#building-fastcomp-from-source has lots of explanation and some easy to follow instructions for downloading and building fastcomp * Node.js (0.8 or above; 0.10.17 or above to run websocket-using servers in node) * Python 2.7.3 * Java is required in order to use the Closure Compiler to minify the code. If you haven't run Emscripten before it's a good idea to have a play with the tutorial here: http://kripken.github.io/emscripten-site/docs/getting_started/Tutorial.html when you are all set up with emscripten and have got the basic tests in the tutorial running building Proton should be simple, simply go to the Proton root directory and follow the main instructions in the README there, in precis (from the root directory) it's: mkdir build cd build cmake .. make and you should be all set, to test it's all working do (from the build directory): cd proton-c/bindings/javascript/examples node recv-async.js in one window and node send-async.js in another. These examples are actually JavaScript applications that have been directly compiled from recv-async.c and send-async.c in /examples/messenger/c if you'd prefer to write applications in C and compile them to JavaScript that is a perfectly valid approach and these examples provide a reasonable starting point for doing so. Documentation ============= When you've successfully got a working build do: make docs Which will make all of the proton documentation including the JavaScript docs. If successful the JSDoc generated documentation should be found here: /build/proton-c/bindings/javascript/html/index.html Using "native" JavaScript ========================= The examples in /examples/messenger/javascript are the best starting point. In practice the examples follow a fairly similar pattern to the Python bindings the most important thing to bear in mind though is that JavaScript is completely asynchronous/non-blocking, which can catch the unwary. An application follows the following (rough) steps: 1. (optional) Set the heap size. It's important to realise that most of the library code is compiled C code and the runtime uses a "virtual heap" to support the underlying malloc/free. This is implemented internally as an ArrayBuffer with a default size of 16777216. To allocate a larger heap an application must set the PROTON_TOTAL_MEMORY global. In Node.js this would look like (see send.js): PROTON_TOTAL_MEMORY = 50000000; // Note no var - it needs to be global. In a browser it would look like (see send.html): 2. Load the library and create a message and messenger. In Node.js this would look like (see send.js): var proton = require("qpid-proton"); var message = new proton.Message(); var messenger = new proton.Messenger(); In a browser it would look like (see send.html):