You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by fa...@apache.org on 2014/09/01 20:32:04 UTC

svn commit: r1621865 - in /qpid/proton/branches/fadams-javascript-binding: examples/messenger/javascript/ proton-c/bindings/javascript/ tests/javascript/

Author: fadams
Date: Mon Sep  1 18:32:04 2014
New Revision: 1621865

URL: http://svn.apache.org/r1621865
Log:
The qpid-config port is largely complete except for xml binding support, it also needs a bit of tidying up. Added a simple soak test to send and receive messages from a broker ad-infinitum and a simple html send message example

Added:
    qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/send.html   (with props)
    qpid/proton/branches/fadams-javascript-binding/tests/javascript/soak.js   (with props)
Removed:
    qpid/proton/branches/fadams-javascript-binding/proton-c/bindings/javascript/my-library.js
Modified:
    qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/qpid-config.js
    qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/send.js
    qpid/proton/branches/fadams-javascript-binding/proton-c/bindings/javascript/CMakeLists.txt
    qpid/proton/branches/fadams-javascript-binding/proton-c/bindings/javascript/binding.js

Modified: qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/qpid-config.js
URL: http://svn.apache.org/viewvc/qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/qpid-config.js?rev=1621865&r1=1621864&r2=1621865&view=diff
==============================================================================
--- qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/qpid-config.js (original)
+++ qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/qpid-config.js Mon Sep  1 18:32:04 2014
@@ -41,7 +41,11 @@ if (typeof exports !== "undefined" && ex
     proton = require("qpid-proton");
 }
 
-var address = 'amqp://0.0.0.0:5673/qmf.default.direct';
+var addr = 'guest:guest@localhost:5673';
+//var addr = 'localhost:5673';
+var address = 'amqp://' + addr + '/qmf.default.direct';
+console.log(address);
+
 var replyTo = '';
 var subscription;
 var subscribed = false;
@@ -52,13 +56,14 @@ var messenger = new proton.Messenger();
 /**
  * The correlator object is a mechanism used to correlate requests with their
  * aynchronous responses. It might possible be better to make use of Promises
- * to implement part of this behaviour but a mechanism would still be meeded to
+ * to implement part of this behaviour but a mechanism would still be needed to
  * correlate a request with its response callback in order to wrap things up in
  * a Promise, so much of the behaviour of this object would still be required.
  * In addition it seemed to make sense to make this QMF2 implementation fairly
  * free of dependencies and using Promises would require external libraries.
- * Instead the correlator implements Promise-like semantics, you might call it
+ * Instead the correlator implements "Promise-like" semantics, you might call it
  * a broken Promise :-)
+ * <p>
  * in particular the request method behaves a *bit* like Promise.all() though it
  * is mostly fake and takes an array of functions that call the add() method
  * which is really the method used to associate response objects by correlationID.
@@ -155,6 +160,7 @@ var getObjects = function(packageName, c
     message.setReplyTo(replyTo);
     message.setCorrelationID(className);
     message.properties = {
+        "routing-key": "broker", // Added for Java Broker
         "x-amqp-0-10.app-id": "qmf2",
         "method": "request",
         "qmf.opcode": "_query_request",
@@ -178,6 +184,7 @@ var invokeMethod = function(object, meth
     message.setReplyTo(replyTo);
     message.setCorrelationID(correlationID);
     message.properties = {
+        "routing-key": "broker", // Added for Java Broker
         "x-amqp-0-10.app-id": "qmf2",
         "method": "request",
         "qmf.opcode": "_method_request",
@@ -197,7 +204,7 @@ messenger.on('work', pumpData);
 messenger.setOutgoingWindow(1024);
 messenger.start();
 
-subscription = messenger.subscribe('amqp://0.0.0.0:5673/#');
+subscription = messenger.subscribe('amqp://' + addr + '/#');
 messenger.recv(); // Receive as many messages as messenger can buffer.
 
 
@@ -358,11 +365,24 @@ var _options =
 '                        output\n';
 
 var REPLICATE_LEVELS = {"none" : true, "configuration": true, "all": true};
-var DEFAULT_PROPERTIES = {"exchange":["name", "type", "durable"], "queue":["name", "durable", "autoDelete"]};
+var DEFAULT_PROPERTIES = {"exchange": {"name": true, "type": true, "durable": true},
+                             "queue": {"name": true, "durable": true, "autoDelete": true}};
+
+var getValue = function(r) {
+    var value = null;
+    if (r.length === 2) {
+        value = r[1];
+        if (!isNaN(value)) {
+            value = parseInt(value);
+        }
+    }
+
+    return value;
+};
 
 var config = {
     _recursive      : false,
-    _host           : 'localhost',
+    _host           : 'localhost:5673', // Note 5673 not 5672 as we use WebSocket transport.
     _connTimeout    : 10,
     _ignoreDefault  : false,
     _altern_ex      : null,
@@ -389,17 +409,13 @@ var config = {
     _extra_arguments: [],
     _start_replica  : null,
     _returnCode     : 0,
-    _list_properties: [],
+    _list_properties: null,
 
     getOptions: function() {
         var options = {};
         for (var a = 0; a < this._extra_arguments.length; a++) {
             var r = this._extra_arguments[a].split('=');
-            var value = null;
-            if (r.length === 2) {
-                value = r[1]; 
-            }
-            options[r[0]] = value;
+            options[r[0]] = getValue(r);
         }
         return options;
     }
@@ -471,7 +487,7 @@ var idMap = function(list) {
     return map;
 };
 
-var renderArguments = function(obj, list) {
+var renderObject = function(obj, list) {
     if (!obj) {
         return '';
     }
@@ -493,7 +509,7 @@ var renderArguments = function(obj, list
     }
 
     if (addComma) {
-        return ' {' + string + '}';
+        return '{' + string + '}';
     } else {
         if (list) {
             return string;
@@ -645,7 +661,7 @@ var exchangeListRecurse = function(filte
                         var queue = queues[oid(bind.queueRef)];
                         var queueName = queue ? queue._values.name : "<unknown>";
                         console.log("    bind [" + bind.bindingKey + "] => " + queueName + 
-                                    renderArguments(bind.arguments));
+                                    " " + renderObject(bind.arguments));
                     }   
                 }
             }
@@ -743,7 +759,7 @@ var queueList = function(filter) {
                 if (args[SHARED_MSG_GROUP] === 1) {
                     string += ' --shared-groups';
                 }
-                string += renderArguments(args, true);
+                string += ' ' + renderObject(args, true);
                 console.log(string);
             }
         }
@@ -785,7 +801,7 @@ var queueListRecurse = function(filter) 
                         }
 
                         console.log("    bind [" + bind.bindingKey + "] => " + exchangeName + 
-                                    renderArguments(bind.arguments));
+                                    " " + renderObject(bind.arguments));
                     }   
                 }
             }
@@ -824,10 +840,10 @@ console.log("Method result");
     if (response._arguments) {
         //console.log(response._arguments);
     } if (response._values) {
-        console.error("Exception from Agent: " + renderArguments(response._values));
+        console.error("Exception from Agent: " + renderObject(response._values));
     }
     // Mostly we want to stop the Messenger Event loop and exit when a QMF method
-    // call returns, but sometimes we don't.
+    // returns, but sometimes we don't, the dontStop flag prevents this behaviour.
     if (!dontStop) {
         messenger.stop();
     }
@@ -846,11 +862,7 @@ var addExchange = function(args) {
 
     for (var a = 0; a < config._extra_arguments.length; a++) {
         var r = config._extra_arguments[a].split('=');
-        var value = null;
-        if (r.length === 2) {
-            value = r[1]; 
-        }
-        declArgs[r[0]] = value;
+        declArgs[r[0]] = getValue(r);
     }
 
     if (config._msgSequence) {
@@ -918,11 +930,7 @@ var addQueue = function(args) {
 
     for (var a = 0; a < config._extra_arguments.length; a++) {
         var r = config._extra_arguments[a].split('=');
-        var value = null;
-        if (r.length === 2) {
-            value = r[1]; 
-        }
-        declArgs[r[0]] = value;
+        declArgs[r[0]] = getValue(r);
     }
 
     if (config._durable) {
@@ -1201,21 +1209,141 @@ console.log(args);
  * The following methods are "generic" create and delete methods to for arbitrary
  * Management Objects e.g. Incoming, Outgoing, Domain, Topic, QueuePolicy,
  * TopicPolicy etc. use --argument k1=v1 --argument k2=v2 --argument k3=v3 to
- * pass arbitrary arguments as key/value pairs to the Object being created/deleted.
+ * pass arbitrary arguments as key/value pairs to the Object being created/deleted,
+ * for example to add a topic object that uses the fanout exchange:
+ * ./qpid-config.js add topic fanout --argument exchange=amq.fanout \
+ * --argument qpid.max_size=1000000 --argument qpid.policy_type=ring
  */
 
 var createObject = function(type, name, args) {
-console.log("createObject");
-console.log(type);
-console.log(name);
-console.log(args);
+    correlator.request(
+        // We invoke the CRUD methods on the broker object.
+        getObjects('org.apache.qpid.broker', 'broker')
+    ).then(function(objects) {
+        var broker = objects.broker[0];
+        correlator.request(
+            // Create an object of the specified type.
+            invokeMethod(broker, 'create', {
+                "type":       type,
+                "name":       name,
+                "properties": args,
+                "strict":     true})
+        ).then(handleMethodResponse);
+    });
+};
 
+var deleteObject = function(type, name, args) {
+    correlator.request(
+        // We invoke the CRUD methods on the broker object.
+        getObjects('org.apache.qpid.broker', 'broker')
+    ).then(function(objects) {
+        var broker = objects.broker[0];
+        correlator.request(
+            // Create an object of the specified type and name.
+            invokeMethod(broker, 'delete', {
+                "type":    type,
+                "name":    name,
+                "options": args})
+        ).then(handleMethodResponse);
+    });
 };
 
-var deleteObject = function(args) {
-console.log("deleteObject");
-console.log(args);
+/**
+ * This is a "generic" mechanism for listing arbitrary Management Objects.
+ */
+var listObjects = function(type) {
+    correlator.request(
+        getObjects('org.apache.qpid.broker', type)
+    ).then(function(objects) {
+        // The correlator passes an object containing responses for all of the
+        // supplied requests so we index it by the supplied type to get our response.
+        objects = objects[type];
+
+        // Collect available attributes, stringify the values and compute the max
+        // length of the value of each attribute so that we can later create a table.
+        var attributes = {};
+        var lengths = {};
+        for (var i = 0; i < objects.length; i++) {
+            var object = objects[i];
+            object = object._values;
+            for (var prop in object) {
+                if (typeof object[prop] === 'object') { // Stringify Object properties.
+                    // Check if property is an ObjectID (reference property),
+                    // if so replace with the "name" part of the OID.
+                    if (object[prop]['_object_name']) {
+                        var parts = object[prop]['_object_name'].split(':');
+                        object[prop] = parts[parts.length - 1];
+                    } else {
+                        // Stringify general Object properties.
+                        object[prop] = renderObject(object[prop]);
+                    }
+                } else {
+                    object[prop] = object[prop].toString(); // Stringify other property types.
+                }
+
+                if (!lengths[prop] || object[prop].length > lengths[prop]) { // Compute lengths.
+                    lengths[prop] = object[prop].length > prop.length ? object[prop].length : prop.length;
+                }
+
+                if (!config._list_properties || config._list_properties[prop]) { // Do we want this property?
+                    attributes[prop] = true;
+                }
+            }
+        }
+
+        if (!config._list_properties && DEFAULT_PROPERTIES[type]) {
+            attributes = DEFAULT_PROPERTIES[type];
+        }
+
+        // Using the information we've previously prepared now render a table
+        // showing the required property values.
+        var desired = [];
+        var header = ''; // Table header showing the property names.
+        if (attributes['name']) {
+            desired.push('name');
+            delete attributes['name'];
+            header += 'name' + Array(lengths['name'] + 2 - 4).join(' ');
+        }
+
+        for (var prop in attributes) {
+            desired.push(prop);
+            header += prop + Array(lengths[prop] + 2 - prop.length).join(' ');
+        }
+
+        console.log("Objects of type '" + type + "'");
+        console.log(header);
+        console.log(Array(header.length).join('='));
+        for (var i = 0; i < objects.length; i++) {
+            var object = objects[i];
+            object = object._values;
+            var string = '';
+            for (var j = 0; j < desired.length; j++) {
+                var key = desired[j];
+                string += object[key] + Array(lengths[key] + 2 - object[key].length).join(' ');
+            }
+
+            console.log(string);
+        }
 
+        messenger.stop();
+    });
+};
+
+var reloadAcl = function() {
+    correlator.request(
+        getObjects('org.apache.qpid.acl', 'acl')
+    ).then(function(objects) {
+        if (objects.acl.length > 0) {
+            var acl = objects.acl[0];
+            correlator.request(
+                // Create an object of the specified type.
+                invokeMethod(acl, 'reloadACLFile', {})
+            ).then(handleMethodResponse);
+        } else {
+            console.log("Failed: No ACL Loaded in Broker");
+            messenger.stop();
+        }
+    });
 };
 
 
@@ -1263,10 +1391,9 @@ if (args.length > 0) {
                 if (config._connTimeout === 0) {
                     config._connTimeout = null;
                 }
-            } else if (arg === '-b' || arg === '--broker' || arg === '-b' || arg === '--broker-addr') {
-                config._host = val;
-                if (config._host == null) {
-                    config._host = 'localhost:5672';
+            } else if (arg === '-b' || arg === '--broker' || arg === '-a' || arg === '--broker-addr') {
+                if (val != null) {
+                    config._host = val;
                 }
             } else if (arg === '--alternate-exchange') {
                 config._altern_ex = val;
@@ -1306,7 +1433,10 @@ if (args.length > 0) {
             } else if (arg === '--f' || arg === '--file') { // TODO Won't work in node.js
                 config._file = val;
             } else if (arg === '--show-property') {
-                config._list_properties = val;
+                if (config._list_properties === null) {
+                    config._list_properties = {};
+                }
+                config._list_properties[val] = true;
             }
         } else {
             params.push(arg);
@@ -1316,9 +1446,6 @@ if (args.length > 0) {
 
 config._extra_arguments = extra_arguments;
 
-console.log("params");
-console.log(params);
-
 // The command only *actually* gets called when the QMF connection has actually
 // been established so we wrap up the function we want to get called in a lambda.
 var command = function() {overview();};
@@ -1365,11 +1492,19 @@ if (params.length > 0) {
         command = function() {bind(Array.prototype.slice.apply(params, [1]));};
     } else if (cmd === 'unbind') {
         command = function() {unbind(Array.prototype.slice.apply(params, [1]));};
+    } else if (cmd === 'reload-acl') {
+        command = function() {reloadAcl();};
+    } else if (cmd === 'list' && params.length > 1) {
+        command = function() {listObjects(modifier);};
+    } else {
+        usage();
     }
 }
 
+//console.log(config._host);
+
+
 var onSubscription = function() {
     command();
 };
 
-

Added: qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/send.html
URL: http://svn.apache.org/viewvc/qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/send.html?rev=1621865&view=auto
==============================================================================
--- qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/send.html (added)
+++ qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/send.html Mon Sep  1 18:32:04 2014
@@ -0,0 +1,110 @@
+<!DOCTYPE html> <!-- HTML5 doctype -->
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+    http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<html>
+
+<head>
+	<title>Simple Proton Messenger Send Example</title>
+	<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
+  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. 
+  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.
+-->
+<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();
+
+var sendMessage = function() {
+    var address = document.getElementById("address").value;
+    var subject = document.getElementById("subject").value;
+    var body = document.getElementById("body").value;
+
+console.log("sendMessage");
+console.log("address = " + address);
+console.log("subject = " + subject);
+console.log("body = " + body);
+
+    message.setAddress(address);
+    message.setSubject(subject);
+    message.body = body;
+
+    messenger.put(message);
+};
+
+messenger.on('error', function(error) {console.log("Received error " + error);});
+messenger.start();
+
+</script>
+
+<style>
+body
+{
+	font: 13px/1.5 Helvetica, Arial, 'Liberation Sans', FreeSans, sans-serif;
+    overflow-x: hidden; /* Hide horizontal scrollbar */
+    background: #dddddd;
+}
+
+label
+{
+    display: block;
+	font-size: 17px;
+}
+
+input, textarea
+{
+	font-size: 13px;
+    margin-bottom: 10px;
+}
+</style>
+
+</head>
+
+<body>
+<div>
+    <label for="address">Address:</label>
+    <input type="text" id="address" size="40"
+           placeholder="amqp://user:password@host:port"
+           name="address" value="amqp://guest:guest@0.0.0.0" />
+</div>
+<div>    
+    <label for="subject">Subject:</label>
+    <input type="text" id="subject" size="40"
+           name="subject" value="Browser Message" />
+</div>
+<div>
+    <label for="body">Message:</label>
+    <textarea id="body" name="body" rows="4" cols="40">Hello From Browser!</textarea>
+</div>
+<div>
+    <input type="button" value="send" onclick="sendMessage()"/>
+</div>
+</body>
+
+</html>

Propchange: qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/send.html
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/send.html
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Propchange: qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/send.html
------------------------------------------------------------------------------
    svn:mime-type = text/html

Modified: qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/send.js
URL: http://svn.apache.org/viewvc/qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/send.js?rev=1621865&r1=1621864&r2=1621865&view=diff
==============================================================================
--- qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/send.js (original)
+++ qpid/proton/branches/fadams-javascript-binding/examples/messenger/javascript/send.js Mon Sep  1 18:32:04 2014
@@ -33,6 +33,10 @@ var running = true;
 var message = new proton.Message();
 var messenger = new proton.Messenger();
 
+// Because this is an asynchronous send we can't simply call messenger.put(message)
+// then exit. The following callback function (and messenger.setOutgoingWindow())
+// gives us a means to wait until the consumer has received the message before
+// exiting. The recv.js example explicitly accepts messages it receives.
 var pumpData = function() {
     var status = messenger.status(tracker);
     if (status != proton.Status.PENDING) {
@@ -81,7 +85,7 @@ console.log("Content: " + msgtext);
 
 messenger.on('error', function(error) {console.log(error);});
 messenger.on('work', pumpData);
-messenger.setOutgoingWindow(1024);
+messenger.setOutgoingWindow(1024); // So we can track status of send message.
 messenger.start();
 
 message.setAddress(address);

Modified: qpid/proton/branches/fadams-javascript-binding/proton-c/bindings/javascript/CMakeLists.txt
URL: http://svn.apache.org/viewvc/qpid/proton/branches/fadams-javascript-binding/proton-c/bindings/javascript/CMakeLists.txt?rev=1621865&r1=1621864&r2=1621865&view=diff
==============================================================================
--- qpid/proton/branches/fadams-javascript-binding/proton-c/bindings/javascript/CMakeLists.txt (original)
+++ qpid/proton/branches/fadams-javascript-binding/proton-c/bindings/javascript/CMakeLists.txt Mon Sep  1 18:32:04 2014
@@ -19,7 +19,7 @@
  
 # This file allows cross-compiling of proton to JavaScript using emscripten
 # (https://github.com/kripken/emscripten). As it is really a cross-compilation
-# (as opposed to a binding a la swig) the approach is rather different and
+# (as opposed to a binding like with swig) the approach is rather different and
 # somewhat replicates the main build in the proton-c/CMakeLists.txt using quite
 # a bit of "copy and paste reuse".
 # TODO refactor this file (and proton-c/CMakeLists.txt) to keep the main
@@ -27,8 +27,8 @@
 
 message(STATUS "Found emscripten, using that to build JavaScript binding")
 
-# Find and install node.js packages that we might need. We can assume that
-# node.js is installed because Emscripten has a dependency on it.
+# Find and install the node.js packages that we might need. We can assume that
+# node.js itself is installed because Emscripten has a dependency on it.
 find_package(NodePackages)
 
 # Describe the target OS we are building to - Emscripten mimics the Linux platform.
@@ -43,6 +43,14 @@ set(CMAKE_C_COMPILER "${EMCC}")
 include(CMakeForceCompiler)
 CMAKE_FORCE_C_COMPILER("${CMAKE_C_COMPILER}" Clang)
 
+if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
+    message(STATUS "DEBUG JavaScript build")
+else()
+    message(STATUS "RELEASE JavaScript build")
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
+    set(EMSCRIPTEN_LINK_OPTIMISATIONS "-O2 --closure 1")
+endif()
+
 # From this point we should be using emscripten compilation tools.
 message(STATUS "emscripten compilation environment:")
 message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}")
@@ -193,21 +201,9 @@ set_target_properties(
   RUNTIME_OUTPUT_DIRECTORY examples
   DEPENDS ws
 
-  # This build shows socket messages - useful for debugging.
-  #LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -s SOCKET_DEBUG=1"
-
-  # Optimised build - takes somewhat longer to build.
-  #LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1"
-
-  # This build shows up emscripten warnings when building - should be able to remove it.
-  #LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -s VERBOSE=1 -O2"
-
-  # This build is optimised but not minified
-  LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2"
+  LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -${EMSCRIPTEN_LINK_OPTIMISATIONS}"
   )
 
-
-
 # Build the main JavaScript library called proton.js
 add_executable(proton.js binding.c)
 target_link_libraries(proton.js qpid-proton-bitcode)
@@ -217,16 +213,13 @@ set_target_properties(
   PROPERTIES
   COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_PLATFORM_FLAGS}"
 
-  # This build is optimised and minified. The --memory-init-file 0 stops emscripten
-  # emitting a separate memory initialization file, if this was enabled it makes
-  # packaging harder as applications would expect proton.js.mem to be served too.
-  # It's even more fiddly with node.js packages. This behaviour might be reinstated
-  # if the packaging mechanism improves.
-
-  # --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js
-  #LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1 --memory-init-file 0 --pre-js
+  # The --memory-init-file 0 stops emscripten emitting a separate memory
+  # initialization file, if this was enabled it makes packaging harder as
+  # applications would expect proton.js.mem to be served too. It's even more
+  # fiddly with node.js packages. This behaviour might be reinstated if the
+  # packaging mechanism improves.
 
-  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1 --memory-init-file 0 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_test', '_uuid_generate', '_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_messenger_receiving', '
 _pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_id', '_pn_message_correlation_id', '_pn_message_free', '_pn_message_errno', '_pn_message_error', '_pn_message_clear', '_pn_message_is_inferred', '_pn_message_set_inferred', '_pn_message_is_durable', '_pn_message_set_durable', '_pn_message_get_priority', '_pn_message_set_priority', '_pn_message_get_ttl', '_pn_message_set_ttl', '_pn_message_is_first_acquirer', '_pn_message_set_first_acquirer', '_pn_message_get_delivery_count', '_pn_message_set_delivery_count', '_pn_message_get_user_id', '_pn_message_set_user_id', '_pn_message_get_address', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_messa
 ge_get_reply_to', '_pn_message_set_reply_to', '_pn_message_get_content_type', '_pn_message_set_content_type', '_pn_message_get_content_encoding', '_pn_message_set_content_encoding', '_pn_message_get_expiry_time', '_pn_message_set_expiry_time', '_pn_message_get_creation_time', '_pn_message_set_creation_time', '_pn_message_get_group_id', '_pn_message_set_group_id', '_pn_message_get_group_sequence', '_pn_message_set_group_sequence', '_pn_message_get_reply_to_group_id', '_pn_message_set_reply_to_group_id', '_pn_message_encode', '_pn_message_decode', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array',
  '_pn_data_put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_array_described', '_pn_data_get_array_type', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_deci
 mal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
+  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" ${EMSCRIPTEN_LINK_OPTIMISATIONS} --memory-init-file 0 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_messenger_receiving', '_pn_messen
 ger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_id', '_pn_message_correlation_id', '_pn_message_free', '_pn_message_errno', '_pn_message_error', '_pn_message_clear', '_pn_message_is_inferred', '_pn_message_set_inferred', '_pn_message_is_durable', '_pn_message_set_durable', '_pn_message_get_priority', '_pn_message_set_priority', '_pn_message_get_ttl', '_pn_message_set_ttl', '_pn_message_is_first_acquirer', '_pn_message_set_first_acquirer', '_pn_message_get_delivery_count', '_pn_message_set_delivery_count', '_pn_message_get_user_id', '_pn_message_set_user_id', '_pn_message_get_address', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_get_rep
 ly_to', '_pn_message_set_reply_to', '_pn_message_get_content_type', '_pn_message_set_content_type', '_pn_message_get_content_encoding', '_pn_message_set_content_encoding', '_pn_message_get_expiry_time', '_pn_message_set_expiry_time', '_pn_message_get_creation_time', '_pn_message_set_creation_time', '_pn_message_get_group_id', '_pn_message_set_group_id', '_pn_message_get_group_sequence', '_pn_message_set_group_sequence', '_pn_message_get_reply_to_group_id', '_pn_message_set_reply_to_group_id', '_pn_message_encode', '_pn_message_decode', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array', '_pn_data
 _put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_array_described', '_pn_data_get_array_type', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_decimal64', '_
 pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
   )
 
 # This command packages up the compiled proton.js into a node.js package called

Modified: qpid/proton/branches/fadams-javascript-binding/proton-c/bindings/javascript/binding.js
URL: http://svn.apache.org/viewvc/qpid/proton/branches/fadams-javascript-binding/proton-c/bindings/javascript/binding.js?rev=1621865&r1=1621864&r2=1621865&view=diff
==============================================================================
--- qpid/proton/branches/fadams-javascript-binding/proton-c/bindings/javascript/binding.js (original)
+++ qpid/proton/branches/fadams-javascript-binding/proton-c/bindings/javascript/binding.js Mon Sep  1 18:32:04 2014
@@ -477,6 +477,14 @@ _Messenger_['setIncomingWindow'] = funct
  */
 _Messenger_['start'] = function() {
     this._check(_pn_messenger_start(this._messenger));
+
+    // This call ensures that the emscripten network callback functions are set
+    // up even if a client hasn't explicity added a work function via a call to
+    // messenger.on('work', <work function>);
+    // Doing this means that pn_messenger_work() will still get called when any
+    // WebSocket events occur, which keeps things more reliable when things like
+    // reconnections occur.
+    Module.EventDispatch.addListener(this);
 };
 
 /**
@@ -541,8 +549,7 @@ _Messenger_['subscribe'] = function(sour
  * Places the content contained in the message onto the outgoing queue
  * of the Messenger. This method will never block, however it will send any
  * unblocked Messages in the outgoing queue immediately and leave any blocked
- * Messages remaining in the outgoing queue. The send call may be used to
- * block until the outgoing queue is empty. The outgoing property may be
+ * Messages remaining in the outgoing queue. The outgoing property may be
  * used to check the depth of the outgoing queue.
  * <p>
  * When the content in a given Message object is copied to the outgoing
@@ -554,13 +561,23 @@ _Messenger_['subscribe'] = function(sour
  * @method put
  * @memberof! proton.Messenger#
  * @param {proton.Message} message a Message to send.
+ * @param {boolean} flush if this is set true or is undefined then messages are
+ *        flushed (this is the default). If explicitly set to false then messages
+ *        may not be sent immediately and might require an explicit call to work().
+ *        This may be used to "batch up" messages and *may* be more efficient.
  * @returns {proton.Data.Long} a tracker.
  */
-_Messenger_['put'] = function(message) {
+_Messenger_['put'] = function(message, flush) {
+    flush = flush === false ? false : true;
     message._preEncode();
     this._checkErrors = true;
     this._check(_pn_messenger_put(this._messenger, message._message));
 
+    // If flush is set invoke pn_messenger_work.
+    if (flush) {
+        _pn_messenger_work(this._messenger, 0);
+    }
+
     // Getting the tracker is a little tricky as it is a 64 bit number. The way
     // emscripten handles this is to return the low 32 bits directly and pass
     // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
@@ -578,6 +595,12 @@ _Messenger_['put'] = function(message) {
  * @returns {proton.Status} one of None, PENDING, REJECTED, or ACCEPTED.
  */
 _Messenger_['status'] = function(tracker) {
+    if (tracker == null) {
+        var low = _pn_messenger_outgoing_tracker(this._messenger);
+        var high = Runtime.getTempRet0();
+        tracker = new Data.Long(low, high);
+    }
+
     return _pn_messenger_status(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits());
 };
 
@@ -589,6 +612,12 @@ _Messenger_['status'] = function(tracker
  * @returns {boolean} true if delivery is still buffered.
  */
 _Messenger_['isBuffered'] = function(tracker) {
+    if (tracker == null) {
+        var low = _pn_messenger_outgoing_tracker(this._messenger);
+        var high = Runtime.getTempRet0();
+        tracker = new Data.Long(low, high);
+    }
+
     return (_pn_messenger_buffered(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits()) > 0);
 };
 
@@ -982,7 +1011,9 @@ Module.EventDispatch = new function() { 
             };
         }
 
-        _messengers[name].callbacks.push(callback);
+        if (callback) {
+            _messengers[name].callbacks.push(callback);
+        }
     };
 
     /**

Added: qpid/proton/branches/fadams-javascript-binding/tests/javascript/soak.js
URL: http://svn.apache.org/viewvc/qpid/proton/branches/fadams-javascript-binding/tests/javascript/soak.js?rev=1621865&view=auto
==============================================================================
--- qpid/proton/branches/fadams-javascript-binding/tests/javascript/soak.js (added)
+++ qpid/proton/branches/fadams-javascript-binding/tests/javascript/soak.js Mon Sep  1 18:32:04 2014
@@ -0,0 +1,99 @@
+#!/usr/bin/env node
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// Check if the environment is Node.js and if so import the required library.
+if (typeof exports !== "undefined" && exports !== null) {
+    proton = require("qpid-proton");
+}
+
+var addr = 'guest:guest@localhost:5673';
+//var addr = 'localhost:5673';
+var address = 'amqp://' + addr;
+console.log(address);
+
+var subscriptionQueue = '';
+var subscription;
+var subscribed = false;
+var count = 0;
+var start = 0; // Start Time.
+
+var message = new proton.Message();
+var messenger = new proton.Messenger();
+
+var pumpData = function() {
+    if (!subscribed) {
+        var subscriptionAddress = subscription.getAddress();
+        if (subscriptionAddress) {
+            subscribed = true;
+            var splitAddress = subscriptionAddress.split('/');
+            subscriptionQueue = splitAddress[splitAddress.length - 1];
+            onSubscription();
+        }
+    }
+
+    while (messenger.incoming()) {
+        // The second parameter forces Binary payloads to be decoded as strings
+        // this is useful because the broker QMF Agent encodes strings as AMQP
+        // binary, which is a right pain from an interoperability perspective.
+        var t = messenger.get(message, true);
+        //console.log("Address: " + message.getAddress());
+        //console.log("Content: " + message.body);
+        messenger.accept(t);
+
+        if (count % 1000 === 0) {
+            var time = +new Date();
+            console.log("count = " + count + ", duration = " + (time - start) + ", rate = " + ((count*1000)/(time - start)));
+        }
+
+        sendMessage();
+    }
+
+    if (messenger.isStopped()) {
+        message.free();
+        messenger.free();
+    }
+};
+
+var sendMessage = function() {
+    var msgtext = "Message Number " + count;
+    count++;
+
+    message.setAddress(address + '/' + subscriptionQueue);
+    message.body = msgtext;
+    messenger.put(message);
+//messenger.settle();
+};
+
+messenger.on('error', function(error) {console.log(error);});
+messenger.on('work', pumpData);
+//messenger.setOutgoingWindow(1024);
+messenger.setIncomingWindow(1024); // The Java Broker seems to need this.
+messenger.start();
+
+subscription = messenger.subscribe('amqp://' + addr + '/#');
+messenger.recv(); // Receive as many messages as messenger can buffer.
+
+var onSubscription = function() {
+    console.log("Subscription Queue: " + subscriptionQueue);
+    start = +new Date();
+    sendMessage();
+};
+

Propchange: qpid/proton/branches/fadams-javascript-binding/tests/javascript/soak.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: qpid/proton/branches/fadams-javascript-binding/tests/javascript/soak.js
------------------------------------------------------------------------------
    svn:executable = *



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org