blob: 5c96cb5f8dda1d7a0f2555beb59c686494c4092a [file] [log] [blame]
/*
* 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.
*
*/
/*****************************************************************************/
/* */
/* Messenger */
/* */
/*****************************************************************************/
/**
* Constructs a proton.Messenger instance giving it an (optional) name. If name
* is supplied that will be used as the name of the Messenger, otherwise a UUID
* will be used. The Messenger is initialised to non-blocking mode as it makes
* little sense to have blocking behaviour in a JavaScript implementation.
* @classdesc The {@link proton.Messenger} class defines a high level interface for sending
* and receiving {@link proton.Message}. Every {@link proton.Messenger} contains a
* single logical queue of incoming messages and a single logical queue
* of outgoing messages. These messages in these queues may be destined
* for, or originate from, a variety of addresses.
* <p>
* The messenger interface is single-threaded.
* <pre>
* Address Syntax
* ==============
* </pre>
* An address has the following form:
* <pre>
* [ amqp[s]:// ] [user[:password]@] domain [/[name]]
* </pre>
* Where domain can be one of:
* <pre>
* host | host:port | ip | ip:port | name
* </pre>
* The following are valid examples of addresses:
* <pre>
* - example.org
* - example.org:1234
* - amqp://example.org
* - amqps://example.org
* - example.org/incoming
* - amqps://example.org/outgoing
* - amqps://fred:trustno1@example.org
* - 127.0.0.1:1234
* - amqps://127.0.0.1:1234
*
* Sending & Receiving Messages
* ============================
* </pre>
* The {@link proton.Messenger} class works in conjuction with the {@link proton.Message} class.
* The {@link proton.Message} class is a mutable holder of message content.
* <p>
* The put method copies its Message to the outgoing queue, and may
* send queued messages if it can do so without blocking.
* <pre>
* var message = new proton.Message();
* for (var i = 0; i < 3; i++) {
* message.setAddress("amqp://host/queue");
* message.setSubject = ("Hello World " + i);
* messenger.put(message);
* }
* </pre>
* Similarly, the recv method receives messages into the incoming
* queue. It may receive fewer than the requested number. The get method pops the
* eldest Message off the incoming queue and copies it into the Message
* object that you supply.
* <pre>
* var message = new proton.Message();
* messenger.recv(10);
* while (messenger.incoming() > 0) {
* messenger.get(message);
* console.log(message.getSubject());
* }
* Hello World 0
* Hello World 1
* Hello World 2
* </pre>
*
* @constructor proton.Messenger
* @param {string} name the name of this Messenger instance.
*/
Module['Messenger'] = function(name) { // Messenger Constructor.
/**
* The emscripten idiom below is used in a number of places in the JavaScript
* bindings to map JavaScript Strings to C style strings. ALLOC_STACK will
* increase the stack and place the item there. When the stack is next restored
* (by calling Runtime.stackRestore()), that memory will be automatically
* freed. In C code compiled by emscripten saving and restoring of the stack
* is automatic, but if we want to us ALLOC_STACK from native JavaScript we
* need to explicitly save and restore the stack using Runtime.stackSave()
* and Runtime.stackRestore() or we will leak emscripten heap memory.
* See https://github.com/kripken/emscripten/wiki/Interacting-with-code
* The _pn_messenger constructor copies the char* passed to it.
*/
var sp = Runtime.stackSave();
this._messenger = _pn_messenger(name ? allocate(intArrayFromString(name), 'i8', ALLOC_STACK) : 0);
Runtime.stackRestore(sp);
/**
* Initiate Messenger non-blocking mode. For JavaScript we make this the
* default behaviour and don't export this method because JavaScript is
* fundamentally an asynchronous non-blocking execution environment.
*/
_pn_messenger_set_blocking(this._messenger, false);
// Set the Messenger "passive" as we are supplying our own event loop here.
_pn_messenger_set_passive(this._messenger, true);
// Subscriptions that haven't yet completed, used for managing subscribe events.
this._pendingSubscriptions = [];
// Used in the Event registration mechanism (in the 'on' and 'emit' methods).
this._callbacks = {};
// This call ensures that the emscripten network callback functions are initialised.
Module.EventDispatch.registerMessenger(this);
};
Module['Messenger'].PN_CUMULATIVE = 0x1; // Protected Class attribute.
// Expose prototype as a variable to make method declarations less verbose.
var _Messenger_ = Module['Messenger'].prototype;
// ************************* Protected methods ********************************
// We use the dot notation rather than associative array form for protected
// methods so they are visible to this "package", but the Closure compiler will
// minify and obfuscate names, effectively making a defacto "protected" method.
/**
* This helper method checks the supplied error code, converts it into an
* exception and throws the exception. This method will try to use the message
* populated in pn_messenger_error(), if present, but if not it will fall
* back to using the basic error code rendering from pn_code().
* @param {number} code the error code to check.
*/
_Messenger_._check = function(code) {
if (code < 0 && code !== Module['Error']['INPROGRESS']) {
var errno = this['getErrno']();
var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
if (message !== 'PN_TIMEOUT') {
if (this._callbacks['error']) {
console.log("emitting " + message);
this._emit('error', new Module['MessengerError'](message));
} else {
console.log("throwing " + message);
throw new Module['MessengerError'](message);
}
}
}
return code;
};
/**
* Invokes the callbacks registered for a specified event.
* @method _emit
* @memberof! proton.Messenger#
* @param event {string} the event we want to emit.
* @param param {object} the parameter we'd like to pass to the event callback.
*/
_Messenger_._emit = function(event, param) {
var callbacks = this._callbacks[event];
if (callbacks) {
for (var i = 0; i < callbacks.length; i++) {
var callback = callbacks[i];
if ('function' === typeof callback) {
callback.call(this, param);
}
}
}
};
/**
* Checks any pending subscriptions and when a source address becomes available
* emit a subscription event passing the Subscription that triggered the event.
* Note that this doesn't seem to work for listen/bind style subscriptions,
* that is to say subscriptions of the form amqp://~0.0.0.0, don't know why?
* As a workaround the subscribe call emits a subscription event immediately for
* peer subscriptions to the local Messenger, this *should* be OK.
*/
_Messenger_._checkSubscriptions = function() {
// Check for completed subscriptions, and emit subscribe event.
var subscriptions = this._pendingSubscriptions;
if (subscriptions.length) {
var pending = []; // Array of any subscriptions that remain pending.
for (var j = 0; j < subscriptions.length; j++) {
subscription = subscriptions[j];
if (subscription['getAddress']()) {
this._emit('subscription', subscription);
} else {
pending.push(subscription);
}
}
this._pendingSubscriptions = pending;
}
};
// *************************** Public methods *****************************
/**
* N.B. The following methods are not exported by the JavaScript Messenger
* binding for reasons described below.
*
* For these methods it is expected that security would be implemented via
* a secure WebSocket. TODO what happens if we decide to implement TCP sockets
* via Node.js net library. If we do that we may want to compile OpenSSL
* using emscripten and include these methods.
* pn_messenger_set_certificate()
* pn_messenger_get_certificate()
* pn_messenger_set_private_key()
* pn_messenger_get_private_key()
* pn_messenger_set_password()
* pn_messenger_get_password()
* pn_messenger_set_trusted_certificates()
* pn_messenger_get_trusted_certificates()
*
* For these methods the implementation is fairly meaningless because JavaScript
* is a fundamentally asynchronous non-blocking environment.
* pn_messenger_set_timeout()
* pn_messenger_set_blocking()
* pn_messenger_interrupt()
* pn_messenger_work() - omitted because we have our own JavaScript Event loop.
*/
/**
* Registers a listener callback for a specified event.
* @method on
* @memberof! proton.Messenger#
* @param {string} event the event we want to listen for.
* @param {function} callback the callback function to be registered for the specified event.
*/
_Messenger_['on'] = function(event, callback) {
if ('function' === typeof callback) {
if (!this._callbacks[event]) {
this._callbacks[event] = [];
}
this._callbacks[event].push(callback);
}
};
/**
* Removes a listener callback for a specified event.
* @method removeListener
* @memberof! proton.Messenger#
* @param {string} event the event we want to detach from.
* @param {function} callback the callback function to be removed for the specified event.
* if no callback is specified all callbacks are removed for the event.
*/
_Messenger_['removeListener'] = function(event, callback) {
if (callback) {
var callbacks = this._callbacks[event];
if ('function' === typeof callback && callbacks) {
// Search for the specified callback.
for (var i = 0; i < callbacks.length; i++) {
if (callback === callbacks[i]) {
// If we find the specified callback, delete it and return.
callbacks.splice(i, 1);
return;
}
}
}
} else {
// If we call remove with no callback specified we remove all callbacks.
delete this._callbacks[event];
}
};
/**
* Retrieves the name of a Messenger.
* @method getName
* @memberof! proton.Messenger#
* @returns {string} the name of the messenger.
*/
_Messenger_['getName'] = function() {
return Pointer_stringify(_pn_messenger_name(this._messenger));
};
/**
* Retrieves the timeout for a Messenger.
* @method getTimeout
* @memberof! proton.Messenger#
* @returns {number} zero because JavaScript is fundamentally non-blocking.
*/
_Messenger_['getTimeout'] = function() {
return 0;
};
/**
* Accessor for messenger blocking mode.
* @method isBlocking
* @memberof! proton.Messenger#
* @returns {boolean} false because JavaScript is fundamentally non-blocking.
*/
_Messenger_['isBlocking'] = function() {
return false;
};
/**
* Free the Messenger. This will close all connections that are managed
* by the Messenger. Call the stop method before destroying the Messenger.
* <p>
* N.B. This method has to be called explicitly in JavaScript as we can't
* intercept finalisers, so we need to remember to free before removing refs.
* @method free
* @memberof! proton.Messenger#
*/
_Messenger_['free'] = function() {
// This call ensures that the emscripten network callback functions are removed.
Module.EventDispatch.unregisterMessenger(this);
_pn_messenger_free(this._messenger);
};
/**
* @method getErrno
* @memberof! proton.Messenger#
* @returns {number} the most recent error message code.
*/
_Messenger_['getErrno'] = function() {
return _pn_messenger_errno(this._messenger);
};
/**
* @method getError
* @memberof! proton.Messenger#
* @returns {string} the most recent error message as a String.
*/
_Messenger_['getError'] = function() {
return Pointer_stringify(_pn_error_text(_pn_messenger_error(this._messenger)));
};
/**
* Returns the size of the outgoing window that was set with setOutgoingWindow.
* The default is 0.
* @method getOutgoingWindow
* @memberof! proton.Messenger#
* @returns {number} the outgoing window size.
*/
_Messenger_['getOutgoingWindow'] = function() {
return _pn_messenger_get_outgoing_window(this._messenger);
};
/**
* Sets the outgoing tracking window for the Messenger. The Messenger will
* track the remote status of this many outgoing deliveries after calling
* send. Defaults to zero.
* <p>
* A Message enters this window when you call put() with the Message.
* If your outgoing window size is n, and you call put() n+1 times, status
* information will no longer be available for the first Message.
* @method setOutgoingWindow
* @memberof! proton.Messenger#
* @param {number} window the size of the tracking window in messages.
*/
_Messenger_['setOutgoingWindow'] = function(window) {
_pn_messenger_set_outgoing_window(this._messenger, window);
};
/**
* Returns the size of the incoming window that was set with setIncomingWindow.
* The default is 0.
* @method getIncomingWindow
* @memberof! proton.Messenger#
* @returns {number} the incoming window size.
*/
_Messenger_['getIncomingWindow'] = function() {
return _pn_messenger_get_incoming_window(this._messenger);
};
/**
* Sets the incoming tracking window for the Messenger. The Messenger will
* track the remote status of this many incoming deliveries after calling
* send. Defaults to zero.
* <p>
* Messages enter this window only when you take them into your application
* using get(). If your incoming window size is n, and you get() n+1 messages
* without explicitly accepting or rejecting the oldest message, then the
* Message that passes beyond the edge of the incoming window will be assigned
* the default disposition of its link.
* @method setIncomingWindow
* @memberof! proton.Messenger#
* @param {number} window the size of the tracking window in messages.
*/
_Messenger_['setIncomingWindow'] = function(window) {
_pn_messenger_set_incoming_window(this._messenger, window);
};
/**
* Currently a no-op placeholder. For future compatibility, do not send or
* recv messages before starting the Messenger.
* @method start
* @memberof! proton.Messenger#
*/
_Messenger_['start'] = function() {
this._check(_pn_messenger_start(this._messenger));
};
/**
* Transitions the Messenger to an inactive state. An inactive Messenger
* will not send or receive messages from its internal queues. A Messenger
* should be stopped before being discarded to ensure a clean shutdown
* handshake occurs on any internally managed connections.
* <p>
* The Messenger may require some time to stop if it is busy, so it is
* necessary to call isStopped to see if it has fully stopped.
* @method stop
* @memberof! proton.Messenger#
*/
_Messenger_['stop'] = function() {
_pn_messenger_stop(this._messenger);
// When we call stop it's quite likely that it will be busy. We call
// Module.EventDispatch.pump to flush the Messenger Event loop, but we
// wrap the call in a setTimeout to make sure that any Events generated
// by the flush occur on the next "tick" of the JavaScript Event loop.
setTimeout(Module.EventDispatch.pump, 0);
};
/**
* Returns true iff a Messenger is in the stopped state.
* @method isStopped
* @memberof! proton.Messenger#
* @returns {boolean} true iff a Messenger is in the stopped state.
*/
_Messenger_['isStopped'] = function() {
return (_pn_messenger_stopped(this._messenger) > 0);
};
/**
* Subscribes the Messenger to messages originating from the
* specified source. The source is an address as specified in the
* Messenger introduction with the following addition. If the
* domain portion of the address begins with the '~' character, the
* Messenger will interpret the domain as host/port, bind to it,
* and listen for incoming messages. For example "~0.0.0.0",
* "amqp://~0.0.0.0", and "amqps://~0.0.0.0" will all bind to any
* local interface and listen for incoming messages with the last
* variant only permitting incoming SSL connections.
* @method subscribe
* @memberof! proton.Messenger#
* @param {string} source the source address we're subscribing to.
* @returns {Subscription} a subscription.
*/
_Messenger_['subscribe'] = function(source) {
if (!source) {
this._emit('error', new Module['SubscriptionError'](source, 'CONNECTION ERROR: Address not specified'));
} else {
return Module.EventDispatch.subscribe(this, source);
}
};
/**
* 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 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
* message queue, you may then modify or discard the Message object
* without having any impact on the content in the outgoing queue.
* <p>
* This method returns an outgoing tracker for the Message. The tracker
* can be used to determine the delivery status of the Message.
* @method put
* @memberof! proton.Messenger#
* @param {proton.Message} message a Message to send.
* @returns {proton.Data.Long} a tracker.
*/
_Messenger_['put'] = function(message) {
message._preEncode();
this._check(_pn_messenger_put(this._messenger, message._message));
// 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
// low/high pair around to methods that require a tracker.
var low = _pn_messenger_outgoing_tracker(this._messenger);
var high = Runtime.getTempRet0();
return new Data.Long(low, high);
};
/**
* Send messages from a Messenger's outgoing queue. This method forces the Event
* loop to pump data for as long as the underlying socket remains writeable.
* Note that after calling send() applications should yield control to the JavaScript
* Event loop by calling setTimeout() or process.nextTick() so that the underlying
* network processing can actually take place.
* @method send
* @memberof! proton.Messenger#
*/
_Messenger_['send'] = function(number) {
Module.EventDispatch.pump();
};
/**
* Gets the aggregate bufferedAmount values from all of the underlying WebSockets.
* This value represents the amount of data buffered but not yet sent over the
* network. If it grows too high it is a sign that the application is sending too
* much data and should be throttled by yielding control to the JavaScript Event loop.
* @method getBufferedAmount
* @memberof! proton.Messenger#
* @returns {number} the total amount of data buffered by the Messenger's sockets.
*/
_Messenger_['getBufferedAmount'] = function() {
return Module.EventDispatch.getBufferedAmount(this);
};
/**
* Gets the last known remote state of the delivery associated with the given tracker.
* @method status
* @memberof! proton.Messenger#
* @param {proton.Data.Long} tracker the tracker whose status is to be retrieved.
* @returns {proton.Status} one of None, PENDING, REJECTED, or ACCEPTED.
*/
_Messenger_['status'] = function(tracker) {
if (tracker == null) { // Use == not === to check for both null and undefined.
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());
};
/**
* Checks if the delivery associated with the given tracker is still waiting to be sent.
* @method isBuffered
* @memberof! proton.Messenger#
* @param {proton.Data.Long} tracker the tracker identifying the delivery.
* @returns {boolean} true if delivery is still buffered.
*/
_Messenger_['isBuffered'] = function(tracker) {
if (tracker == null) { // Use == not === to check for both null and undefined.
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);
};
/**
* Frees a Messenger from tracking the status associated with a given tracker.
* If you don't supply a tracker, all outgoing messages up to the most recent
* will be settled.
* @method settle
* @memberof! proton.Messenger#
* @param {proton.Data.Long} tracker the tracker identifying the delivery.
*/
_Messenger_['settle'] = function(tracker) {
// 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
// low/high pair around to methods that require a tracker.
var flags = 0;
if (tracker == null) { // Use == not === to check for both null and undefined.
var low = _pn_messenger_outgoing_tracker(this._messenger);
var high = Runtime.getTempRet0();
tracker = new Data.Long(low, high);
flags = Module['Messenger'].PN_CUMULATIVE;
}
_pn_messenger_settle(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits(), flags);
};
/**
* Receives up to limit messages into the incoming queue. If no value for limit
* is supplied, this call will receive as many messages as it can buffer internally.
* @method recv
* @memberof! proton.Messenger#
* @param {number} limit the maximum number of messages to receive. If unspecified
* receive as many messages as it can buffer internally.
*/
_Messenger_['recv'] = function(limit) {
_pn_messenger_recv(this._messenger, (limit ? limit : -1));
};
/**
* Returns the capacity of the incoming message queue of messenger. Note this
* count does not include those messages already available on the incoming queue.
* @method receiving
* @memberof! proton.Messenger#
* @returns {number} the message queue capacity.
*/
_Messenger_['receiving'] = function() {
return _pn_messenger_receiving(this._messenger);
};
/**
* Moves the message from the head of the incoming message queue into the
* supplied message object. Any content in the message will be overwritten.
* <p>
* A tracker for the incoming Message is returned. The tracker can later be
* used to communicate your acceptance or rejection of the Message.
* @method get
* @memberof! proton.Messenger#
* @param {proton.Message} message the destination message object. If no Message
* object is supplied, the Message popped from the head of the queue is discarded.
* @param {boolean} decodeBinaryAsString if set decode any AMQP Binary payload
* objects as strings. This can be useful as the data in Binary objects
* will be overwritten with subsequent calls to get, so they must be
* explicitly copied. Needless to say it is only safe to set this flag if
* you know that the data you are dealing with is actually a string, for
* example C/C++ applications often seem to encode strings as AMQP binary,
* a common cause of interoperability problems.
* @returns {proton.Data.Long} a tracker for the incoming Message.
*/
_Messenger_['get'] = function(message, decodeBinaryAsString) {
var impl = null;
if (message) {
impl = message._message;
}
_pn_messenger_get(this._messenger, impl);
if (message) {
message._postDecode(decodeBinaryAsString);
}
// 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
// low/high pair around to methods that require a tracker.
var low = _pn_messenger_incoming_tracker(this._messenger);
var high = Runtime.getTempRet0();
return new Data.Long(low, high);
};
/**
* Returns the Subscription of the Message returned by the most recent call
* to get, or null if pn_messenger_get has not yet been called.
* @method incomingSubscription
* @memberof! proton.Messenger#
* @returns {Subscription} a Subscription or null if get has never been called
* for this Messenger.
*/
_Messenger_['incomingSubscription'] = function() {
var subscription = _pn_messenger_incoming_subscription(this._messenger);
if (subscription) {
return new Subscription(subscription);
} else {
return null;
}
};
/**
* Signal the sender that you have acted on the Message pointed to by the tracker.
* If no tracker is supplied, then all messages that have been returned by the
* get method are accepted, except those that have already been auto-settled
* by passing beyond your incoming window size.
* @method accept
* @memberof! proton.Messenger#
* @param {proton.Data.Long} tracker the tracker identifying the delivery.
*/
_Messenger_['accept'] = function(tracker) {
// 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
// low/high pair around to methods that require a tracker.
var flags = 0;
if (tracker == null) { // Use == not === to check for both null and undefined.
var low = _pn_messenger_incoming_tracker(this._messenger);
var high = Runtime.getTempRet0();
tracker = new Data.Long(low, high);
flags = Module['Messenger'].PN_CUMULATIVE;
}
this._check(_pn_messenger_accept(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits(), flags));
};
/**
* Rejects the Message indicated by the tracker. If no tracker is supplied,
* all messages that have been returned by the get method are rejected, except
* those already auto-settled by passing beyond your outgoing window size.
* @method reject
* @memberof! proton.Messenger#
* @param {proton.Data.Long} tracker the tracker identifying the delivery.
*/
_Messenger_['reject'] = function(tracker) {
// 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
// low/high pair around to methods that require a tracker.
var flags = 0;
if (tracker == null) { // Use == not === to check for both null and undefined.
var low = _pn_messenger_incoming_tracker(this._messenger);
var high = Runtime.getTempRet0();
tracker = new Data.Long(low, high);
flags = Module['Messenger'].PN_CUMULATIVE;
}
this._check(_pn_messenger_reject(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits(), flags));
};
/**
* Returns the number of messages in the outgoing message queue of a messenger.
* @method outgoing
* @memberof! proton.Messenger#
* @returns {number} the outgoing queue depth.
*/
_Messenger_['outgoing'] = function() {
return _pn_messenger_outgoing(this._messenger);
};
/**
* Returns the number of messages in the incoming message queue of a messenger.
* @method incoming
* @memberof! proton.Messenger#
* @returns {number} the incoming queue depth.
*/
_Messenger_['incoming'] = function() {
return _pn_messenger_incoming(this._messenger);
};
/**
* Adds a routing rule to a Messenger's internal routing table.
* <p>
* The route method may be used to influence how a messenger will internally treat
* a given address or class of addresses. Every call to the route method will
* result in messenger appending a routing rule to its internal routing table.
* <p>
* Whenever a message is presented to a messenger for delivery, it will match the
* address of this message against the set of routing rules in order. The first
* rule to match will be triggered, and instead of routing based on the address
* presented in the message, the messenger will route based on the address supplied
* in the rule.
* <p>
* The pattern matching syntax supports two types of matches, a '' will match any
* character except a '/', and a '*' will match any character including a '/'.
* <p>
* A routing address is specified as a normal AMQP address, however it may
* additionally use substitution variables from the pattern match that triggered
* the rule.
* <p>
* Any message sent to "foo" will be routed to "amqp://foo.com":
* <pre>
* route("foo", "amqp://foo.com");
* </pre>
* Any message sent to "foobar" will be routed to "amqp://foo.com/bar":
* <pre>
* route("foobar", "amqp://foo.com/bar");
* </pre>
* Any message sent to bar/<path> will be routed to the corresponding path within
* the amqp://bar.com domain:
* <pre>
* route("bar/*", "amqp://bar.com/$1");
* </pre>
* Supply credentials for foo.com:
* <pre>
* route("amqp://foo.com/*", "amqp://user:password@foo.com/$1");
* </pre>
* Supply credentials for all domains:
* <pre>
* route("amqp://*", "amqp://user:password@$1");
* </pre>
* Route all addresses through a single proxy while preserving the original destination:
* <pre>
* route("amqp://%/*", "amqp://user:password@proxy/$1/$2");
* </pre>
* Route any address through a single broker:
* <pre>
* route("*", "amqp://user:password@broker/$1");
* </pre>
* @method route
* @memberof! proton.Messenger#
* @param {string} pattern a glob pattern to select messages.
* @param {string} address an address indicating outgoing address rewrite.
*/
_Messenger_['route'] = function(pattern, address) {
var sp = Runtime.stackSave();
_pn_messenger_route(this._messenger,
allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
allocate(intArrayFromString(address), 'i8', ALLOC_STACK));
Runtime.stackRestore(sp);
};
/**
* Rewrite message addresses prior to transmission.
* <p>
* Similar to route(), except that the destination of the Message is determined
* before the message address is rewritten.
* <p>
* The outgoing address is only rewritten after routing has been finalized. If
* a message has an outgoing address of "amqp://0.0.0.0:5678", and a rewriting
* rule that changes its outgoing address to "foo", it will still arrive at the
* peer that is listening on "amqp://0.0.0.0:5678", but when it arrives there,
* the receiver will see its outgoing address as "foo".
* <p>
* The default rewrite rule removes username and password from addresses
* before they are transmitted.
* @method rewrite
* @memberof! proton.Messenger#
* @param {string} pattern a glob pattern to select messages.
* @param {string} address an address indicating outgoing address rewrite.
*/
_Messenger_['rewrite'] = function(pattern, address) {
var sp = Runtime.stackSave();
_pn_messenger_rewrite(this._messenger,
allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
allocate(intArrayFromString(address), 'i8', ALLOC_STACK));
Runtime.stackRestore(sp);
};