Path: blob/trunk/third_party/closure/goog/messaging/respondingchannel.js
2868 views
// Copyright 2012 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview Definition of goog.messaging.RespondingChannel, which wraps a16* MessageChannel and allows the user to get the response from the services.17*18*/192021goog.provide('goog.messaging.RespondingChannel');2223goog.require('goog.Disposable');24goog.require('goog.log');25goog.require('goog.messaging.MultiChannel');26272829/**30* Creates a new RespondingChannel wrapping a single MessageChannel.31* @param {goog.messaging.MessageChannel} messageChannel The messageChannel to32* to wrap and allow for responses. This channel must not have any existing33* services registered. All service registration must be done through the34* {@link RespondingChannel#registerService} api instead. The other end of35* channel must also be a RespondingChannel.36* @constructor37* @extends {goog.Disposable}38*/39goog.messaging.RespondingChannel = function(messageChannel) {40goog.messaging.RespondingChannel.base(this, 'constructor');4142/**43* The message channel wrapped in a MultiChannel so we can send private and44* public messages on it.45* @type {goog.messaging.MultiChannel}46* @private47*/48this.messageChannel_ = new goog.messaging.MultiChannel(messageChannel);4950/**51* Map of invocation signatures to function callbacks. These are used to keep52* track of the asyncronous service invocations so the result of a service53* call can be passed back to a callback in the calling frame.54* @type {Object<number, function(Object)>}55* @private56*/57this.sigCallbackMap_ = {};5859/**60* The virtual channel to send private messages on.61* @type {goog.messaging.MultiChannel.VirtualChannel}62* @private63*/64this.privateChannel_ = this.messageChannel_.createVirtualChannel(65goog.messaging.RespondingChannel.PRIVATE_CHANNEL_);6667/**68* The virtual channel to send public messages on.69* @type {goog.messaging.MultiChannel.VirtualChannel}70* @private71*/72this.publicChannel_ = this.messageChannel_.createVirtualChannel(73goog.messaging.RespondingChannel.PUBLIC_CHANNEL_);7475this.privateChannel_.registerService(76goog.messaging.RespondingChannel.CALLBACK_SERVICE_,77goog.bind(this.callbackServiceHandler_, this), true);78};79goog.inherits(goog.messaging.RespondingChannel, goog.Disposable);808182/**83* The name of the method invocation callback service (used internally).84* @type {string}85* @const86* @private87*/88goog.messaging.RespondingChannel.CALLBACK_SERVICE_ = 'mics';899091/**92* The name of the channel to send private control messages on.93* @type {string}94* @const95* @private96*/97goog.messaging.RespondingChannel.PRIVATE_CHANNEL_ = 'private';9899100/**101* The name of the channel to send public messages on.102* @type {string}103* @const104* @private105*/106goog.messaging.RespondingChannel.PUBLIC_CHANNEL_ = 'public';107108109/**110* The next signature index to save the callback against.111* @type {number}112* @private113*/114goog.messaging.RespondingChannel.prototype.nextSignatureIndex_ = 0;115116117/**118* Logger object for goog.messaging.RespondingChannel.119* @type {goog.log.Logger}120* @private121*/122goog.messaging.RespondingChannel.prototype.logger_ =123goog.log.getLogger('goog.messaging.RespondingChannel');124125126/**127* Gets a random number to use for method invocation results.128* @return {number} A unique random signature.129* @private130*/131goog.messaging.RespondingChannel.prototype.getNextSignature_ = function() {132return this.nextSignatureIndex_++;133};134135136/** @override */137goog.messaging.RespondingChannel.prototype.disposeInternal = function() {138goog.dispose(this.messageChannel_);139delete this.messageChannel_;140// Note: this.publicChannel_ and this.privateChannel_ get disposed by141// this.messageChannel_142delete this.publicChannel_;143delete this.privateChannel_;144};145146147/**148* Sends a message over the channel.149* @param {string} serviceName The name of the service this message should be150* delivered to.151* @param {string|!Object} payload The value of the message. If this is an152* Object, it is serialized to a string before sending if necessary.153* @param {function(?Object)} callback The callback invoked with154* the result of the service call.155*/156goog.messaging.RespondingChannel.prototype.send = function(157serviceName, payload, callback) {158159var signature = this.getNextSignature_();160this.sigCallbackMap_[signature] = callback;161162var message = {};163message['signature'] = signature;164message['data'] = payload;165166this.publicChannel_.send(serviceName, message);167};168169170/**171* Receives the results of the peer's service results.172* @param {!Object|string} message The results from the remote service173* invocation.174* @private175*/176goog.messaging.RespondingChannel.prototype.callbackServiceHandler_ = function(177message) {178179var signature = message['signature'];180var result = message['data'];181182if (signature in this.sigCallbackMap_) {183var callback =184/** @type {function(Object)} */ (this.sigCallbackMap_[signature]);185callback(result);186delete this.sigCallbackMap_[signature];187} else {188goog.log.warning(this.logger_, 'Received signature is invalid');189}190};191192193/**194* Registers a service to be called when a message is received.195* @param {string} serviceName The name of the service.196* @param {function(!Object)} callback The callback to process the197* incoming messages. Passed the payload.198*/199goog.messaging.RespondingChannel.prototype.registerService = function(200serviceName, callback) {201this.publicChannel_.registerService(202serviceName, goog.bind(this.callbackProxy_, this, callback), true);203};204205206/**207* A intermediary proxy for service callbacks to be invoked and return their208* their results to the remote caller's callback.209* @param {function((string|!Object))} callback The callback to process the210* incoming messages. Passed the payload.211* @param {!Object|string} message The message containing the signature and212* the data to invoke the service callback with.213* @private214*/215goog.messaging.RespondingChannel.prototype.callbackProxy_ = function(216callback, message) {217218var resultMessage = {};219resultMessage['data'] = callback(message['data']);220resultMessage['signature'] = message['signature'];221// The callback invoked above may have disposed the channel so check if it222// exists.223if (this.privateChannel_) {224this.privateChannel_.send(225goog.messaging.RespondingChannel.CALLBACK_SERVICE_, resultMessage);226}227};228229230