Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/messaging/respondingchannel.js
2868 views
1
// Copyright 2012 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview Definition of goog.messaging.RespondingChannel, which wraps a
17
* MessageChannel and allows the user to get the response from the services.
18
*
19
*/
20
21
22
goog.provide('goog.messaging.RespondingChannel');
23
24
goog.require('goog.Disposable');
25
goog.require('goog.log');
26
goog.require('goog.messaging.MultiChannel');
27
28
29
30
/**
31
* Creates a new RespondingChannel wrapping a single MessageChannel.
32
* @param {goog.messaging.MessageChannel} messageChannel The messageChannel to
33
* to wrap and allow for responses. This channel must not have any existing
34
* services registered. All service registration must be done through the
35
* {@link RespondingChannel#registerService} api instead. The other end of
36
* channel must also be a RespondingChannel.
37
* @constructor
38
* @extends {goog.Disposable}
39
*/
40
goog.messaging.RespondingChannel = function(messageChannel) {
41
goog.messaging.RespondingChannel.base(this, 'constructor');
42
43
/**
44
* The message channel wrapped in a MultiChannel so we can send private and
45
* public messages on it.
46
* @type {goog.messaging.MultiChannel}
47
* @private
48
*/
49
this.messageChannel_ = new goog.messaging.MultiChannel(messageChannel);
50
51
/**
52
* Map of invocation signatures to function callbacks. These are used to keep
53
* track of the asyncronous service invocations so the result of a service
54
* call can be passed back to a callback in the calling frame.
55
* @type {Object<number, function(Object)>}
56
* @private
57
*/
58
this.sigCallbackMap_ = {};
59
60
/**
61
* The virtual channel to send private messages on.
62
* @type {goog.messaging.MultiChannel.VirtualChannel}
63
* @private
64
*/
65
this.privateChannel_ = this.messageChannel_.createVirtualChannel(
66
goog.messaging.RespondingChannel.PRIVATE_CHANNEL_);
67
68
/**
69
* The virtual channel to send public messages on.
70
* @type {goog.messaging.MultiChannel.VirtualChannel}
71
* @private
72
*/
73
this.publicChannel_ = this.messageChannel_.createVirtualChannel(
74
goog.messaging.RespondingChannel.PUBLIC_CHANNEL_);
75
76
this.privateChannel_.registerService(
77
goog.messaging.RespondingChannel.CALLBACK_SERVICE_,
78
goog.bind(this.callbackServiceHandler_, this), true);
79
};
80
goog.inherits(goog.messaging.RespondingChannel, goog.Disposable);
81
82
83
/**
84
* The name of the method invocation callback service (used internally).
85
* @type {string}
86
* @const
87
* @private
88
*/
89
goog.messaging.RespondingChannel.CALLBACK_SERVICE_ = 'mics';
90
91
92
/**
93
* The name of the channel to send private control messages on.
94
* @type {string}
95
* @const
96
* @private
97
*/
98
goog.messaging.RespondingChannel.PRIVATE_CHANNEL_ = 'private';
99
100
101
/**
102
* The name of the channel to send public messages on.
103
* @type {string}
104
* @const
105
* @private
106
*/
107
goog.messaging.RespondingChannel.PUBLIC_CHANNEL_ = 'public';
108
109
110
/**
111
* The next signature index to save the callback against.
112
* @type {number}
113
* @private
114
*/
115
goog.messaging.RespondingChannel.prototype.nextSignatureIndex_ = 0;
116
117
118
/**
119
* Logger object for goog.messaging.RespondingChannel.
120
* @type {goog.log.Logger}
121
* @private
122
*/
123
goog.messaging.RespondingChannel.prototype.logger_ =
124
goog.log.getLogger('goog.messaging.RespondingChannel');
125
126
127
/**
128
* Gets a random number to use for method invocation results.
129
* @return {number} A unique random signature.
130
* @private
131
*/
132
goog.messaging.RespondingChannel.prototype.getNextSignature_ = function() {
133
return this.nextSignatureIndex_++;
134
};
135
136
137
/** @override */
138
goog.messaging.RespondingChannel.prototype.disposeInternal = function() {
139
goog.dispose(this.messageChannel_);
140
delete this.messageChannel_;
141
// Note: this.publicChannel_ and this.privateChannel_ get disposed by
142
// this.messageChannel_
143
delete this.publicChannel_;
144
delete this.privateChannel_;
145
};
146
147
148
/**
149
* Sends a message over the channel.
150
* @param {string} serviceName The name of the service this message should be
151
* delivered to.
152
* @param {string|!Object} payload The value of the message. If this is an
153
* Object, it is serialized to a string before sending if necessary.
154
* @param {function(?Object)} callback The callback invoked with
155
* the result of the service call.
156
*/
157
goog.messaging.RespondingChannel.prototype.send = function(
158
serviceName, payload, callback) {
159
160
var signature = this.getNextSignature_();
161
this.sigCallbackMap_[signature] = callback;
162
163
var message = {};
164
message['signature'] = signature;
165
message['data'] = payload;
166
167
this.publicChannel_.send(serviceName, message);
168
};
169
170
171
/**
172
* Receives the results of the peer's service results.
173
* @param {!Object|string} message The results from the remote service
174
* invocation.
175
* @private
176
*/
177
goog.messaging.RespondingChannel.prototype.callbackServiceHandler_ = function(
178
message) {
179
180
var signature = message['signature'];
181
var result = message['data'];
182
183
if (signature in this.sigCallbackMap_) {
184
var callback =
185
/** @type {function(Object)} */ (this.sigCallbackMap_[signature]);
186
callback(result);
187
delete this.sigCallbackMap_[signature];
188
} else {
189
goog.log.warning(this.logger_, 'Received signature is invalid');
190
}
191
};
192
193
194
/**
195
* Registers a service to be called when a message is received.
196
* @param {string} serviceName The name of the service.
197
* @param {function(!Object)} callback The callback to process the
198
* incoming messages. Passed the payload.
199
*/
200
goog.messaging.RespondingChannel.prototype.registerService = function(
201
serviceName, callback) {
202
this.publicChannel_.registerService(
203
serviceName, goog.bind(this.callbackProxy_, this, callback), true);
204
};
205
206
207
/**
208
* A intermediary proxy for service callbacks to be invoked and return their
209
* their results to the remote caller's callback.
210
* @param {function((string|!Object))} callback The callback to process the
211
* incoming messages. Passed the payload.
212
* @param {!Object|string} message The message containing the signature and
213
* the data to invoke the service callback with.
214
* @private
215
*/
216
goog.messaging.RespondingChannel.prototype.callbackProxy_ = function(
217
callback, message) {
218
219
var resultMessage = {};
220
resultMessage['data'] = callback(message['data']);
221
resultMessage['signature'] = message['signature'];
222
// The callback invoked above may have disposed the channel so check if it
223
// exists.
224
if (this.privateChannel_) {
225
this.privateChannel_.send(
226
goog.messaging.RespondingChannel.CALLBACK_SERVICE_, resultMessage);
227
}
228
};
229
230