diffusion
Version:
Diffusion JavaScript client
704 lines (671 loc) • 30 kB
JavaScript
var _interface = require('util/interface')._interface;
/**
* Messages Feature.
* <P>
* This feature provides a client session with messaging capabilities. Each
* message is delivered to a request stream registered with the server.
* Additionally, the server and other clients can send messages to be received
* using this feature.
* <P>
* Message requests are sent and received for a particular path. The message
* path provides a hierarchical context for the recipient.
* <P>
* Message paths are distinct from topic paths. A topic with the path need not
* exist on the server; if a topic does exist, it is unaffected by messaging. An
* application can use the same path to associate messages with topics, or an
* arbitrary path can be chosen.
* <P>
* A message request sent directly to another session is discarded if the
* receiving session is no longer connected or does not have a stream that
* matches the message path - an error is returned to the sending session in
* this case.
* <P>
* Handlers for receiving messages are registered for a path. Each session may
* register at most one handler for a given path. When dispatching a message,
* the server will consider all registered handlers and select one registered
* for the most specific path. If multiple sessions have registered a handler
* registered for a path, one will be chosen arbitrarily.
* <P>
* When registering handlers to receive messages it is also possible to indicate
* that certain session properties (see {@link Session} for a full description
* of session properties), should be delivered with each message from a client
* session. The current values of the named properties for the originating
* session will be delivered with the message.
* <P>
* Messages can also be sent using 'filters', (see {@link Session} for a full
* description of session filters), where the message is delivered to all
* sessions that satisfy a particular filter expression.
* <P>
* Messages from other clients are received via
* {@link Session.messages.RequestStream streams}. Streams receive an
* {@link Session.messages.RequestStream#onClose onClose} callback when
* unregistered and an {@link Session.messages.RequestStream#onError onError}
* callback if the session is closed.
* <H3>Request-Response Messaging</H3>
* Typed request-response messaging allows applications to send requests (of
* type T) and receive responses (of type R) in the form of a {@link Result}.
* Using Messaging, applications send requests to paths using
* {@link Session.messages.Messaging#sendRequest sendRequest}. In order to
* receive requests, applications must have a local request stream assigned to
* the specific path, using {@link Session.messages#setRequestStream
* setRequestStream}. When a request is received, the {@link
* Session.messages.RequestStream#onRequest onRequest} method on the stream is
* triggered, to which a response can be sent using the provided {@link
* Session.messages.Responder#respond respond} method call.
* <H3>One-way Messaging (deprecated)</H3>
* One-way messaging allows a client to
* send an untyped message to be sent to a path and be notified that the message
* has been delivered. No response is possible.
* <p>
* A client can listen for one-way messages for a selection of paths by
* {@link #listen adding} one or more
* {@link MessageStream} implementations. The mapping of selectors to message
* streams is maintained locally in the client process. Any number of message
* streams for inbound messages can be added on various selectors. If a message
* is received on a message path that matches with no message streams, it is
* passed to any {@link #addFallbackMessageStream fallback message streams} that
* have been registered.
*
* <H3>Access control</H3>
* A client session needs
* {@link TopicPermission#SEND_TO_MESSAGE_HANDLER SEND_TO_MESSAGE_HANDLER}
* permission for the message paths to which it sends messages. If a client
* sends messages to a message path for which it does not have permission, the
* message is discarded by the server.
*
* <H3>Accessing the feature</H3>
* Obtain this feature from a {@link Session session} as follows:
*
* @example
* // Get a reference to messaging feature
* var messages = session.messages;
*
* @namespace Session.messages
*/
var Messages = _interface('Messaging', [
/**
* Send an arbitrary message to either the server or another session, on a particular path.
* <P>
* The path does not need to correspond to an existing topic; however the use of <code>/</code> as a hierarchical
* delimiter allows for other sessions to listen to messages from specific paths.
* <P>
* The message content may be of any type that can be used for topic {@link Session.topics#update updates}. It is
* up to any receiving session to de-serialize it as appropriate.
* <P>
* An optional argument may be provided to target a specific session or a collection of sessions that satisfy a
* given filter string. Messages sent will be received if that session has established a {@link
* Session.messages.MessageStream MessageStream} for the same message path. The ability to send messages to specific
* sessions or via a filter is determined by permissions assigned to the sender.
* <P>
* If no session ID or filter is given, the message will be sent to the server and dispatched to a control client
* that has registered a {@link Session.messages.MessageHandler MessageHandler} for the same, or higher, path.
* There is no guarantee that a MessageHandler will have been established for the path that the message is sent on.
* <P>
* If no recipient is specified, a successful result will resolve with a single object containing the
* <code>path</code> that the message was sent to.
* <P>
* If a session ID was used as the recipient, then the result will resolve with an object containing both
* <code>path</code> and <code>recipient</code> fields. The result will only resolve when the message has
* been successfully received by the intended recipient.
* <P>
* If a session filter was used to send the message, then the result will contain <code>path</code>,
* <code>recipient</code>, <code>sent</code> and <code>errors</code> fields. The <code>sent</code> field specifies
* the number of sessions that the filter resolved and successfully sent the message to. The <code>errors</code>
* field contains an array of errors for any session that could not receive the message.
*
* @example
* // Send a message to be received by the server and passed to a MessageHandler
* session.messages.send('foo', 123);
*
* @example
* // Send a message to a specific session
* session.messages.send('bar', 'hello', sessionID);
*
* @example
* // Send a message with a filter
* session.messages.send('baz', 'world', '$Principal is "john"');
*
* @param {String} path - The message path
* @param {Object} message - The message value
* @param {Session.messages.SendOptions} [options] - The optional message send options
* @param {(String|Object)} [target] - The target recipient's session ID (as a string or
* Session ID object) or a session property filter string.
* @returns {Result<Session.messages.MessageSendResult>} The
* {@link Result<Session.messages.MessageSendResult>} of the send operation
* @function Session.messages#send
*
* @deprecated since 6.2
* <p>
* One-way messaging is deprecated in favor of request-response
* messaging. Use {@link Session.messages#sendRequest
* sendRequest} instead. This method will be removed in a future
* release.
*/
'send',
/**
* Listen to a stream of messages sent to this Session for a particular path. Messages will be received as
* {@link Session.messages.Message message} instances.
* <P>
* The message content is dependent on the sender. Correct parsing of the message content from a <code>Buffer</code>
* is up to the consuming session.
* <P>
* Received messages do not indicate which session sent them; if sender information is required then this should be
* included within the message content.
* <P>
* The first argument of this function can be a string, a {@link TopicSelector}, or an array of strings and
* {@link TopicSelector}s.
*
* @example
* // Create with a default listener function
* session.messages.listen('foo', function(message) {
* // Do something with the message
* });
*
* @example
* // Create a message stream and consume from it
* var stream = session.messages.listen('foo');
*
* stream.on('message', function(message) {
* // Do something with the message
* });
*
* @param {String | TopicSelector | String[]} path - The message path
* @param {Function} [listener] - The default listener
* @returns {Session.messages.MessageStream} A stream providing messages received on the specific path
* @function Session.messages#listen
*
* @deprecated since 6.2
* <p>
* One-way messaging is deprecated in favor of request-response
* messaging. See {@link #sendRequest sendRequest} and
* {@link #sendRequestToFilter sendRequestToFilter}. This method
* will be removed in a future release.
*/
'listen',
/**
* Register a {@link Session.messages.MessageHandler MessageHandler} to receive messages that were sent from other
* sessions for a particular path but with no specified recipient. The handler must implement the
* {@link Session.messages.MessageHandler MessageHandler} interface.
* <P>
* The provided handler will be passed messages received on the same path used for registration, or any lower
* branches. A session may only register a single handler for a given path at a time.
* <P>
* The message content is dependent on the sender. Correct parsing of the message content from a <code>Buffer</code>
* is up to the consuming handler.
* <P>
* Unlike {@link Session.messages#listen}, received messages provide the sender's SessionId.
*
* @example
* // Create a message handler
* var handler = {
* onMessage : function(message) {
* console.log(message); // Log the received message
* },
* onActive : function(unregister) {
*
* },
* onClose : function() {
*
* }
* };
*
* // Register the handler
* session.messages.addHandler('foo/bar', handler).then(function() {
* // Registration happened successfully
* }, function(error) {
* // Registration failed
* });
*
*
* @param {String} path - The message path to handle
* @param {Session.messages.MessageHandler} handler - The message handler
* @param {Array} [keys] - Message keys to register for this session
* @returns {Result<undefined>} The registration {@link Result<undefined>}
* @function Session.messages#addHandler
*
* @deprecated since 6.2
* <p>
* One-way messaging is deprecated in favor of request-response
* messaging. See {@link #sendRequest sendRequest} and
* {@link #sendRequestToFilter sendRequestToFilter}. This method
* will be removed in a future release.
*/
'addHandler',
/**
* Register a request handler to handle requests from other client sessions on a path.
*
* @example
* // Create a request handler that handles strings
* var handler = {
* onRequest: function(request, context, responder) {
* console.log(request); // Log the request
* responder.respond('something');
* },
* onError: function() {},
* onClose: function() {}
* };
*
* // Register the handler
* control.messages.addRequestHandler('test/topic', handler).then(function() {
* // Registration happened successfully
* }, function(error) {
* // Registration failed
* });
*
* @param {String} path - The request path to handle
* @param {Session.messages.RequestHandler} handler - Request handler to be registered at the server
* @param {Array} [sessionProperties] - An optional array containing session properties that should be
* included with each request
* @param {Function} [requestType] - An optional request {@link diffusion.datatypes.DataType DataType}
* @returns {Result<Registration>} The registration {@link Result<Registration>}
* @function Session.messages#addRequestHandler
*/
'addRequestHandler',
/**
* Send a request.
*
* A response is returned when the {Result} is complete.
*
* @example
* // Send a string request to be received by the server and passed to a
* // {Session.messages.RequestHandler} registered on the supplied topic
* session.messages.sendRequest('test/topic', 'string request');
*
* @example
* // Send a JSON request to be received by the server and passed to a
* // {Session.messages.RequestHandler} registered on the supplied topic
* session.messages.sendRequest('test/topic', diffusion.datatypes.json()
* .from({ "foo": "bar"}), diffusion.datatypes.json());
*
* @example
* // Send an implicit JSON request to be received by the server and passed to a
* // {Session.messages.RequestHandler} registered on the supplied topic
* session.messages.sendRequest('test/topic', {
* dwarfs: ['sneezy', 'sleepy','dopey',
* 'doc', 'happy', 'bashful',
* 'grumpy']
* });
*
* @param {String} path - The path to send the request to
* @param {Object} request - The request to send
* @param {(String|Object)} [target] - The target recipient's session ID (as a string or Session ID object)
* @param {Function} [requestType] - An optional request {@link diffusion.datatypes.DataType DataType}
* @param {Function} [responseType] - An optional response {@link diffusion.datatypes.DataType DataType}
* @returns {Result} A {Result} containing the response
* @function Session.messages#sendRequest
*/
'sendRequest',
/**
* Send a request to all sessions that satisfy a given session filter.
*
* @example
* // Send a string request to be received by the server and passed to sessions matching the filter.
* session.messages.sendRequestToFilter('$Principal NE "control"', 'test/topic', 'string request', {
* onResponse : function(sessionID, response) {
* console.log(response); // Log the response
* },
* onResponseError : function() {},
* onError : function() {},
* onClose : function() {}});
*
* @example
* // Send a JSON request to be received by the server and passed to sessions matching the filter.
* session.messages.sendRequestToFilter('$Principal NE "control"', 'test/topic',
* { dwarfs: ['sneezy', 'sleepy','dopey' ] },
* {
* onResponse : function(sessionID, response) {
* console.log(response.get()); // Log the response
* },
* onResponseError : function() {},
* onError : function() {},
* onClose : function() {}}, diffusion.datatypes.json(), diffusion.datatypes.json());
*
* @param {String} filter - The session filter expression
* @param {String} path - Message path used by the recipient to select an appropriate handler
* @param {Object} request - The request to send
* @param {Session.messages.FilteredResponseHandler} callback - The handler to receive notification of responses
* (or errors) from sessions
* @param {Function} [requestType] - An optional request {@link diffusion.datatypes.DataType DataType}
* @param {Function} [responseType] - An optional response {@link diffusion.datatypes.DataType DataType}
* @returns {Result} If the server successfully evaluated the filter, the result contains
* the number of sessions the request was sent to. Failure to send a request to a particular matching
* session is reported to the handler.
* @function Session.messages#sendRequestToFilter
*/
'sendRequestToFilter',
/**
* Set a request stream to handle requests to a specified path.
*
* @example
* // Set a request stream handler to handle string requests to 'test/topic'
* var handler = {
* onRequest: function (path, request, responder) {
* console.log(request);
* responder.respond('hello');
* },
* onError: function() {}
* };
*
* control.messages.setRequestStream('test/topic', handler,
* diffusion.datatypes.string(), diffusion.datatypes.string());
*
* @param {String} path - The path to receive request on
* @param {Session.messages.RequestStream} stream - The request stream to handle requests to this path
* @param {Function} [requestType] - An optional request {@link diffusion.datatypes.DataType DataType}
* @param {Function} [responseType] - An optional response {@link diffusion.datatypes.DataType DataType}
* @returns {Session.messages.RequestStream} Null if the request stream is the first stream to be set to
* the path, otherwise this method will return the previously set request stream.
* @function Session.messages#setRequestStream
*/
'setRequestStream',
/**
* Remove the request stream at a particular path.
*
* @param {String} path - The path at which to remove the request stream
* @returns {Session.messages.RequestStream} stream - The request stream that was removed from the path. If
* the path does not have a request stream assigned (or the path does not exist), null will be
* returned instead.
* @function Session.messages#removeRequestStream
*/
'removeRequestStream'
]);
/**
* A stream of messages sent to this session for a particular path.
*
* @fires Stream#error
* @fires Stream#close
* @fires Session.messages.MessageStream#message
*
* @class Session.messages.MessageStream
* @augments Stream
*
* @deprecated since 6.2
* <p>
* One-way messaging is deprecated in favor of request-response
* messaging. See {@link Session.messages.#sendRequest sendRequest}
* and {@link Session.messages.#sendRequestToFilter
* sendRequestToFilter}. This interface will be removed in a future
* release.
*/
Messages.MessageStream = _interface('MessageStream',[
/**
* Emitted when a new message is received.
*
* @event Session.messages.MessageStream#message
* @property {Session.messages.Message} message - the message that has been delivered.
*/
]);
/**
* The handler interface for receiving messages sent from sessions to the server. This interface must be implemented by
* the user, to be registered via {@link Session.messages#addHandler}.
* <P>
* <br/>
* A message handler has a lifecycle that reflects the registration state on the server. This is expressed through the
* callback methods. Once {@link Session.messages.MessageHandler#onClose onClose} has been closed, no further
* interactions will occur.
* <P>
* {@link Session.messages.SessionMessage Messages} received by a handler contain the identity of the original sender.
*
* @class Session.messages.MessageHandler
*
* @deprecated since 6.2
* <p>
* One-way messaging is deprecated in favor of request-response
* messaging. See {@link Session.messages.#sendRequest sendRequest}
* and {@link Session.messages.#sendRequestToFilter
* sendRequestToFilter}. This interface will be removed in a future
* release.
*/
Messages.MessageHandler = _interface('MessageHandler', [
/**
* Handle a message that was sent by another session to the server, on a path that is a descendant of the path
* which this handler is registered for.
*
* @param {Session.messages.SessionMessage} message - The received message
* @function Session.messages.MessageHandler#onMessage
*/
'onMessage',
/**
* Called when the handler has been registered at the server and is now active.
*
* @param {Function} unregister - A function to call that will unregister and close this handler
* @function Session.messages.MessageHandler#onActive
*/
'onActive',
/**
* Called when the handler is unregistered, or the session is closed.
*
* @function Session.messages.MessageHandler#onClose
*/
'onClose'
]);
/**
* Interface which specifies a request stream to receive request notifications.
*
* @class Session.messages.RequestStream
*/
Messages.RequestStream = _interface('RequestStream', [
/**
* Called to indicate a request has been received.
*
* @param {String} path - The path the request was sent on
* @param {Object} request - The request that was received
* @param {Session.messages.Responder} responder - The responder to dispatch a response back to the requester
* @function Session.messages.RequestStream#onRequest
*/
'onRequest',
/**
* Notification of a contextual error related to this stream. This is
* analogous to an Error being thrown. Situations in which
* <code>onError</code> is called include being unable to parse the request
* with the data type the stream was registered with. No further calls will
* be made to this stream.
*
* @param {Error} error - The error
* @function Session.messages.RequestStream#onError
*/
'orError',
/**
* Called when the request stream is removed, or the session is closed.
*
* @function Session.messages.RequestStream#onClose
*/
'onClose'
]);
/**
* Interface which specifies a request handler to receive request notifications.
*
* @class Session.messages.RequestHandler
*/
Messages.RequestHandler = _interface('RequestHandler', [
/**
* Called to indicate a request has been received.
*
* @param {Object} request - The request that was received
* @param {Session.messages.RequestContext} context - Context object that provides the session id
* (session that sent the request), path and session properties
* @param {Session.messages.Responder} responder - The responder to dispatch a response back to the requester
* @function Session.messages.RequestHandler#onRequest
*/
'onRequest',
/**
* Notification of a contextual error related to this handler. This is
* analogous to an Error being thrown. Situations in which
* <code>onError</code> is called include the session being closed before the
* handler is registered, a communication timeout, or a problem with the
* provided parameters. No further calls will be made to this handler.
*
* @param {Object} error - The error
* @function Session.messages.RequestHandler#onError
*/
'onError',
/**
* Called when the request handler is unregistered, or the session is closed.
*
* @function Session.messages.RequestHandler#onClose
*/
'onClose'
]);
/**
* Interface which specifies a response handler for requests dispatched through a filter.
*
* @class Session.messages.FilteredResponseHandler
*/
Messages.FilteredResponseHandler = _interface('FilteredResponseHandler', [
/**
* Called to indicate a response has been received.
*
* @param {Object} sessionId - SessionID of the session that sent the response
* @param {Object} response - Response object
* @function Session.messages.FilteredResponseHandler#onResponse
*/
'onResponse',
/**
* Called when a response from a session results in an error.
*
* @param {Object} sessionId - SessionID of the session in error
* @param {Error} errorReason - The error reason
* @function Session.messages.FilteredResponseHandler#onResponseError
*/
'onResponseError',
/**
* Notification of a contextual error related to this handler. This is
* analogous to an Error being thrown. Situations in which
* <code>onError</code> is called include the session being closed before the
* handler is registered, a communication timeout, or a problem with the
* provided parameters. No further calls will be made to this handler.
*
* @param {Error} error - The error
* @function Session.messages.FilteredResponseHandler#onError
*/
'onError',
/**
* Called when the filtered response handler is unregistered, or the session is closed.
*
* @function Session.messages.FilteredResponseHandler#onClose
*/
'onClose'
]);
/**
* Responder interface to dispatch responses to requests.
*
* @class Session.messages.Responder
*/
Messages.Responder = _interface('Responder', [
/**
* Dispatch a response to a request.
*
* @param {Object} response - the response to send
* @function Session.messages.Responder#respond
*/
'respond',
/**
* Reject a request.
*
* @param {String} message - context message to be contained in the rejection.
* @function Session.messages.Responder#reject
*/
'reject'
]);
/**
* A registered request handler.
*
* @class Session.messages.Registration
*/
Messages.Registration = _interface('Registration', [
/**
* Request that the request handler is unregistered from the server.
*
* @returns {Result<undefined>} that completes when a response is received from the server
* @function Session.messages.Registration#close
*/
'close'
]);
/**
* @typedef {Object} Session.messages.RequestContext
* @property {SessionId} sessionId - SessionId of the session that sent the request
* @property {String} path - the message path of the request
* @property {Object} properties - the session properties
*/
/**
* The priority of the message. Higher priorities are delivered faster.
*
* @readonly
* @enum
* @memberOf Session.messages
* @alias Priority
*
* @deprecated since 6.2
* <p>
* This is only used within one-way messaging, which is deprecated
* from this release. This enum will be removed in a future
* release.
*/
Messages.Priority = {
/** Indicates that messages should be delivered with normal priority. */
NORMAL : 0,
/** Indicates that messages should be delivered with high priority. */
HIGH : 1,
/** Indicates that messages should be delivered with low priority. */
LOW : 2
};
/**
* @example
* // Read message content as a JSON DataType value
* var jsonObj = diffusion.datatypes.json().readValue(message.content).get();
*
* @typedef {Object} Session.messages.Message
* @property {String} path - The path that this message was sent on
* @property {Buffer} content - The message's value as a binary buffer
*
* @deprecated since 6.2
* <p>
* One-way messaging is deprecated in favor of request-response
* messaging. See {@link Session.messages.#sendRequest sendRequest}
* and {@link Session.messages.#sendRequestToFilter
* sendRequestToFilter}. This interface will be removed in a future
* release.
*/
Messages.Message = {};
/**
* @typedef {Object} Session.messages.SessionMessage
* @property {String} path - The path that this message was sent on
* @property {Buffer} content - The message's value as a binary buffer
* @property {String} session - The session that sent this message
*
* @deprecated since 6.2
* <p>
* One-way messaging is deprecated in favor of request-response
* messaging. See {@link Session.messages.#sendRequest sendRequest}
* and {@link Session.messages.#sendRequestToFilter
* sendRequestToFilter}. This interface will be removed in a future
* release.
*/
Messages.SessionMessage = {};
/**
* @typedef {Object} Session.messages.SendOptions
* @property {Session.messages.Priority} [priority=Session.messages.Priority.NORMAL] - The message priority
* @property {String[]} [headers=[]] - The message headers as an array of strings
*
* @deprecated since 6.2
* <p>
* This is only used within one-way messaging, which is deprecated
* from this release. This interface will be removed in a future
* release.
*/
/**
* @typedef {Object} Session.messages.MessageSendResult
* @property {String} path - topic path
* @property {String} recipient - session filter or SessionID of the recipient
* @property {Number} [sent] - the number of sessions the message has been sent to using a filter string
* @property {Array<ErrorReport>} [errors] - errors from sending to sessions using a filter string
*
* @deprecated since 6.2
* <p>
* One-way messaging is deprecated in favor of request-response
* messaging. See {@link Session.messages.#sendRequest sendRequest}
* and {@link Session.messages.#sendRequestToFilter
* sendRequestToFilter}. This interface will be removed in a future
* release.
*/
module.exports = Messages;