| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 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 {remoting.SignalStrategy} primary | |
| 16 * @param {remoting.SignalStrategy} secondary | |
| 17 * | |
| 18 * @implements {remoting.SignalStrategy} | |
| 19 * @constructor | |
| 20 */ | |
| 21 remoting.FallbackSignalStrategy = function(primary, | |
| 22 secondary) { | |
| 23 /** @private {remoting.SignalStrategy} */ | |
| 24 this.primary_ = primary; | |
| 25 this.primary_.setStateChangedCallback(this.onPrimaryStateChanged_.bind(this)); | |
| 26 | |
| 27 /** @private {remoting.SignalStrategy} */ | |
| 28 this.secondary_ = secondary; | |
| 29 this.secondary_.setStateChangedCallback( | |
| 30 this.onSecondaryStateChanged_.bind(this)); | |
| 31 | |
| 32 /** @private {?function(remoting.SignalStrategy.State)} */ | |
| 33 this.onStateChangedCallback_ = null; | |
| 34 | |
| 35 /** @private {?function(Element):void} */ | |
| 36 this.onIncomingStanzaCallback_ = null; | |
| 37 | |
| 38 /** | |
| 39 * @private {number} | |
| 40 * @const | |
| 41 */ | |
| 42 this.PRIMARY_CONNECT_TIMEOUT_MS_ = 10 * 1000; | |
| 43 | |
| 44 /** | |
| 45 * @enum {string} | |
| 46 * @private | |
| 47 */ | |
| 48 this.State = { | |
| 49 NOT_CONNECTED: 'not-connected', | |
| 50 PRIMARY_PENDING: 'primary-pending', | |
| 51 PRIMARY_SUCCEEDED: 'primary-succeeded', | |
| 52 SECONDARY_PENDING: 'secondary-pending', | |
| 53 SECONDARY_SUCCEEDED: 'secondary-succeeded', | |
| 54 SECONDARY_FAILED: 'secondary-failed', | |
| 55 CLOSED: 'closed' | |
| 56 }; | |
| 57 | |
| 58 /** @private {string} */ | |
| 59 this.state_ = this.State.NOT_CONNECTED; | |
| 60 | |
| 61 /** @private {?remoting.SignalStrategy.State} */ | |
| 62 this.externalState_ = null; | |
| 63 | |
| 64 /** @private {string} */ | |
| 65 this.server_ = ''; | |
| 66 | |
| 67 /** @private {string} */ | |
| 68 this.username_ = ''; | |
| 69 | |
| 70 /** @private {string} */ | |
| 71 this.authToken_ = ''; | |
| 72 | |
| 73 /** @private {number} */ | |
| 74 this.primaryConnectTimerId_ = 0; | |
| 75 | |
| 76 /** @private {remoting.LogToServer} */ | |
| 77 this.logToServer_ = null; | |
| 78 | |
| 79 /** | |
| 80 * @type {Array<{strategyType: remoting.SignalStrategy.Type, | |
| 81 progress: remoting.FallbackSignalStrategy.Progress}>} | |
| 82 */ | |
| 83 this.connectionSetupResults_ = []; | |
| 84 | |
| 85 }; | |
| 86 | |
| 87 /** | |
| 88 * @enum {string} | |
| 89 */ | |
| 90 remoting.FallbackSignalStrategy.Progress = { | |
| 91 SUCCEEDED: 'succeeded', | |
| 92 FAILED: 'failed', | |
| 93 TIMED_OUT: 'timed-out', | |
| 94 SUCCEEDED_LATE: 'succeeded-late', | |
| 95 FAILED_LATE: 'failed-late', | |
| 96 }; | |
| 97 | |
| 98 remoting.FallbackSignalStrategy.prototype.dispose = function() { | |
| 99 this.primary_.dispose(); | |
| 100 this.secondary_.dispose(); | |
| 101 }; | |
| 102 | |
| 103 /** | |
| 104 * @param {function(remoting.SignalStrategy.State):void} onStateChangedCallback | |
| 105 * Callback to call on state change. | |
| 106 */ | |
| 107 remoting.FallbackSignalStrategy.prototype.setStateChangedCallback = function( | |
| 108 onStateChangedCallback) { | |
| 109 this.onStateChangedCallback_ = onStateChangedCallback; | |
| 110 }; | |
| 111 | |
| 112 /** | |
| 113 * @param {?function(Element):void} onIncomingStanzaCallback Callback to call on | |
| 114 * incoming messages. | |
| 115 */ | |
| 116 remoting.FallbackSignalStrategy.prototype.setIncomingStanzaCallback = | |
| 117 function(onIncomingStanzaCallback) { | |
| 118 this.onIncomingStanzaCallback_ = onIncomingStanzaCallback; | |
| 119 if (this.state_ == this.State.PRIMARY_PENDING || | |
| 120 this.state_ == this.State.PRIMARY_SUCCEEDED) { | |
| 121 this.primary_.setIncomingStanzaCallback(onIncomingStanzaCallback); | |
| 122 } else if (this.state_ == this.State.SECONDARY_PENDING || | |
| 123 this.state_ == this.State.SECONDARY_SUCCEEDED) { | |
| 124 this.secondary_.setIncomingStanzaCallback(onIncomingStanzaCallback); | |
| 125 } | |
| 126 }; | |
| 127 | |
| 128 /** | |
| 129 * @param {string} server | |
| 130 * @param {string} username | |
| 131 * @param {string} authToken | |
| 132 */ | |
| 133 remoting.FallbackSignalStrategy.prototype.connect = | |
| 134 function(server, username, authToken) { | |
| 135 base.debug.assert(this.state_ == this.State.NOT_CONNECTED); | |
| 136 base.debug.assert(this.onStateChangedCallback_ != null); | |
| 137 this.server_ = server; | |
| 138 this.username_ = username; | |
| 139 this.authToken_ = authToken; | |
| 140 this.state_ = this.State.PRIMARY_PENDING; | |
| 141 this.primary_.setIncomingStanzaCallback(this.onIncomingStanzaCallback_); | |
| 142 this.primary_.connect(server, username, authToken); | |
| 143 this.primaryConnectTimerId_ = | |
| 144 window.setTimeout(this.onPrimaryTimeout_.bind(this), | |
| 145 this.PRIMARY_CONNECT_TIMEOUT_MS_); | |
| 146 }; | |
| 147 | |
| 148 /** | |
| 149 * Sends a message. Can be called only in CONNECTED state. | |
| 150 * @param {string} message | |
| 151 */ | |
| 152 remoting.FallbackSignalStrategy.prototype.sendMessage = function(message) { | |
| 153 this.getConnectedSignalStrategy_().sendMessage(message); | |
| 154 }; | |
| 155 | |
| 156 /** | |
| 157 * Send any messages accumulated during connection set-up. | |
| 158 * | |
| 159 * @param {remoting.LogToServer} logToServer The LogToServer instance for the | |
| 160 * connection. | |
| 161 */ | |
| 162 remoting.FallbackSignalStrategy.prototype.sendConnectionSetupResults = | |
| 163 function(logToServer) { | |
| 164 this.logToServer_ = logToServer; | |
| 165 this.sendConnectionSetupResultsInternal_(); | |
| 166 } | |
| 167 | |
| 168 remoting.FallbackSignalStrategy.prototype.sendConnectionSetupResultsInternal_ = | |
| 169 function() { | |
| 170 for (var i = 0; i < this.connectionSetupResults_.length; ++i) { | |
| 171 var result = this.connectionSetupResults_[i]; | |
| 172 this.logToServer_.logSignalStrategyProgress(result.strategyType, | |
| 173 result.progress); | |
| 174 } | |
| 175 this.connectionSetupResults_ = []; | |
| 176 }; | |
| 177 | |
| 178 /** @return {remoting.SignalStrategy.State} Current state */ | |
| 179 remoting.FallbackSignalStrategy.prototype.getState = function() { | |
| 180 return (this.externalState_ === null) | |
| 181 ? remoting.SignalStrategy.State.NOT_CONNECTED | |
| 182 : this.externalState_; | |
| 183 }; | |
| 184 | |
| 185 /** @return {!remoting.Error} Error when in FAILED state. */ | |
| 186 remoting.FallbackSignalStrategy.prototype.getError = function() { | |
| 187 base.debug.assert(this.state_ == this.State.SECONDARY_FAILED); | |
| 188 base.debug.assert( | |
| 189 this.secondary_.getState() == remoting.SignalStrategy.State.FAILED); | |
| 190 return this.secondary_.getError(); | |
| 191 }; | |
| 192 | |
| 193 /** @return {string} Current JID when in CONNECTED state. */ | |
| 194 remoting.FallbackSignalStrategy.prototype.getJid = function() { | |
| 195 return this.getConnectedSignalStrategy_().getJid(); | |
| 196 }; | |
| 197 | |
| 198 /** @return {remoting.SignalStrategy.Type} The signal strategy type. */ | |
| 199 remoting.FallbackSignalStrategy.prototype.getType = function() { | |
| 200 return this.getConnectedSignalStrategy_().getType(); | |
| 201 }; | |
| 202 | |
| 203 /** | |
| 204 * @return {remoting.SignalStrategy} The active signal strategy, if the | |
| 205 * connection has succeeded. | |
| 206 * @private | |
| 207 */ | |
| 208 remoting.FallbackSignalStrategy.prototype.getConnectedSignalStrategy_ = | |
| 209 function() { | |
| 210 if (this.state_ == this.State.PRIMARY_SUCCEEDED) { | |
| 211 base.debug.assert( | |
| 212 this.primary_.getState() == remoting.SignalStrategy.State.CONNECTED); | |
| 213 return this.primary_; | |
| 214 } else if (this.state_ == this.State.SECONDARY_SUCCEEDED) { | |
| 215 base.debug.assert( | |
| 216 this.secondary_.getState() == remoting.SignalStrategy.State.CONNECTED); | |
| 217 return this.secondary_; | |
| 218 } else { | |
| 219 base.debug.assert( | |
| 220 false, | |
| 221 'getConnectedSignalStrategy called in unconnected state'); | |
| 222 return null; | |
| 223 } | |
| 224 }; | |
| 225 | |
| 226 /** | |
| 227 * @param {remoting.SignalStrategy.State} state | |
| 228 * @private | |
| 229 */ | |
| 230 remoting.FallbackSignalStrategy.prototype.onPrimaryStateChanged_ = | |
| 231 function(state) { | |
| 232 switch (state) { | |
| 233 case remoting.SignalStrategy.State.CONNECTED: | |
| 234 if (this.state_ == this.State.PRIMARY_PENDING) { | |
| 235 window.clearTimeout(this.primaryConnectTimerId_); | |
| 236 this.updateProgress_( | |
| 237 this.primary_, | |
| 238 remoting.FallbackSignalStrategy.Progress.SUCCEEDED); | |
| 239 this.state_ = this.State.PRIMARY_SUCCEEDED; | |
| 240 } else { | |
| 241 this.updateProgress_( | |
| 242 this.primary_, | |
| 243 remoting.FallbackSignalStrategy.Progress.SUCCEEDED_LATE); | |
| 244 } | |
| 245 break; | |
| 246 | |
| 247 case remoting.SignalStrategy.State.FAILED: | |
| 248 if (this.state_ == this.State.PRIMARY_PENDING) { | |
| 249 window.clearTimeout(this.primaryConnectTimerId_); | |
| 250 this.updateProgress_( | |
| 251 this.primary_, | |
| 252 remoting.FallbackSignalStrategy.Progress.FAILED); | |
| 253 this.connectSecondary_(); | |
| 254 } else { | |
| 255 this.updateProgress_( | |
| 256 this.primary_, | |
| 257 remoting.FallbackSignalStrategy.Progress.FAILED_LATE); | |
| 258 } | |
| 259 return; // Don't notify the external callback | |
| 260 | |
| 261 case remoting.SignalStrategy.State.CLOSED: | |
| 262 this.state_ = this.State.CLOSED; | |
| 263 break; | |
| 264 } | |
| 265 | |
| 266 this.notifyExternalCallback_(state); | |
| 267 }; | |
| 268 | |
| 269 /** | |
| 270 * @param {remoting.SignalStrategy.State} state | |
| 271 * @private | |
| 272 */ | |
| 273 remoting.FallbackSignalStrategy.prototype.onSecondaryStateChanged_ = | |
| 274 function(state) { | |
| 275 switch (state) { | |
| 276 case remoting.SignalStrategy.State.CONNECTED: | |
| 277 this.updateProgress_( | |
| 278 this.secondary_, | |
| 279 remoting.FallbackSignalStrategy.Progress.SUCCEEDED); | |
| 280 this.state_ = this.State.SECONDARY_SUCCEEDED; | |
| 281 break; | |
| 282 | |
| 283 case remoting.SignalStrategy.State.FAILED: | |
| 284 this.updateProgress_( | |
| 285 this.secondary_, | |
| 286 remoting.FallbackSignalStrategy.Progress.FAILED); | |
| 287 this.state_ = this.State.SECONDARY_FAILED; | |
| 288 break; | |
| 289 | |
| 290 case remoting.SignalStrategy.State.CLOSED: | |
| 291 this.state_ = this.State.CLOSED; | |
| 292 break; | |
| 293 } | |
| 294 | |
| 295 this.notifyExternalCallback_(state); | |
| 296 }; | |
| 297 | |
| 298 /** | |
| 299 * Notify the external callback of a change in state if it's consistent with | |
| 300 * the allowed state transitions (ie, if it represents a later stage in the | |
| 301 * connection process). Suppress state transitions that would violate this, | |
| 302 * for example a CONNECTING -> NOT_CONNECTED transition when we switch from | |
| 303 * the primary to the secondary signal strategy. | |
| 304 * | |
| 305 * @param {remoting.SignalStrategy.State} state | |
| 306 * @private | |
| 307 */ | |
| 308 remoting.FallbackSignalStrategy.prototype.notifyExternalCallback_ = | |
| 309 function(state) { | |
| 310 if (this.externalState_ === null || state > this.externalState_) { | |
| 311 this.externalState_ = state; | |
| 312 this.onStateChangedCallback_(state); | |
| 313 } | |
| 314 }; | |
| 315 | |
| 316 /** | |
| 317 * @private | |
| 318 */ | |
| 319 remoting.FallbackSignalStrategy.prototype.connectSecondary_ = function() { | |
| 320 base.debug.assert(this.state_ == this.State.PRIMARY_PENDING); | |
| 321 base.debug.assert(this.server_ != ''); | |
| 322 base.debug.assert(this.username_ != ''); | |
| 323 base.debug.assert(this.authToken_ != ''); | |
| 324 | |
| 325 this.state_ = this.State.SECONDARY_PENDING; | |
| 326 this.primary_.setIncomingStanzaCallback(null); | |
| 327 this.secondary_.setIncomingStanzaCallback(this.onIncomingStanzaCallback_); | |
| 328 this.secondary_.connect(this.server_, this.username_, this.authToken_); | |
| 329 }; | |
| 330 | |
| 331 /** | |
| 332 * @private | |
| 333 */ | |
| 334 remoting.FallbackSignalStrategy.prototype.onPrimaryTimeout_ = function() { | |
| 335 this.updateProgress_( | |
| 336 this.primary_, | |
| 337 remoting.FallbackSignalStrategy.Progress.TIMED_OUT); | |
| 338 this.connectSecondary_(); | |
| 339 }; | |
| 340 | |
| 341 /** | |
| 342 * @param {remoting.SignalStrategy} strategy | |
| 343 * @param {remoting.FallbackSignalStrategy.Progress} progress | |
| 344 * @private | |
| 345 */ | |
| 346 remoting.FallbackSignalStrategy.prototype.updateProgress_ = function( | |
| 347 strategy, progress) { | |
| 348 console.log('FallbackSignalStrategy progress: ' + strategy.getType() + ' ' + | |
| 349 progress); | |
| 350 this.connectionSetupResults_.push({ | |
| 351 'strategyType': strategy.getType(), | |
| 352 'progress': progress | |
| 353 }); | |
| 354 if (this.logToServer_) { | |
| 355 this.sendConnectionSetupResultsInternal_(); | |
| 356 } | |
| 357 }; | |
| OLD | NEW |