Add a mechanism to allow the emscripten virtual heap size to be specified at run-time by applications rather than having to change it at compile-time. Improve the documentation especially the main README
git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1626584 13f79535-47bb-0310-9956-ffa450edef68 Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/2cf80a9e Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/2cf80a9e Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/2cf80a9e Branch: refs/heads/master Commit: 2cf80a9e7181f2929dea5aa2c6adc935af6262bc Parents: 929eab4 Author: fadams <fadams@unknown> Authored: Sun Sep 21 14:44:57 2014 +0000 Committer: fadams <fadams@unknown> Committed: Sun Sep 21 14:44:57 2014 +0000 ---------------------------------------------------------------------- examples/messenger/javascript/send.html | 14 +- examples/messenger/javascript/send.js | 3 +- proton-c/bindings/javascript/README | 381 ++++++++++++++++++++- proton-c/bindings/javascript/TODO | 48 ++- proton-c/bindings/javascript/binding-close.js | 12 +- proton-c/bindings/javascript/module.js | 51 ++- 6 files changed, 471 insertions(+), 38 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2cf80a9e/examples/messenger/javascript/send.html ---------------------------------------------------------------------- diff --git a/examples/messenger/javascript/send.html b/examples/messenger/javascript/send.html index 382b293..dc8b448 100644 --- a/examples/messenger/javascript/send.html +++ b/examples/messenger/javascript/send.html @@ -26,18 +26,24 @@ <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <!-- - Import JavaScript Messenger Binding proton.js. Note that this simple example pulls - it from the node_modules/qpid-proton/lib which is created by the build process + Import the Messenger Binding proton.js. Note that this simple example pulls + it from the node_modules/qpid-proton/lib, which is created by the build process so that the node.js based examples "just work", in a real Web App you would need - to copy the proton.js to your own server. + to copy the proton.js to your own server. + In actual fact the CMake build actually builds proton.js into the directory: <build>/proton-c/bindings/javascript where <build> is the build directory created to run cmake from. + + In this example we also set the global variable PROTON_HEAP_SIZE in order to + increase the virtual heap available to the emscripten compiled C runtime. It + is not really necessary to do this for this application as the default value + of 16777216 is fine, it is simply done here to illustrate how to do it. --> +<script type="text/javascript">PROTON_HEAP_SIZE = 50000000;</script> <script type="text/javascript" src="../../../node_modules/qpid-proton/lib/proton.js"></script> <script type="text/javascript"> - var message = new proton.Message(); var messenger = new proton.Messenger(); http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2cf80a9e/examples/messenger/javascript/send.js ---------------------------------------------------------------------- diff --git a/examples/messenger/javascript/send.js b/examples/messenger/javascript/send.js index 9c48fab..0ca3a7e 100644 --- a/examples/messenger/javascript/send.js +++ b/examples/messenger/javascript/send.js @@ -20,11 +20,12 @@ */ // Check if the environment is Node.js and if not log an error and exit. -if (!exports) { +if (typeof process !== 'object' || typeof require !== 'function') { console.error("send.js should be run in Node.js"); return; } +PROTON_HEAP_SIZE = 50000000; var proton = require("qpid-proton"); var address = "amqp://0.0.0.0"; http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2cf80a9e/proton-c/bindings/javascript/README ---------------------------------------------------------------------- diff --git a/proton-c/bindings/javascript/README b/proton-c/bindings/javascript/README index 1998a47..a29352d 100644 --- a/proton-c/bindings/javascript/README +++ b/proton-c/bindings/javascript/README @@ -4,6 +4,115 @@ 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/TypeArray 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) it is very +important to note that: + +JavaScript clients cannot *directly* talk to "normal" AMQP applications such as +qpidd or the Java Broker because they use the traditional 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 +<proton>/examples/messenger/javascript/proxy.js +is a simple Node.js WebSocket<->TCP Socket proxy, simple 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 <qpid-work>/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>/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 ===================== @@ -11,26 +120,35 @@ 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. https://github.com/kripken/emscripten/wiki/Emscripten-SDK +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 +provides 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. - The documentation suggests master branch but in the short term incoming is - probably better as a few updates to emscripten have been added to help get - proton working and these may take a little while to get merged back to master. +* 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. - https://github.com/kripken/emscripten/wiki/LLVM-Backend has lots of explanation - and some easy to follow instructions for downloading and building fast-comp + 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 https://github.com/kripken/emscripten/wiki/Tutorial - +tutorial here: +http://kripken.github.io/emscripten-site/docs/getting_started/Tutorial.html @@ -44,7 +162,8 @@ the root directory) it's: cmake .. make -and you should be all set, to test it's all working do: +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 @@ -52,14 +171,243 @@ in one window and node send-async.js -in another +in another. + +These examples are actually JavaScript applications that have been directly +compiled from recv-async.c and send-async.c in <proton>/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 successful 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: + +<proton>/build/proton-c/bindings/javascript/html/index.html + + +Using "native" JavaScript +========================= + +The examples in <proton>/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_HEAP_SIZE global. +In Node.js this would look like (see send.js): +PROTON_HEAP_SIZE = 50000000; // Note no var - it needs to be global. + +In a browser it would look like (see send.html): +<script type="text/javascript">PROTON_HEAP_SIZE = 50000000;</script> + +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): +<script type="text/javascript" src="../../../node_modules/qpid-proton/lib/proton.js"></script> -KNOWN ISSUES -============ +<script type="text/javascript"> +var message = new proton.Message(); +var messenger = new proton.Messenger(); +.... -send-async and recv-async are both pretty hacky at the moment. +3. Set up event handlers as necessary. +messenger.on('error', <error callback>); +messenger.on('work', <work callback>); +messenger.on('subscription', <subscription callback>); + +The work callback is triggered on WebSocket events, so in general you would use +this to send and receive messages, for example in recv.js we have: + +var pumpData = function() { + while (messenger.incoming()) { + var t = messenger.get(message); + + console.log("Address: " + message.getAddress()); + console.log("Subject: " + message.getSubject()); + + // body is the body as a native JavaScript Object, useful for most real cases. + //console.log("Content: " + message.body); + + // data is the body as a proton.Data Object, used in this case because + // format() returns exactly the same representation as recv.c + console.log("Content: " + message.data.format()); + + messenger.accept(t); + } +}; + +messenger.on('work', pumpData); + + +The subscription callback is triggered when the address provided in a call to +messenger.subscribe(<address>); + +Gets resolved. An example of its usage can be found in qpid-config.js which is +a fully functioning and complete port of the python qpid-config tool. It also +illustrates how to do asynchronous request/response based applications. + +Aside from the asynchronous aspects the rest of the API is essentially the same +as the Python binding aside from minor things such as camel casing method names etc. + +Serialisation/Deserialisation, Types etc. +========================================= + +The JavaScript binding tries to be as simple, intuitive and natural as possible +so when sending a message all native JavaScript types including Object literals +and Arrays are transparently supported, for example. + +var message = new proton.Message(); +message.setAddress('amqp://localhost'); +message.setSubject('UK.NEWS'); +message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}]; + + +The main things to bear in mind is that (particularly for sending messages) we +may need to use "adapters" to make sure values are correctly interpreted and +encoded to the correct type in the AMQP type system. This is especially important +when interoperating with a peer written in a strongly typed language (C/C++/Java). + +Some examples of available types follow: + +// UUID +message.body = new proton.Data.Uuid(); + +// AMQP Symbol +message.body = new proton.Data.Symbol("My Symbol"); + +// Binary data (created from a String in this case). +message.body = new proton.Data.Binary("Monkey BathпогÑÐ¾Ð¼Ð·Ñ Ñвбнм"); + +// Binary data (Get a Uint8Array view of the data and directly access that). +message.body = new proton.Data.Binary(4); +var buffer = message.body.getBuffer(); +buffer[0] = 65; +buffer[1] = 77; +buffer[2] = 81; +buffer[3] = 80; + +// Binary Data (Created from an Array, you can use an ArrayBuffer/TypedArray too). +message.body = new proton.Data.Binary([65, 77, 81, 80]); + + +Note that the implementation of proton.Data.Binary tries to minimise copying so +it accesses the internal emscripten heap *directly* this requires memory management +which is mostly handled transparently, but users need to be aware that the +underlying memory is "owned" by the Message Object so if Binary data needs to +be maintained after the next call to messenger.get(message); it must be +*explicitly* copied. For more detail do "make docs" and see: +<proton>/build/proton-c/bindings/javascript/html/proton.Data.Binary.html + + +// AMQP Described (value, descriptor) +message.body = new proton.Data.Described('persian, 'com.cheezburger.icanhas'); + +// AMQP Timestamp maps to native JavaScript Date. +message.body = new Date(); + +// Various AMQP Array examples. +message.body = new proton.Data.Array('INT', [1, 3, 5, 7], "odd numbers"); +message.body = new proton.Data.Array('UINT', [1, 3, 5, 7], "odd"); +message.body = new proton.Data.Array('ULONG', [1, 3, 5, 7], "odd"); +message.body = new proton.Data.Array('FLOAT', [1, 3, 5, 7], "odd"); +message.body = new proton.Data.Array('STRING', ["1", "3", "5", "7"], "odd"); + +// A JavaScript TypedArray will map directly to and from an AMQP Array of the +// appropriate type (Internally sets a descriptor of 'TypedArray'). +message.body = new Uint8Array([1, 3, 5, 7]); + +// UUID Array +message.body = new proton.Data.Array('UUID', [new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid()], "unique"); + +// Null +message.body = null; + +// Boolean +message.body = true; + +// Native JavaScript Array maps to an AMQP List +message.body = ['Rod', 'Jane', 'Freddy']; + +// Native JavaScript Object maps to an AMQP Map +message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}]; + +// JavaScript only has a "number" type so the binding provides "decorator" +// methods added to the JavaScript Number class. To access this from number +// primitives it is necessary to either use braces or use a "double dot" so that +// the interpreter can disambiguate from a simple decimal point. The binding will +// attempt to use the correct type such that message.body = 2147483647; would be +// sent as an AMQP integer but because of the way JavaScript coerces integers +// message.body = 2147483647.0; would also be sent as an AMQP integer because +// 2147483647.0 gets transparently conveted to 2147483647 by the interpreter so +// to explicitly send this as an AMQP float we'd need to do: +// message.body = 2147483647.0.float(); + +// Some more number examples: +message.body = 66..char(); // char +message.body = 2147483647; // int +message.body = -2147483649; // long +message.body = 12147483649; // long +message.body = (12147483649).long(); // long +message.body = (17223372036854778000).ulong(); // ulong +message.body = (121474.836490).float(); // float +message.body = 12147483649.0.float(); // float +message.body = (4294967296).uint(); // uint +message.body = (255).ubyte(); // ubyte + +Note too that floats are subject to a loss of precision + + +Fortunately most of these quirks only affect serialisation.when the binding +receives a message it will attempt to decode it into the most "natural" native +JavaScript type. + + +One additional decoding "quirk" can be caused by C++ qpid::messaging clients. It +is unfortunately quite common for C++ clients to incorrectly encode Strings as +AMQP Binary by neglecting to provide an encoding. The QMF Management Agent is one +such culprit. This is a bit of a pain, especially because of proton.Data.Binary +memory management quirks and having to remember to explicitly copy the data +on each call to messenger.get(message); In order to cater for this an overloaded +messenger.get(message, true); has been provided. Setting the second parameter to +true forces any received Binary payloads to be decoded as Strings. If you know +that producers might behave in this way and you are not expecting any "real" +Binary data from the producer this convenience mechanism results in nice clean +JavaScript Objects being received and is extremely useful for things like QMF. + +JSON +==== + +As well as allowing native JavaScript Objects and Arrays to be transparently +serialised and deserialised via the AMQP type system it is also possible to +serialise/deserialise as JSON. + +message.setAddress('amqp://localhost'); +message.setContentType('application/json'); +message.body = {array: [1, 2, 3, 4], object: {name: "John Smith", age: 65}}; + +On the wire the above will be encoded as an opaque binary in an AMQP data section +but will be deserialised into a JavaScript Object in exactly the same was as the +previous examples that use the AMQP type system. SUPPORT ======= @@ -69,5 +417,10 @@ a tracker request: https://issues.apache.org/jira/browse/PROTON +The main support channel is the qpid-users mailing list, see: + + http://qpid.apache.org/discussion.html#mailing-lists + You can also directly interact with the development team and other users in the #qpid channel on irc.freenode.net. + http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2cf80a9e/proton-c/bindings/javascript/TODO ---------------------------------------------------------------------- diff --git a/proton-c/bindings/javascript/TODO b/proton-c/bindings/javascript/TODO index bd1d158..092ee2e 100644 --- a/proton-c/bindings/javascript/TODO +++ b/proton-c/bindings/javascript/TODO @@ -1,11 +1,49 @@ Qpid Proton JavaScript Language Bindings TODO List ================================================== -The code base contains some tweaked emscripten library code, this is ultimately going -to get done properly, commited back to emscripten and removed from here. +Network code is currently limited to a WebSocket transport, including for Node.js +It would be good to allow a configurable transport so that Node.js and Chrome +packaged apps could use native TCP sockets. +The JavaScript binding is pure JavaScript, that has been trans-compiled from C +to JavaScript using emscripten. This allows the same code to be used in a browser +and Node.js, but it potentially has a performance penalty in Node.js. An alternative +for Node.js might be to build a SWIG binding (recent versions of SWIG support +JavaScript). This should be viewed as a complementary not competing approach as +it would only work for environments like Node.js and definitely *not* browser +environments which clearly require pure JavaScript. + +Optimisation are enabled for compiling and linking but there hasn't been any +profiling done yet. The binding code *shouldn't* be the bottleneck but it's +always possible that I messed up. + +Error handling is nowhere near as good as it should be, though this is mostly +because Messenger itself is a bit lacking on the error handling/recovery front. + +Although described as "Proton" this is currently a JavaScript binding for Messenger +and associated Message & Data classes. There has been some talk on the user list +of an alternative reactive API based on proton Engine. This might ultimately be +a better fit for JavaScript but it is very much in its infancy and I haven't +really looked at it yet. + +proton-j seems to use hawt-dispatch, which is modelled after Grand Central +Dispatch so I need to work out what it's using it do do and whether there are +parallels in proton-c + +Although the WebSocket transport uses the sub-protocol 'AMQPWSB10' as specified +in http://docs.oasis-open.org/amqp-bindmap/amqp-wsb/v1.0/amqp-wsb-v1.0.html +section 2.1 is is not technically compliant with the spec. as the AMQP data is +created by the proton-c code, which produces a data-stream for the TCP transport +whereas the WebSocket spec. seems to want to make use of the fact that WebSocket +is a frame based transport (whereas TCP is not). This is quite hard to resolve +as the binding simply sends the contents of the octet buffer created by proton +over the transport and thus to make this binding compliant with the spec. would +require a change to the underlying proton-c code! It is possible that this may be +done in future as any SCTP would require the ability to push AMQP frames too. +In the mean time fortunately the Java Broker WebSocket transport is actually +tolerant of this off-spec. behaviour. My personal view is that both approaches +should be valid and in particular using the standard TCP framing means that it +is straightforward to create WebSocket<->TCP proxies, which is useful given that +only the Java Broker currently has a native WebSocket transport. -The example send-async.c and recv-async.c are both pretty hacky at the moment. -proton-j seems to use hawt-dispatch, which is modelled after Grand Central Dispatch so I need to -work out what it's using it do do and whether there are parallels in proton-c http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2cf80a9e/proton-c/bindings/javascript/binding-close.js ---------------------------------------------------------------------- diff --git a/proton-c/bindings/javascript/binding-close.js b/proton-c/bindings/javascript/binding-close.js index b7f1d93..07b68c2 100644 --- a/proton-c/bindings/javascript/binding-close.js +++ b/proton-c/bindings/javascript/binding-close.js @@ -18,10 +18,16 @@ * */ -// These values are essentially constants sitting in the proton namespace. -// We have to set them after pn_get_version_major/pn_get_version_minor have been -// defined so we must do it here in binding-close.js as it's a --post-js block. +/** + * These values are essentially constants sitting in the proton namespace + * that is to say they will be exported via: + * proton.VERSION_MAJOR + * proton.VERSION_MINOR + * We have to set them after pn_get_version_major/pn_get_version_minor have been + * defined so we must do it here in binding-close.js as it's a --post-js block. + */ Module['VERSION_MAJOR'] = _pn_get_version_major(); Module['VERSION_MINOR'] = _pn_get_version_minor(); })(); // End of self calling lambda used to wrap library. + http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2cf80a9e/proton-c/bindings/javascript/module.js ---------------------------------------------------------------------- diff --git a/proton-c/bindings/javascript/module.js b/proton-c/bindings/javascript/module.js index 0fdb803..cf64700 100644 --- a/proton-c/bindings/javascript/module.js +++ b/proton-c/bindings/javascript/module.js @@ -19,9 +19,13 @@ */ /** - * This file provides a JavaScript wrapper around the Proton Messenger API. - * It will be used to wrap the emscripten compiled proton-c code and be minified by - * the Closure compiler, so all comments will be stripped from the actual library. + * This file defines the Module Object which provides a namespace around the Proton + * Messenger API. The Module object is used extensively by the emscripten runtime, + * however for convenience it is exported with the name "proton" and not "Module". + * <p> + * The emscripten compiled proton-c code and the JavaScript binding code will be + * minified by the Closure compiler, so all comments will be stripped from the + * actual library. * <p> * This JavaScript wrapper provides a somewhat more idiomatic object oriented * interface which abstracts the low-level emscripten based implementation details @@ -32,25 +36,50 @@ /** * The Module Object is exported by emscripten for all execution platforms, we * use it as a namespace to allow us to selectively export only what we wish to - * be publicly visible from this package/module. + * be publicly visible from this package/module, which is wrapped in a closure. * <p> * Internally the binding code uses the associative array form for declaring * exported properties to prevent the Closure compiler from minifying e.g. * <pre>Module['Messenger'] = ...</pre> - * Exported Objects can be used in client code using a more convenient namespace, e.g.: + * Exported Objects can however be used in client code using a more convenient + * and obvious proton namespace, e.g.: * <pre> - * proton = require('qpid-proton'); + * var proton = require('qpid-proton'); * var messenger = new proton.Messenger(); * var message = new proton.Message(); + * ... + * </pre> + * The core part of this library is actually proton-c compiled into JavaScript. + * In order to provide C style memory management (malloc/free) emscripten uses + * a "virtual heap", which is actually a pre-allocated ArrayBuffer. The size of + * this virtual heap is set as part of the runtime initialisation and cannot be + * changed subsequently (the default size is 16*1024*1024 = 16777216). + * <p> + * Applications can specify the size of virtual heap that they require via the + * global variable PROTON_HEAP_SIZE, this must be set <b>before</b> the library is + * loaded e.g. in Node.js an application would do: + * <pre> + * PROTON_HEAP_SIZE = 50000000; // Note no var - it needs to be global. + * var proton = require('qpid-proton'); + * ... + * </pre> + * A browser based application would do: + * <pre> + * <script type="text/javascript">PROTON_HEAP_SIZE = 50000000;</script> + * <script type="text/javascript" src="proton.js"></script> * </pre> * @namespace proton */ +var Module = {}; -var Module = { - // Prevent emscripten runtime exiting, we will be enabling network callbacks. - 'noExitRuntime' : true, -}; - +// If the global variable PROTON_HEAP_SIZE has been set by the application this +// will result in the emscripten heap getting set to the next multiple of +// 16777216 above PROTON_HEAP_SIZE. +if (typeof process === 'object' && typeof require === 'function' && global['PROTON_HEAP_SIZE']) { + Module['TOTAL_MEMORY'] = global['PROTON_HEAP_SIZE']; +} else if (typeof window === 'object' && window['PROTON_HEAP_SIZE']) { + Module['TOTAL_MEMORY'] = window['PROTON_HEAP_SIZE']; +} /*****************************************************************************/ /* */ --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
