diff options
Diffstat (limited to 'src/js/fiveui/js/messenger.js')
-rw-r--r-- | src/js/fiveui/js/messenger.js | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/src/js/fiveui/js/messenger.js b/src/js/fiveui/js/messenger.js new file mode 100644 index 0000000..fc1962c --- /dev/null +++ b/src/js/fiveui/js/messenger.js @@ -0,0 +1,141 @@ +/* + * Module : messenger.js + * Copyright : (c) 2011-2012, Galois, Inc. + * + * Maintainer : + * Stability : Provisional + * Portability: Portable + * + * Licensed 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. + */ + +var fiveui = fiveui || {}; + +(function() { + +/** + * @constructor + * @param {{on: function(!string, function(*)), emit: function(!string, *)}} + * channel The object containing on and emit. + */ +fiveui.Messenger = function(channel) { + this.callbacks = {}; + this.handlers = {}; + + this.channel = channel; + this.channel.on(fiveui.Messenger.type, _.bind(this._handler, this)); +}; + +fiveui.Messenger.type = "fiveui_messaging_type"; + +_.extend(fiveui.Messenger.prototype, { + + /** + * @param {!string} type The message type to send. + * @param {?Object} data The payload (which can be null). + * @param {?function(?Object)} callback An optional callback to be + * invoked in response. + */ + send: function(type, data, callback){ + var id = null; + if (callback) { + id = this._newId(); + this.callbacks[id] = callback; + } + + var payload = new fiveui.Messenger.Payload(false, type, data, id); + this.channel.emit(fiveui.Messenger.type, payload); + }, + + /** + * Register a handler for the specified message type. + * + * @param {!string} type The message type. + * @param {!function(*)} callback The function to call when a message + * of the specified type is received. + */ + register: function(type, callback) { + if(null == this.handlers[type]) { + this.handlers[type] = []; + } + this.handlers[type].push(callback); + }, + + _handler: function(payload) { + if (payload.isCallback && payload.id != null) { + // this is a callback invocation, lookup the callback and invoke it: + this.callbacks[payload.id](payload.data); + + // remove the callback: + this._remove(payload.id); + } else { + // look up a handler and invoke it, passing in the response fn: + var hs = this.handlers[payload.type]; + if (hs && hs.length > 0) { + + // this is a new incomming message. + // create a response function: + var respond = function(respData) { + this.channel.emit(fiveui.Messenger.type, + new fiveui.Messenger.Payload(true, payload.type, respData, payload.id)); + }; + + // iterate over the handlers, invoking them with the response callback. + _.each(hs, function(h) { + h(payload.data, _.bind(respond, this)); + }, this); + } + } + }, + + /** + * Remove a callback from the map of callbacks. + * + * @param {!number} callbackId The id of the callback to remove. + */ + _remove: function(callbackId) { + delete this.callbacks[callbackId]; + }, + + /** + * @return {!number} The next unique id for a callback. + */ + _newId: function() { + var list = Object.keys(this.callbacks); + return fiveui.utils.getNewId(list); + } + +}); + +/** + * @constructor + * @param {!boolean} isCallback True if this is in response to a + * message, false if this is requesting a callback. + * @param {!string} type + * @param {?Object} data + * @param {!number} id Callback id to invoke, or in which this is a response. + */ +fiveui.Messenger.Payload = function(isCallback, type, data, id) { + this.isCallback = isCallback; + this.type = type; + this.id = id; + this.__defineGetter__('data', function() { + return JSON.parse(this.rawData); + }); + this.__defineSetter__('data', function(obj){ + this.rawData = JSON.stringify(obj); + }); + this.data = data; +}; + +})(); |