Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: remoting/webapp/crd/js/fallback_signal_strategy.js

Issue 815943004: Implement FallbackSignalStrategy. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Reviewer feedback. Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « remoting/remoting_webapp_files.gypi ('k') | remoting/webapp/crd/js/signal_strategy.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
Sergey Ulanov 2015/01/14 19:42:43 2015
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 'use strict';
6
7 /** @suppress {duplicate} */
8 var remoting = remoting || {};
9
10 /**
11 * A signal strategy encapsulating a primary and a back-up strategy. If the
12 * primary fails or times out, then the secondary is used. Information about
13 * which strategy was used, and why, is returned via |onProgressCallback|.
14 *
15 * @param {function(
16 * function(remoting.SignalStrategy.State)
17 * ):remoting.SignalStrategy} primaryFactory
18 * @param {function(
19 * function(remoting.SignalStrategy.State)
20 * ):remoting.SignalStrategy} secondaryFactory
21 * @param {function(remoting.SignalStrategy.State):void} onStateChangedCallback
22 * @param {function(remoting.FallbackSignalStrategy.Progress)}
23 * onProgressCallback
24 *
25 * @implements {remoting.SignalStrategy}
26 * @constructor
27 */
28 remoting.FallbackSignalStrategy = function(
29 primaryFactory, secondaryFactory,
30 onStateChangedCallback, onProgressCallback) {
31 /**
32 * @type {remoting.SignalStrategy}
33 * @private
34 */
35 this.primary_ = primaryFactory(this.onPrimaryStateChanged_.bind(this));
36
37 /**
38 * @type {remoting.SignalStrategy}
39 * @private
40 */
41 this.secondary_ = secondaryFactory(this.onSecondaryStateChanged_.bind(this));
42
43 /**
44 * @type {function(remoting.SignalStrategy.State)}
45 * @private
46 */
47 this.onStateChangedCallback_ = onStateChangedCallback;
48
49 /**
50 * @type {function(remoting.FallbackSignalStrategy.Progress)}
51 * @private
52 */
53 this.onProgressCallback_ = onProgressCallback;
54
55 /**
56 * @type {?function(Element):void}
57 * @private
58 */
59 this.onIncomingStanzaCallback_ = null;
60
61 /**
62 * @type {number}
63 * @private
64 * @const
65 */
66 this.PRIMARY_CONNECT_TIMEOUT_MS_ = 10 * 1000;
67
68 /**
69 * @enum {string}
70 * @private
71 */
72 this.State = {
73 NOT_CONNECTED: 'not-connected',
74 PRIMARY_PENDING: 'primary-pending',
75 PRIMARY_SUCCEEDED: 'primary-succeeded',
76 SECONDARY_PENDING: 'secondary-pending',
77 SECONDARY_SUCCEEDED: 'secondary-succeeded',
78 SECONDARY_FAILED: 'secondary-failed',
79 CLOSED: 'closed'
80 };
81
82 /**
83 * @type {string}
84 * @private
85 */
86 this.state_ = this.State.NOT_CONNECTED;
87
88 /**
89 * @type {?remoting.SignalStrategy.State}
90 * @private
91 */
92 this.externalState_ = null;
93
94 /**
95 * @type {string}
96 * @private
97 */
98 this.server_ = '';
99
100 /**
101 * @type {string}
102 * @private
103 */
104 this.username_ = '';
105
106 /**
107 * @type {string}
108 * @private
109 */
110 this.authToken_ = '';
111
112 /**
113 * @type {number}
114 * @private
115 */
116 this.primaryConnectTimerId_ = 0;
117 };
118
119 /**
120 * @enum {string}
121 */
122 remoting.FallbackSignalStrategy.Progress = {
123 PRIMARY_SUCCEEDED: 'primary-succeeded',
124 PRIMARY_FAILED: 'primary-failed',
125 PRIMARY_TIMED_OUT: 'primary-timed-out',
126 PRIMARY_SUCCEEDED_LATE: 'primary-succeeded-late',
127 PRIMARY_FAILED_LATE: 'primary-failed-late',
128 SECONDARY_SUCCEEDED: 'secondary-succeeded',
129 SECONDARY_FAILED: 'secondary-failed'
130 };
131
132 remoting.FallbackSignalStrategy.prototype.dispose = function() {
133 this.primary_.dispose();
134 this.secondary_.dispose();
135 };
136
137 /**
138 * @param {?function(Element):void} onIncomingStanzaCallback Callback to call on
139 * incoming messages.
140 */
141 remoting.FallbackSignalStrategy.prototype.setIncomingStanzaCallback =
142 function(onIncomingStanzaCallback) {
143 this.onIncomingStanzaCallback_ = onIncomingStanzaCallback;
144 if (this.state_ == this.State.PRIMARY_PENDING ||
145 this.state_ == this.State.PRIMARY_SUCCEEDED) {
146 this.primary_.setIncomingStanzaCallback(onIncomingStanzaCallback);
147 } else if (this.state_ == this.State.SECONDARY_PENDING ||
148 this.state_ == this.State.SECONDARY_SUCCEEDED) {
149 this.secondary_.setIncomingStanzaCallback(onIncomingStanzaCallback);
150 }
151 };
152
153 /**
154 * @param {string} server
155 * @param {string} username
156 * @param {string} authToken
157 */
158 remoting.FallbackSignalStrategy.prototype.connect =
159 function(server, username, authToken) {
160 base.debug.assert(this.state_ == this.State.NOT_CONNECTED);
161 this.server_ = server;
162 this.username_ = username;
163 this.authToken_ = authToken;
164 this.state_ = this.State.PRIMARY_PENDING;
165 this.primary_.setIncomingStanzaCallback(this.onIncomingStanzaCallback_);
166 this.primary_.connect(server, username, authToken);
167 this.primaryConnectTimerId_ =
168 window.setTimeout(this.onPrimaryTimeout_.bind(this),
169 this.PRIMARY_CONNECT_TIMEOUT_MS_);
170 };
171
172 /**
173 * Sends a message. Can be called only in CONNECTED state.
174 * @param {string} message
175 */
176 remoting.FallbackSignalStrategy.prototype.sendMessage = function(message) {
177 this.getConnectedSignalStrategy_().sendMessage(message);
178 };
179
180 /** @return {remoting.SignalStrategy.State} Current state */
181 remoting.FallbackSignalStrategy.prototype.getState = function() {
182 return (this.externalState_ === null)
183 ? remoting.SignalStrategy.State.NOT_CONNECTED
184 : this.externalState_;
185 };
186
187 /** @return {remoting.Error} Error when in FAILED state. */
188 remoting.FallbackSignalStrategy.prototype.getError = function() {
189 base.debug.assert(this.state_ == this.State.SECONDARY_FAILED);
190 base.debug.assert(
191 this.secondary_.getState() == remoting.SignalStrategy.State.FAILED);
192 return this.secondary_.getError();
193 };
194
195 /** @return {string} Current JID when in CONNECTED state. */
196 remoting.FallbackSignalStrategy.prototype.getJid = function() {
197 return this.getConnectedSignalStrategy_().getJid();
198 };
199
200 /**
201 * @return {remoting.SignalStrategy} The active signal strategy, if the
202 * connection has succeeded.
203 * @private
204 */
205 remoting.FallbackSignalStrategy.prototype.getConnectedSignalStrategy_ =
206 function() {
207 if (this.state_ == this.State.PRIMARY_SUCCEEDED) {
208 base.debug.assert(
209 this.primary_.getState() == remoting.SignalStrategy.State.CONNECTED);
210 return this.primary_;
211 } else if (this.state_ == this.State.SECONDARY_SUCCEEDED) {
212 base.debug.assert(
213 this.secondary_.getState() == remoting.SignalStrategy.State.CONNECTED);
214 return this.secondary_;
215 } else {
216 base.debug.assert(
217 false,
218 'getConnectedSignalStrategy called in unconnected state');
219 return null;
220 }
221 };
222
223 /**
224 * @param {remoting.SignalStrategy.State} state
225 * @private
226 */
227 remoting.FallbackSignalStrategy.prototype.onPrimaryStateChanged_ =
228 function(state) {
229 switch (state) {
230 case remoting.SignalStrategy.State.CONNECTED:
231 if (this.state_ == this.State.PRIMARY_PENDING) {
232 window.clearTimeout(this.primaryConnectTimerId_);
233 this.onProgressCallback_(
234 remoting.FallbackSignalStrategy.Progress.PRIMARY_SUCCEEDED);
235 this.state_ = this.State.PRIMARY_SUCCEEDED;
236 } else {
237 this.onProgressCallback_(
238 remoting.FallbackSignalStrategy.Progress.PRIMARY_SUCCEEDED_LATE);
239 }
240 break;
241
242 case remoting.SignalStrategy.State.FAILED:
243 if (this.state_ == this.State.PRIMARY_PENDING) {
244 window.clearTimeout(this.primaryConnectTimerId_);
245 this.onProgressCallback_(
246 remoting.FallbackSignalStrategy.Progress.PRIMARY_FAILED);
247 this.connectSecondary_();
248 } else {
249 this.onProgressCallback_(
250 remoting.FallbackSignalStrategy.Progress.PRIMARY_FAILED_LATE);
251 }
252 return; // Don't notify the external callback
253
254 case remoting.SignalStrategy.State.CLOSED:
255 this.state_ = this.State.CLOSED;
256 break;
257 }
258
259 this.notifyExternalCallback_(state);
260 };
261
262 /**
263 * @param {remoting.SignalStrategy.State} state
264 * @private
265 */
266 remoting.FallbackSignalStrategy.prototype.onSecondaryStateChanged_ =
267 function(state) {
268 switch (state) {
269 case remoting.SignalStrategy.State.CONNECTED:
270 this.onProgressCallback_(
271 remoting.FallbackSignalStrategy.Progress.SECONDARY_SUCCEEDED);
272 this.state_ = this.State.SECONDARY_SUCCEEDED;
273 break;
274
275 case remoting.SignalStrategy.State.FAILED:
276 this.onProgressCallback_(
277 remoting.FallbackSignalStrategy.Progress.SECONDARY_FAILED);
278 this.state_ = this.State.SECONDARY_FAILED;
279 break;
280
281 case remoting.SignalStrategy.State.CLOSED:
282 this.state_ = this.State.CLOSED;
283 break;
284 }
285
286 this.notifyExternalCallback_(state);
287 };
288
289 /**
290 * Notify the external callback of a change in state if it's consistent with
291 * the allowed state transitions (ie, if it represents a later stage in the
292 * connection process). Suppress state transitions that would violate this,
293 * for example a CONNECTING -> NOT_CONNECTED transition when we switch from
294 * the primary to the secondary signal strategy.
295 *
296 * @param {remoting.SignalStrategy.State} state
297 * @private
298 */
299 remoting.FallbackSignalStrategy.prototype.notifyExternalCallback_ =
300 function(state) {
301 if (this.externalState_ === null || state > this.externalState_) {
302 this.externalState_ = state;
303 this.onStateChangedCallback_(state);
304 }
305 };
306
307 /**
308 * @private
309 */
310 remoting.FallbackSignalStrategy.prototype.connectSecondary_ = function() {
311 base.debug.assert(this.state_ == this.State.PRIMARY_PENDING);
312 base.debug.assert(this.server_ != '');
313 base.debug.assert(this.username_ != '');
314 base.debug.assert(this.authToken_ != '');
315
316 this.state_ = this.State.SECONDARY_PENDING;
317 this.primary_.setIncomingStanzaCallback(null);
318 this.secondary_.setIncomingStanzaCallback(this.onIncomingStanzaCallback_);
319 this.secondary_.connect(this.server_, this.username_, this.authToken_);
320 };
321
322 /**
323 * @private
324 */
325 remoting.FallbackSignalStrategy.prototype.onPrimaryTimeout_ = function() {
326 this.onProgressCallback_(
327 remoting.FallbackSignalStrategy.Progress.PRIMARY_TIMED_OUT);
328 this.connectSecondary_();
329 };
330
331 /**
332 * @return {remoting.SignalStrategy} The primary signal strategy.
333 * @private
334 */
335 remoting.FallbackSignalStrategy.prototype.getPrimaryStrategyForTesting_ =
336 function() {
337 return this.primary_;
338 };
339
340 /**
341 * @return {remoting.SignalStrategy} The primary signal strategy.
342 * @private
343 */
344 remoting.FallbackSignalStrategy.prototype.getSecondaryStrategyForTesting_ =
345 function() {
346 return this.secondary_;
347 };
OLDNEW
« no previous file with comments | « remoting/remoting_webapp_files.gypi ('k') | remoting/webapp/crd/js/signal_strategy.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698