Implement proton.Data.Binary and check end to end binary transfer, looks like it works OK but more testing needed
git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1588790 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/aa766d06 Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/aa766d06 Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/aa766d06 Branch: refs/heads/master Commit: aa766d067e31c72fb988c3d7f0b1614ca487e293 Parents: 2448135 Author: fadams <fadams@unknown> Authored: Sun Apr 20 16:46:08 2014 +0000 Committer: fadams <fadams@unknown> Committed: Sun Apr 20 16:46:08 2014 +0000 ---------------------------------------------------------------------- proton-c/bindings/javascript/CMakeLists.txt | 3 +- proton-c/bindings/javascript/binding.js | 180 +++++++++-------------- proton-c/bindings/javascript/spout.js | 10 +- 3 files changed, 81 insertions(+), 112 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/aa766d06/proton-c/bindings/javascript/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/proton-c/bindings/javascript/CMakeLists.txt b/proton-c/bindings/javascript/CMakeLists.txt index 19dc0a0..966d0ba 100644 --- a/proton-c/bindings/javascript/CMakeLists.txt +++ b/proton-c/bindings/javascript/CMakeLists.txt @@ -225,7 +225,8 @@ set_target_properties( LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --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 --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.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_m essenger_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_free', '_pn_message_get_address', '_pn_message_errno', '_pn_message_error', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_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_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']\"" ) - +# If the docs target is specified and the jsdoc3 package for node.js has been +# installed then build the JavaScript API documentation. if (NODE_JSDOC_FOUND) message(STATUS "Documentation Enabled") add_custom_target(docs-js COMMAND ${JSDOC_EXE} http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/aa766d06/proton-c/bindings/javascript/binding.js ---------------------------------------------------------------------- diff --git a/proton-c/bindings/javascript/binding.js b/proton-c/bindings/javascript/binding.js index 6559f11..41020e6 100644 --- a/proton-c/bindings/javascript/binding.js +++ b/proton-c/bindings/javascript/binding.js @@ -49,56 +49,6 @@ var Module = { }; - -/** - * This class is a buffer for use with the emscripten based port of zlib. It allows creation management of a - * buffer in the virtual heap space of the zlib library hiding the implementation detail from client code. - */ -/* -var Buffer = function(size) { - var _public = {}; - var asize = 0; // The allocated size of the input buffer. - var ptr = 0; // Handle to the input buffer. - - // Private methods. - function freeBuffer() { - if (ptr !== 0) { - _free(ptr); - } - }; - - // Public methods - _public.destroy = function() { - freeBuffer(); - }; - - _public.setSize = function(size) { - if (size > asize) { - freeBuffer(); - ptr = _malloc(size); // Get output buffer from emscripten. - asize = size; - } - _public.size = size; - }; - - _public.getRaw = function() { - return ptr; - }; - - _public.getBuffer = function() { - // Get a Uint8Array view on the input buffer. - return new Uint8Array(HEAPU8.buffer, ptr, _public.size); - }; - - if (size) { - _public.setSize(size); - } - - return _public; -}; -*/ - - /*****************************************************************************/ /* */ /* Status */ @@ -1515,6 +1465,18 @@ Data.Long.prototype.toString = function() { * @param {number} start an optional data pointer to the start of the Binary data buffer. */ Data['Binary'] = function(size, start) { // Data.Binary Constructor. + /* + * If the start pointer is specified then the underlying binary data is owned + * by another object, so we set the call to free to be a null function. If + * the start pointer is not passed then we allocate storage of the specified + * size on the emscripten heap and set the call to free to free the data from + * the emscripten heap. We have made the call to free a protected method that + * is only visible within the scope of the binding closure, clients should + * not have to call free themselves as the data is either already "owned" by + * a Data object or is destined to be passed to a Data object, which will in + * turn take responsibility for calling free once it has taken ownership of + * the underlying binary data. + */ if (start) { this.free = function() {}; } else { @@ -1528,7 +1490,7 @@ Data['Binary'] = function(size, start) { // Data.Binary Constructor. /* * Get a Uint8Array view of the data. N.B. this is just a *view* of the data, - * which will out of scope on the next call to {@link proton.Messenger.get}. If + * which will go out of scope on the next call to {@link proton.Messenger.get}. If * a client wants to retain the data then copyBuffer should be used to explicitly * create a copy of the data which the client then owns to do with as it wishes. * @method getBuffer @@ -1956,11 +1918,34 @@ _Data_['putUUID'] = function(u) { * Puts a binary value. * @method putBinary * @memberof! proton.Data# - * @param b a binary value. + * @param {proton.Data.Binary} b a binary value. */ -_Data_['putBinary'] = function(d) { -console.log("putBinary not properly implemented yet"); - this._check(_pn_data_put_binary(this._data, b)); +_Data_['putBinary'] = function(b) { +console.log("putBinary"); + + var sp = Runtime.stackSave(); + // The implementation here is a bit "quirky" due to some low-level details + // of the interaction between emscripten and LLVM and the use of pn_bytes. + // The JavaScript code below is basically a binding to: + // + // pn_data_put_binary(data, pn_bytes(b.size, b.start)); + + // Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but + // the low-level code handles this *by pointer* so we first need to allocate + // 8 bytes storage for {size, start} on the emscripten stack and then we + // pass the pointer to that storage as the first parameter to the compiled + // pn_bytes. + var bytes = allocate(8, 'i8', ALLOC_STACK); + _pn_bytes(bytes, b.size, b.start); + + // The compiled pn_data_put_binary takes the pn_bytes_t by reference not value. + this._check(_pn_data_put_binary(this._data, bytes)); + + // After calling _pn_data_put_binary the underlying data object "owns" the + // binary data, so we can call free on the proton.Data.Binary instance to + // release any storage it has acquired back to the emscripten heap. + b.free(); + Runtime.stackRestore(sp); }; /** @@ -2282,8 +2267,34 @@ _Data_['getUUID'] = function() { * @returns {proton.Data.Binary} value if the current node is a Binary, returns null otherwise. */ _Data_['getBinary'] = function() { -console.log("getBinary not properly implemented yet"); - //this._check(_pn_data_put_binary(this._data, b)); +console.log("getBinary"); + var sp = Runtime.stackSave(); + // The implementation here is a bit "quirky" due to some low-level details + // of the interaction between emscripten and LLVM and the use of pn_bytes. + // The JavaScript code below is basically a binding to: + // + // pn_bytes bytes = pn_data_get_binary(data); + + // Here's the quirky bit, pn_data_get_binary actually returns pn_bytes_t + // *by value* but the low-level code handles this *by pointer* so we first + // need to allocate 8 bytes storage for {size, start} on the emscripten stack + // and then we pass the pointer to that storage as the first parameter to the + // compiled pn_data_get_binary. + var bytes = allocate(8, 'i8', ALLOC_STACK); + _pn_data_get_binary(bytes, this._data); + + // The bytes variable is really of type pn_bytes_t* so we use emscripten's + // getValue() call to retrieve the size and then the start pointer. + var size = getValue(bytes, 'i32'); + var start = getValue(bytes + 4, '*'); + + // Create a proton.Data.Binary from the pn_bytes_t information. + var binary = new Data['Binary'](size, start); + + // Tidy up the memory that we allocated on emscripten's stack. + Runtime.stackRestore(sp); + + return binary; }; /** @@ -2484,6 +2495,8 @@ console.log("obj is quoted String " + quoted); } } else if (obj instanceof Data['UUID']) { this['putUUID'](obj); + } else if (obj instanceof Data['Binary']) { + this['putBinary'](obj); } else if (obj instanceof Data['Symbol']) { this['putSymbol'](obj); } else if (Data.isNumber(obj)) { @@ -2548,56 +2561,3 @@ _Data_.getObject = _Data_['getObject']; - - - - - - - - - - -/* -Module['Inflate'] = function(size) { - var _public = {}; - var stream = _inflateInitialise(); - var inputBuffer = Buffer(size); - var outputBuffer = Buffer(size); - - // Public methods - _public['destroy'] = function() { - _inflateDestroy(stream); - inputBuffer.destroy(); - outputBuffer.destroy(); - }; - - _public['reset'] = function() { - _inflateReset(stream); - }; - - _public['inflate'] = function(ptr) { - ptr = ptr ? ptr : outputBuffer.getRaw(); - var inflatedSize; // Pass by reference variable - need to use Module.setValue to initialise it. - setValue(inflatedSize, outputBuffer.size, 'i32'); - var err = _zinflate(stream, ptr, inflatedSize, inputBuffer.getRaw(), inputBuffer.size); - inflatedSize = getValue(inflatedSize, 'i32'); // Dereference the real inflatedSize value; - outputBuffer.setSize(inflatedSize); - return ((err < 0) ? err : inflatedSize); // Return the inflated size, or error code if inflation fails. - }; - - // Export methods from the input and output buffers for use by client code. - _public['setInputBufferSize'] = inputBuffer.setSize; - _public['getRawInputBuffer'] = inputBuffer.getRaw; - _public['getInputBuffer'] = inputBuffer.getBuffer; - - _public['setOutputBufferSize'] = outputBuffer.setSize; - _public['getRawOutBuffer'] = outputBuffer.getRaw; - _public['getOutputBuffer'] = outputBuffer.getBuffer; - - return _public; -}; -*/ - - - http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/aa766d06/proton-c/bindings/javascript/spout.js ---------------------------------------------------------------------- diff --git a/proton-c/bindings/javascript/spout.js b/proton-c/bindings/javascript/spout.js index 8bb8542..7d3cc58 100644 --- a/proton-c/bindings/javascript/spout.js +++ b/proton-c/bindings/javascript/spout.js @@ -70,6 +70,14 @@ console.log("exiting"); //message.body = msgtext; //message.body = new proton.Data.UUID(); //message.body = new proton.Data.Symbol("My Symbol"); + message.body = new proton.Data.Binary(4); + var buffer = message.body.getBuffer(); + buffer[0] = 65; + buffer[1] = 77; + buffer[2] = 81; + buffer[3] = 80; + + //message.body = true; //message.body = " \"127.0\" "; @@ -80,7 +88,7 @@ console.log("exiting"); //message.body = 2147483647.000001; // double //message.body = ['Rod', 'Jane', 'Freddy']; - message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}]; + //message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}]; tracker = messenger.put(message); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
