| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 /** | |
| 6 * This class provides a "bridge" for communicating between the javascript and | |
| 7 * the browser. | |
| 8 * | |
| 9 * @constructor | |
| 10 */ | |
| 11 function BrowserBridge() { | |
| 12 // List of observers for various bits of browser state. | |
| 13 this.connectionTestsObservers_ = []; | |
| 14 this.hstsObservers_ = []; | |
| 15 this.httpThrottlingObservers_ = []; | |
| 16 this.constantsObservers_ = []; | |
| 17 | |
| 18 this.pollableDataHelpers_ = {}; | |
| 19 this.pollableDataHelpers_.proxySettings = | |
| 20 new PollableDataHelper('onProxySettingsChanged', | |
| 21 this.sendGetProxySettings.bind(this)); | |
| 22 this.pollableDataHelpers_.badProxies = | |
| 23 new PollableDataHelper('onBadProxiesChanged', | |
| 24 this.sendGetBadProxies.bind(this)); | |
| 25 this.pollableDataHelpers_.httpCacheInfo = | |
| 26 new PollableDataHelper('onHttpCacheInfoChanged', | |
| 27 this.sendGetHttpCacheInfo.bind(this)); | |
| 28 this.pollableDataHelpers_.hostResolverInfo = | |
| 29 new PollableDataHelper('onHostResolverInfoChanged', | |
| 30 this.sendGetHostResolverInfo.bind(this)); | |
| 31 this.pollableDataHelpers_.socketPoolInfo = | |
| 32 new PollableDataHelper('onSocketPoolInfoChanged', | |
| 33 this.sendGetSocketPoolInfo.bind(this)); | |
| 34 this.pollableDataHelpers_.spdySessionInfo = | |
| 35 new PollableDataHelper('onSpdySessionInfoChanged', | |
| 36 this.sendGetSpdySessionInfo.bind(this)); | |
| 37 this.pollableDataHelpers_.spdyStatus = | |
| 38 new PollableDataHelper('onSpdyStatusChanged', | |
| 39 this.sendGetSpdyStatus.bind(this)); | |
| 40 this.pollableDataHelpers_.spdyAlternateProtocolMappings = | |
| 41 new PollableDataHelper('onSpdyAlternateProtocolMappingsChanged', | |
| 42 this.sendGetSpdyAlternateProtocolMappings.bind( | |
| 43 this)); | |
| 44 if (cr.isWindows) { | |
| 45 this.pollableDataHelpers_.serviceProviders = | |
| 46 new PollableDataHelper('onServiceProvidersChanged', | |
| 47 this.sendGetServiceProviders.bind(this)); | |
| 48 } | |
| 49 this.pollableDataHelpers_.prerenderInfo = | |
| 50 new PollableDataHelper('onPrerenderInfoChanged', | |
| 51 this.sendGetPrerenderInfo.bind(this)); | |
| 52 | |
| 53 // NetLog entries are all sent to the |SourceTracker|, which both tracks them | |
| 54 // and manages its own observer list. | |
| 55 this.sourceTracker = new SourceTracker(); | |
| 56 | |
| 57 // Setting this to true will cause messages from the browser to be ignored, | |
| 58 // and no messages will be sent to the browser, either. Intended for use when | |
| 59 // viewing log files. | |
| 60 this.disabled_ = false; | |
| 61 } | |
| 62 | |
| 63 /** | |
| 64 * Delay in milliseconds between updates of certain browser information. | |
| 65 */ | |
| 66 BrowserBridge.POLL_INTERVAL_MS = 5000; | |
| 67 | |
| 68 //------------------------------------------------------------------------------ | |
| 69 // Messages sent to the browser | |
| 70 //------------------------------------------------------------------------------ | |
| 71 | |
| 72 /** | |
| 73 * Wraps |chrome.send|. Doesn't send anything when disabled. | |
| 74 */ | |
| 75 BrowserBridge.prototype.send = function(value1, value2) { | |
| 76 if (!this.disabled_) { | |
| 77 if (arguments.length == 1) { | |
| 78 chrome.send(value1); | |
| 79 } else if (arguments.length == 2) { | |
| 80 chrome.send(value1, value2); | |
| 81 } else { | |
| 82 throw 'Unsupported number of arguments.'; | |
| 83 } | |
| 84 } | |
| 85 }; | |
| 86 | |
| 87 BrowserBridge.prototype.sendReady = function() { | |
| 88 this.send('notifyReady'); | |
| 89 | |
| 90 // Some of the data we are interested is not currently exposed as a stream, | |
| 91 // so we will poll the browser to find out when it changes and then notify | |
| 92 // the observers. | |
| 93 window.setInterval(this.checkForUpdatedInfo.bind(this, false), | |
| 94 BrowserBridge.POLL_INTERVAL_MS); | |
| 95 }; | |
| 96 | |
| 97 BrowserBridge.prototype.sendGetProxySettings = function() { | |
| 98 // The browser will call receivedProxySettings on completion. | |
| 99 this.send('getProxySettings'); | |
| 100 }; | |
| 101 | |
| 102 BrowserBridge.prototype.sendReloadProxySettings = function() { | |
| 103 this.send('reloadProxySettings'); | |
| 104 }; | |
| 105 | |
| 106 BrowserBridge.prototype.sendGetBadProxies = function() { | |
| 107 // The browser will call receivedBadProxies on completion. | |
| 108 this.send('getBadProxies'); | |
| 109 }; | |
| 110 | |
| 111 BrowserBridge.prototype.sendGetHostResolverInfo = function() { | |
| 112 // The browser will call receivedHostResolverInfo on completion. | |
| 113 this.send('getHostResolverInfo'); | |
| 114 }; | |
| 115 | |
| 116 BrowserBridge.prototype.sendClearBadProxies = function() { | |
| 117 this.send('clearBadProxies'); | |
| 118 }; | |
| 119 | |
| 120 BrowserBridge.prototype.sendClearHostResolverCache = function() { | |
| 121 this.send('clearHostResolverCache'); | |
| 122 }; | |
| 123 | |
| 124 BrowserBridge.prototype.sendStartConnectionTests = function(url) { | |
| 125 this.send('startConnectionTests', [url]); | |
| 126 }; | |
| 127 | |
| 128 BrowserBridge.prototype.sendHSTSQuery = function(domain) { | |
| 129 this.send('hstsQuery', [domain]); | |
| 130 }; | |
| 131 | |
| 132 BrowserBridge.prototype.sendHSTSAdd = function(domain, | |
| 133 include_subdomains, | |
| 134 pins) { | |
| 135 this.send('hstsAdd', [domain, include_subdomains, pins]); | |
| 136 }; | |
| 137 | |
| 138 BrowserBridge.prototype.sendHSTSDelete = function(domain) { | |
| 139 this.send('hstsDelete', [domain]); | |
| 140 }; | |
| 141 | |
| 142 BrowserBridge.prototype.sendGetHttpCacheInfo = function() { | |
| 143 this.send('getHttpCacheInfo'); | |
| 144 }; | |
| 145 | |
| 146 BrowserBridge.prototype.sendGetSocketPoolInfo = function() { | |
| 147 this.send('getSocketPoolInfo'); | |
| 148 }; | |
| 149 | |
| 150 BrowserBridge.prototype.sendCloseIdleSockets = function() { | |
| 151 this.send('closeIdleSockets'); | |
| 152 }; | |
| 153 | |
| 154 BrowserBridge.prototype.sendFlushSocketPools = function() { | |
| 155 this.send('flushSocketPools'); | |
| 156 }; | |
| 157 | |
| 158 BrowserBridge.prototype.sendGetSpdySessionInfo = function() { | |
| 159 this.send('getSpdySessionInfo'); | |
| 160 }; | |
| 161 | |
| 162 BrowserBridge.prototype.sendGetSpdyStatus = function() { | |
| 163 this.send('getSpdyStatus'); | |
| 164 }; | |
| 165 | |
| 166 BrowserBridge.prototype.sendGetSpdyAlternateProtocolMappings = function() { | |
| 167 this.send('getSpdyAlternateProtocolMappings'); | |
| 168 }; | |
| 169 | |
| 170 BrowserBridge.prototype.sendGetServiceProviders = function() { | |
| 171 this.send('getServiceProviders'); | |
| 172 }; | |
| 173 | |
| 174 BrowserBridge.prototype.sendGetPrerenderInfo = function() { | |
| 175 this.send('getPrerenderInfo'); | |
| 176 }; | |
| 177 | |
| 178 BrowserBridge.prototype.enableIPv6 = function() { | |
| 179 this.send('enableIPv6'); | |
| 180 }; | |
| 181 | |
| 182 BrowserBridge.prototype.setLogLevel = function(logLevel) { | |
| 183 this.send('setLogLevel', ['' + logLevel]); | |
| 184 }; | |
| 185 | |
| 186 BrowserBridge.prototype.enableHttpThrottling = function(enable) { | |
| 187 this.send('enableHttpThrottling', [enable]); | |
| 188 }; | |
| 189 | |
| 190 BrowserBridge.prototype.refreshSystemLogs = function() { | |
| 191 this.send('refreshSystemLogs'); | |
| 192 }; | |
| 193 | |
| 194 BrowserBridge.prototype.getSystemLog = function(log_key, cellId) { | |
| 195 this.send('getSystemLog', [log_key, cellId]); | |
| 196 }; | |
| 197 | |
| 198 //------------------------------------------------------------------------------ | |
| 199 // Messages received from the browser. | |
| 200 //------------------------------------------------------------------------------ | |
| 201 | |
| 202 BrowserBridge.prototype.receive = function(command, params) { | |
| 203 // Does nothing if disabled. | |
| 204 if (this.disabled_) | |
| 205 return; | |
| 206 this[command](params); | |
| 207 }; | |
| 208 | |
| 209 BrowserBridge.prototype.receivedConstants = function(constants) { | |
| 210 for (var i = 0; i < this.constantsObservers_.length; ++i) | |
| 211 this.constantsObservers_[i].onReceivedConstants(constants); | |
| 212 }; | |
| 213 | |
| 214 BrowserBridge.prototype.receivedLogEntries = function(logEntries) { | |
| 215 this.sourceTracker.onReceivedLogEntries(logEntries); | |
| 216 }; | |
| 217 | |
| 218 BrowserBridge.prototype.receivedProxySettings = function(proxySettings) { | |
| 219 this.pollableDataHelpers_.proxySettings.update(proxySettings); | |
| 220 }; | |
| 221 | |
| 222 BrowserBridge.prototype.receivedBadProxies = function(badProxies) { | |
| 223 this.pollableDataHelpers_.badProxies.update(badProxies); | |
| 224 }; | |
| 225 | |
| 226 BrowserBridge.prototype.receivedHostResolverInfo = | |
| 227 function(hostResolverInfo) { | |
| 228 this.pollableDataHelpers_.hostResolverInfo.update(hostResolverInfo); | |
| 229 }; | |
| 230 | |
| 231 BrowserBridge.prototype.receivedSocketPoolInfo = function(socketPoolInfo) { | |
| 232 this.pollableDataHelpers_.socketPoolInfo.update(socketPoolInfo); | |
| 233 }; | |
| 234 | |
| 235 BrowserBridge.prototype.receivedSpdySessionInfo = function(spdySessionInfo) { | |
| 236 this.pollableDataHelpers_.spdySessionInfo.update(spdySessionInfo); | |
| 237 }; | |
| 238 | |
| 239 BrowserBridge.prototype.receivedSpdyStatus = function(spdyStatus) { | |
| 240 this.pollableDataHelpers_.spdyStatus.update(spdyStatus); | |
| 241 }; | |
| 242 | |
| 243 BrowserBridge.prototype.receivedSpdyAlternateProtocolMappings = | |
| 244 function(spdyAlternateProtocolMappings) { | |
| 245 this.pollableDataHelpers_.spdyAlternateProtocolMappings.update( | |
| 246 spdyAlternateProtocolMappings); | |
| 247 }; | |
| 248 | |
| 249 BrowserBridge.prototype.receivedServiceProviders = function(serviceProviders) { | |
| 250 this.pollableDataHelpers_.serviceProviders.update(serviceProviders); | |
| 251 }; | |
| 252 | |
| 253 BrowserBridge.prototype.receivedPassiveLogEntries = function(entries) { | |
| 254 this.sourceTracker.onReceivedPassiveLogEntries(entries); | |
| 255 }; | |
| 256 | |
| 257 BrowserBridge.prototype.receivedStartConnectionTestSuite = function() { | |
| 258 for (var i = 0; i < this.connectionTestsObservers_.length; ++i) | |
| 259 this.connectionTestsObservers_[i].onStartedConnectionTestSuite(); | |
| 260 }; | |
| 261 | |
| 262 BrowserBridge.prototype.receivedStartConnectionTestExperiment = function( | |
| 263 experiment) { | |
| 264 for (var i = 0; i < this.connectionTestsObservers_.length; ++i) { | |
| 265 this.connectionTestsObservers_[i].onStartedConnectionTestExperiment( | |
| 266 experiment); | |
| 267 } | |
| 268 }; | |
| 269 | |
| 270 BrowserBridge.prototype.receivedCompletedConnectionTestExperiment = | |
| 271 function(info) { | |
| 272 for (var i = 0; i < this.connectionTestsObservers_.length; ++i) { | |
| 273 this.connectionTestsObservers_[i].onCompletedConnectionTestExperiment( | |
| 274 info.experiment, info.result); | |
| 275 } | |
| 276 }; | |
| 277 | |
| 278 BrowserBridge.prototype.receivedCompletedConnectionTestSuite = function() { | |
| 279 for (var i = 0; i < this.connectionTestsObservers_.length; ++i) | |
| 280 this.connectionTestsObservers_[i].onCompletedConnectionTestSuite(); | |
| 281 }; | |
| 282 | |
| 283 BrowserBridge.prototype.receivedHSTSResult = function(info) { | |
| 284 for (var i = 0; i < this.hstsObservers_.length; ++i) | |
| 285 this.hstsObservers_[i].onHSTSQueryResult(info); | |
| 286 }; | |
| 287 | |
| 288 BrowserBridge.prototype.receivedHttpCacheInfo = function(info) { | |
| 289 this.pollableDataHelpers_.httpCacheInfo.update(info); | |
| 290 }; | |
| 291 | |
| 292 BrowserBridge.prototype.receivedHttpThrottlingEnabledPrefChanged = function( | |
| 293 enabled) { | |
| 294 for (var i = 0; i < this.httpThrottlingObservers_.length; ++i) { | |
| 295 this.httpThrottlingObservers_[i].onHttpThrottlingEnabledPrefChanged( | |
| 296 enabled); | |
| 297 } | |
| 298 }; | |
| 299 | |
| 300 BrowserBridge.prototype.receivedPrerenderInfo = function(prerenderInfo) { | |
| 301 this.pollableDataHelpers_.prerenderInfo.update(prerenderInfo); | |
| 302 }; | |
| 303 | |
| 304 //------------------------------------------------------------------------------ | |
| 305 | |
| 306 /** | |
| 307 * Prevents receiving/sending events to/from the browser. | |
| 308 */ | |
| 309 BrowserBridge.prototype.disable = function() { | |
| 310 this.disabled_ = true; | |
| 311 }; | |
| 312 | |
| 313 /** | |
| 314 * Adds a listener of the proxy settings. |observer| will be called back when | |
| 315 * data is received, through: | |
| 316 * | |
| 317 * observer.onProxySettingsChanged(proxySettings) | |
| 318 * | |
| 319 * |proxySettings| is a dictionary with (up to) two properties: | |
| 320 * | |
| 321 * "original" -- The settings that chrome was configured to use | |
| 322 * (i.e. system settings.) | |
| 323 * "effective" -- The "effective" proxy settings that chrome is using. | |
| 324 * (decides between the manual/automatic modes of the | |
| 325 * fetched settings). | |
| 326 * | |
| 327 * Each of these two configurations is formatted as a string, and may be | |
| 328 * omitted if not yet initialized. | |
| 329 * | |
| 330 * TODO(eroman): send a dictionary instead. | |
| 331 */ | |
| 332 BrowserBridge.prototype.addProxySettingsObserver = function(observer) { | |
| 333 this.pollableDataHelpers_.proxySettings.addObserver(observer); | |
| 334 }; | |
| 335 | |
| 336 /** | |
| 337 * Adds a listener of the proxy settings. |observer| will be called back when | |
| 338 * data is received, through: | |
| 339 * | |
| 340 * observer.onBadProxiesChanged(badProxies) | |
| 341 * | |
| 342 * |badProxies| is an array, where each entry has the property: | |
| 343 * badProxies[i].proxy_uri: String identify the proxy. | |
| 344 * badProxies[i].bad_until: The time when the proxy stops being considered | |
| 345 * bad. Note the time is in time ticks. | |
| 346 */ | |
| 347 BrowserBridge.prototype.addBadProxiesObserver = function(observer) { | |
| 348 this.pollableDataHelpers_.badProxies.addObserver(observer); | |
| 349 }; | |
| 350 | |
| 351 /** | |
| 352 * Adds a listener of the host resolver info. |observer| will be called back | |
| 353 * when data is received, through: | |
| 354 * | |
| 355 * observer.onHostResolverInfoChanged(hostResolverInfo) | |
| 356 */ | |
| 357 BrowserBridge.prototype.addHostResolverInfoObserver = function(observer) { | |
| 358 this.pollableDataHelpers_.hostResolverInfo.addObserver(observer); | |
| 359 }; | |
| 360 | |
| 361 /** | |
| 362 * Adds a listener of the socket pool. |observer| will be called back | |
| 363 * when data is received, through: | |
| 364 * | |
| 365 * observer.onSocketPoolInfoChanged(socketPoolInfo) | |
| 366 */ | |
| 367 BrowserBridge.prototype.addSocketPoolInfoObserver = function(observer) { | |
| 368 this.pollableDataHelpers_.socketPoolInfo.addObserver(observer); | |
| 369 }; | |
| 370 | |
| 371 /** | |
| 372 * Adds a listener of the SPDY info. |observer| will be called back | |
| 373 * when data is received, through: | |
| 374 * | |
| 375 * observer.onSpdySessionInfoChanged(spdySessionInfo) | |
| 376 */ | |
| 377 BrowserBridge.prototype.addSpdySessionInfoObserver = function(observer) { | |
| 378 this.pollableDataHelpers_.spdySessionInfo.addObserver(observer); | |
| 379 }; | |
| 380 | |
| 381 /** | |
| 382 * Adds a listener of the SPDY status. |observer| will be called back | |
| 383 * when data is received, through: | |
| 384 * | |
| 385 * observer.onSpdyStatusChanged(spdyStatus) | |
| 386 */ | |
| 387 BrowserBridge.prototype.addSpdyStatusObserver = function(observer) { | |
| 388 this.pollableDataHelpers_.spdyStatus.addObserver(observer); | |
| 389 }; | |
| 390 | |
| 391 /** | |
| 392 * Adds a listener of the AlternateProtocolMappings. |observer| will be called | |
| 393 * back when data is received, through: | |
| 394 * | |
| 395 * observer.onSpdyAlternateProtocolMappingsChanged( | |
| 396 * spdyAlternateProtocolMappings) | |
| 397 */ | |
| 398 BrowserBridge.prototype.addSpdyAlternateProtocolMappingsObserver = | |
| 399 function(observer) { | |
| 400 this.pollableDataHelpers_.spdyAlternateProtocolMappings.addObserver(observer); | |
| 401 }; | |
| 402 | |
| 403 /** | |
| 404 * Adds a listener of the service providers info. |observer| will be called | |
| 405 * back when data is received, through: | |
| 406 * | |
| 407 * observer.onServiceProvidersChanged(serviceProviders) | |
| 408 * | |
| 409 * Will do nothing if on a platform other than Windows, as service providers are | |
| 410 * only present on Windows. | |
| 411 */ | |
| 412 BrowserBridge.prototype.addServiceProvidersObserver = function(observer) { | |
| 413 if (this.pollableDataHelpers_.serviceProviders) | |
| 414 this.pollableDataHelpers_.serviceProviders.addObserver(observer); | |
| 415 }; | |
| 416 | |
| 417 /** | |
| 418 * Adds a listener for the progress of the connection tests. | |
| 419 * The observer will be called back with: | |
| 420 * | |
| 421 * observer.onStartedConnectionTestSuite(); | |
| 422 * observer.onStartedConnectionTestExperiment(experiment); | |
| 423 * observer.onCompletedConnectionTestExperiment(experiment, result); | |
| 424 * observer.onCompletedConnectionTestSuite(); | |
| 425 */ | |
| 426 BrowserBridge.prototype.addConnectionTestsObserver = function(observer) { | |
| 427 this.connectionTestsObservers_.push(observer); | |
| 428 }; | |
| 429 | |
| 430 /** | |
| 431 * Adds a listener for the http cache info results. | |
| 432 * The observer will be called back with: | |
| 433 * | |
| 434 * observer.onHttpCacheInfoChanged(info); | |
| 435 */ | |
| 436 BrowserBridge.prototype.addHttpCacheInfoObserver = function(observer) { | |
| 437 this.pollableDataHelpers_.httpCacheInfo.addObserver(observer); | |
| 438 }; | |
| 439 | |
| 440 /** | |
| 441 * Adds a listener for the results of HSTS (HTTPS Strict Transport Security) | |
| 442 * queries. The observer will be called back with: | |
| 443 * | |
| 444 * observer.onHSTSQueryResult(result); | |
| 445 */ | |
| 446 BrowserBridge.prototype.addHSTSObserver = function(observer) { | |
| 447 this.hstsObservers_.push(observer); | |
| 448 }; | |
| 449 | |
| 450 /** | |
| 451 * Adds a listener for HTTP throttling-related events. |observer| will be called | |
| 452 * back when HTTP throttling is enabled/disabled, through: | |
| 453 * | |
| 454 * observer.onHttpThrottlingEnabledPrefChanged(enabled); | |
| 455 */ | |
| 456 BrowserBridge.prototype.addHttpThrottlingObserver = function(observer) { | |
| 457 this.httpThrottlingObservers_.push(observer); | |
| 458 }; | |
| 459 | |
| 460 /** | |
| 461 * Adds a listener for the received constants event. |observer| will be called | |
| 462 * back when the constants are received, through: | |
| 463 * | |
| 464 * observer.onReceivedConstants(constants); | |
| 465 */ | |
| 466 BrowserBridge.prototype.addConstantsObserver = function(observer) { | |
| 467 this.constantsObservers_.push(observer); | |
| 468 }; | |
| 469 | |
| 470 /** | |
| 471 * Adds a listener for updated prerender info events | |
| 472 * |observer| will be called back with: | |
| 473 * | |
| 474 * observer.onPrerenderInfoChanged(prerenderInfo); | |
| 475 */ | |
| 476 BrowserBridge.prototype.addPrerenderInfoObserver = function(observer) { | |
| 477 this.pollableDataHelpers_.prerenderInfo.addObserver(observer); | |
| 478 }; | |
| 479 | |
| 480 /** | |
| 481 * If |force| is true, calls all startUpdate functions. Otherwise, just | |
| 482 * runs updates with active observers. | |
| 483 */ | |
| 484 BrowserBridge.prototype.checkForUpdatedInfo = function(force) { | |
| 485 for (name in this.pollableDataHelpers_) { | |
| 486 var helper = this.pollableDataHelpers_[name]; | |
| 487 if (force || helper.hasActiveObserver()) | |
| 488 helper.startUpdate(); | |
| 489 } | |
| 490 }; | |
| 491 | |
| 492 /** | |
| 493 * Calls all startUpdate functions and, if |callback| is non-null, | |
| 494 * calls it with the results of all updates. | |
| 495 */ | |
| 496 BrowserBridge.prototype.updateAllInfo = function(callback) { | |
| 497 if (callback) | |
| 498 new UpdateAllObserver(callback, this.pollableDataHelpers_); | |
| 499 this.checkForUpdatedInfo(true); | |
| 500 }; | |
| 501 | |
| 502 /** | |
| 503 * This is a helper class used by BrowserBridge, to keep track of: | |
| 504 * - the list of observers interested in some piece of data. | |
| 505 * - the last known value of that piece of data. | |
| 506 * - the name of the callback method to invoke on observers. | |
| 507 * - the update function. | |
| 508 * @constructor | |
| 509 */ | |
| 510 function PollableDataHelper(observerMethodName, startUpdateFunction) { | |
| 511 this.observerMethodName_ = observerMethodName; | |
| 512 this.startUpdate = startUpdateFunction; | |
| 513 this.observerInfos_ = []; | |
| 514 } | |
| 515 | |
| 516 PollableDataHelper.prototype.getObserverMethodName = function() { | |
| 517 return this.observerMethodName_; | |
| 518 }; | |
| 519 | |
| 520 PollableDataHelper.prototype.isObserver = function(object) { | |
| 521 for (var i = 0; i < this.observerInfos_.length; ++i) { | |
| 522 if (this.observerInfos_[i].observer == object) | |
| 523 return true; | |
| 524 } | |
| 525 return false; | |
| 526 }; | |
| 527 | |
| 528 /** | |
| 529 * This is a helper class used by PollableDataHelper, to keep track of | |
| 530 * each observer and whether or not it has received any data. The | |
| 531 * latter is used to make sure that new observers get sent data on the | |
| 532 * update following their creation. | |
| 533 * @constructor | |
| 534 */ | |
| 535 function ObserverInfo(observer) { | |
| 536 this.observer = observer; | |
| 537 this.hasReceivedData = false; | |
| 538 } | |
| 539 | |
| 540 PollableDataHelper.prototype.addObserver = function(observer) { | |
| 541 this.observerInfos_.push(new ObserverInfo(observer)); | |
| 542 }; | |
| 543 | |
| 544 PollableDataHelper.prototype.removeObserver = function(observer) { | |
| 545 for (var i = 0; i < this.observerInfos_.length; ++i) { | |
| 546 if (this.observerInfos_[i].observer === observer) { | |
| 547 this.observerInfos_.splice(i, 1); | |
| 548 return; | |
| 549 } | |
| 550 } | |
| 551 }; | |
| 552 | |
| 553 /** | |
| 554 * Helper function to handle calling all the observers, but ONLY if the data has | |
| 555 * actually changed since last time or the observer has yet to receive any data. | |
| 556 * This is used for data we received from browser on an update loop. | |
| 557 */ | |
| 558 PollableDataHelper.prototype.update = function(data) { | |
| 559 var prevData = this.currentData_; | |
| 560 var changed = false; | |
| 561 | |
| 562 // If the data hasn't changed since last time, will only need to notify | |
| 563 // observers that have not yet received any data. | |
| 564 if (!prevData || JSON.stringify(prevData) != JSON.stringify(data)) { | |
| 565 changed = true; | |
| 566 this.currentData_ = data; | |
| 567 } | |
| 568 | |
| 569 // Notify the observers of the change, as needed. | |
| 570 for (var i = 0; i < this.observerInfos_.length; ++i) { | |
| 571 var observerInfo = this.observerInfos_[i]; | |
| 572 if (changed || !observerInfo.hasReceivedData) { | |
| 573 observerInfo.observer[this.observerMethodName_](this.currentData_); | |
| 574 observerInfo.hasReceivedData = true; | |
| 575 } | |
| 576 } | |
| 577 }; | |
| 578 | |
| 579 /** | |
| 580 * Returns true if one of the observers actively wants the data | |
| 581 * (i.e. is visible). | |
| 582 */ | |
| 583 PollableDataHelper.prototype.hasActiveObserver = function() { | |
| 584 for (var i = 0; i < this.observerInfos_.length; ++i) { | |
| 585 if (this.observerInfos_[i].observer.isActive()) | |
| 586 return true; | |
| 587 } | |
| 588 return false; | |
| 589 }; | |
| 590 | |
| 591 /** | |
| 592 * This is a helper class used by BrowserBridge to send data to | |
| 593 * a callback once data from all polls has been received. | |
| 594 * | |
| 595 * It works by keeping track of how many polling functions have | |
| 596 * yet to receive data, and recording the data as it it received. | |
| 597 * | |
| 598 * @constructor | |
| 599 */ | |
| 600 function UpdateAllObserver(callback, pollableDataHelpers) { | |
| 601 this.callback_ = callback; | |
| 602 this.observingCount_ = 0; | |
| 603 this.updatedData_ = {}; | |
| 604 | |
| 605 for (name in pollableDataHelpers) { | |
| 606 ++this.observingCount_; | |
| 607 var helper = pollableDataHelpers[name]; | |
| 608 helper.addObserver(this); | |
| 609 this[helper.getObserverMethodName()] = | |
| 610 this.onDataReceived_.bind(this, helper, name); | |
| 611 } | |
| 612 } | |
| 613 | |
| 614 UpdateAllObserver.prototype.isActive = function() { | |
| 615 return true; | |
| 616 }; | |
| 617 | |
| 618 UpdateAllObserver.prototype.onDataReceived_ = function(helper, name, data) { | |
| 619 helper.removeObserver(this); | |
| 620 --this.observingCount_; | |
| 621 this.updatedData_[name] = data; | |
| 622 if (this.observingCount_ == 0) | |
| 623 this.callback_(this.updatedData_); | |
| 624 }; | |
| OLD | NEW |