UNPKG

diffusion

Version:

Diffusion JavaScript client

704 lines (671 loc) 30 kB
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;