Chromium Code Reviews| Index: remoting/webapp/crd/js/combined_host_list_api.js |
| diff --git a/remoting/webapp/crd/js/combined_host_list_api.js b/remoting/webapp/crd/js/combined_host_list_api.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..d8a9954c912f5036f4a541cb04a548efa500f7a6 |
| --- /dev/null |
| +++ b/remoting/webapp/crd/js/combined_host_list_api.js |
| @@ -0,0 +1,184 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +/** |
| + * @fileoverview |
| + * API implementation that combines two other implementations. |
| + */ |
| + |
| +/** @suppress {duplicate} */ |
| +var remoting = remoting || {}; |
| + |
| +(function() { |
| + |
| +'use strict'; |
| + |
| +/** |
| + * Amount of time to wait for GCD results after legacy registry has |
| + * returned. |
| + */ |
| +var GCD_TIMEOUT_MS = 1000; |
| + |
| +/** |
| + * @constructor |
| + * @param {!remoting.HostListApi} legacyImpl |
| + * @param {!remoting.HostListApi} gcdImpl |
| + * @implements {remoting.HostListApi} |
| + */ |
| +remoting.CombinedHostListApi = function(legacyImpl, gcdImpl) { |
| + /** @const {!remoting.HostListApi} */ |
| + this.legacyImpl_ = legacyImpl; |
| + |
| + /** @const {!remoting.HostListApi} */ |
| + this.gcdImpl_ = gcdImpl; |
| + |
| + /** |
| + * List of host IDs most recently retrieved from |legacyImpl_|. |
| + * @type {!Set<string>} |
| + */ |
| + this.legacyIds_ = new Set(); |
| + |
| + /** |
| + * List of host IDs most recently retrieved |gcdImpl_|. |
| + * @type {!Set<string>} |
| + */ |
| + this.gcdIds_ = new Set(); |
| +}; |
| + |
| +/** @override */ |
| +remoting.CombinedHostListApi.prototype.register = function( |
| + hostName, publicKey, hostClientId) { |
| + var that = this; |
| + // First, register the new host with GCD, which will create a |
| + // service account and generate a host ID. |
| + return this.gcdImpl_.register(hostName, publicKey, hostClientId).then( |
| + function(gcdRegResult) { |
| + // After the GCD registration has been created, copy the |
| + // registration to the legacy directory so that clients not yet |
| + // upgraded to use GCD can see the new host. |
| + // |
| + // This is an ugly hack for multiple reasons: |
| + // |
| + // 1. It completely ignores |this.legacyImpl_|, complicating |
| + // unit tests. |
| + // |
| + // 2. It relies on the fact that, when |hostClientId| is null, |
| + // the legacy directory will "register" a host without |
| + // creating a service account. This is an obsolete feature |
| + // of the legacy directory that is being revived for a new |
| + // purpose. |
| + // |
| + // 3. It assumes the device ID generated by GCD is usable as a |
| + // host ID by the legacy directory. Fortunately both systems |
| + // use UUIDs. |
| + return remoting.LegacyHostListApi.registerWithHostId( |
| + gcdRegResult.hostId, hostName, publicKey, null).then( |
| + function() { |
| + // On success, return the result from GCD, ignoring |
| + // the result returned by the legacy directory. |
| + that.gcdIds_.add(gcdRegResult.hostId); |
| + that.legacyIds_.add(gcdRegResult.hostId); |
| + return gcdRegResult; |
| + }, |
| + function(error) { |
| + console.warn( |
| + 'Error copying host GCD host registration ' + |
| + 'to legacy directory: ' + error); |
| + throw error; |
| + } |
| + ); |
| + }); |
| +}; |
| + |
| +/** @override */ |
| +remoting.CombinedHostListApi.prototype.get = function() { |
| + // Fetch the host list from both directories and merge hosts that |
| + // have the same ID. |
| + var that = this; |
| + var legacyPromise = this.legacyImpl_.get(); |
| + var gcdPromise = this.gcdImpl_.get(); |
| + return legacyPromise.then(function(legacyHosts) { |
| + // If GCD is too slow, just ignore it and return results from the |
| + // legacy directory. |
| + /** @type {!Promise<!Array<!remoting.Host>>} */ |
| + var timeoutPromise = base.Promise.withTimeout( |
| + gcdPromise, GCD_TIMEOUT_MS, []); |
| + return timeoutPromise.then(function(gcdHosts) { |
| + // Combine host information from both directories. In the case |
| + // of conflicting information, prefer information from whichever |
| + // directory claims to have newer information. |
| + |
| + var hosts = []; |
| + /** @type {!Map<string,!remoting.Host>} */ |
| + var gcdHostMap = new Map(); |
| + /** @type {!Map<string,!remoting.Host>} */ |
| + var legacyHostMap = new Map(); |
| + gcdHosts.forEach(function(host) { |
| + gcdHostMap.set(host.hostId, host); |
| + }); |
| + legacyHosts.forEach(function(host) { |
| + legacyHostMap.set(host.hostId, host); |
| + }); |
| + gcdHosts.forEach(function(host) { |
| + var legacyHost = legacyHostMap.get(host.hostId); |
| + if (!legacyHost || host.updatedTime >= legacyHost.updatedTime) { |
| + hosts.push(host); |
|
kelvinp
2015/07/20 18:00:51
Nit:
After we ensure that either there is no lega
John Williams
2015/07/20 21:43:10
I rewrote this method for clarity; PTAL.
|
| + } |
| + }); |
| + legacyHosts.forEach(function(host) { |
| + var gcdHost = gcdHostMap.get(host.hostId); |
| + if (!gcdHost || host.updatedTime > gcdHost.updatedTime) { |
| + hosts.push(host); |
| + } |
| + }); |
| + that.legacyIds_ = base.keySet(legacyHostMap); |
| + that.gcdIds_ = base.keySet(gcdHostMap); |
| + return hosts; |
| + }); |
| + }); |
| +}; |
| + |
| +/** @override */ |
| +remoting.CombinedHostListApi.prototype.put = |
| + function(hostId, hostName, hostPublicKey) { |
| + var legacyPromise = Promise.resolve(); |
| + if (this.legacyIds_.has(hostId)) { |
| + legacyPromise = this.legacyImpl_.put(hostId, hostName, hostPublicKey); |
| + } |
| + var gcdPromise = Promise.resolve(); |
| + if (this.gcdIds_.has(hostId)) { |
| + gcdPromise = this.gcdImpl_.put(hostId, hostName, hostPublicKey); |
| + } |
| + return legacyPromise.then(function() { |
| + // If GCD is too slow, just ignore it and return result from the |
| + // legacy directory. |
| + return base.Promise.withTimeout( |
| + gcdPromise, GCD_TIMEOUT_MS); |
| + }); |
| +}; |
| + |
| +/** @override */ |
| +remoting.CombinedHostListApi.prototype.remove = function(hostId) { |
| + var legacyPromise = Promise.resolve(); |
| + if (this.legacyIds_.has(hostId)) { |
| + legacyPromise = this.legacyImpl_.remove(hostId); |
| + } |
| + var gcdPromise = Promise.resolve(); |
| + if (this.gcdIds_.has(hostId)) { |
| + gcdPromise = this.gcdImpl_.remove(hostId); |
| + } |
| + return legacyPromise.then(function() { |
| + // If GCD is too slow, just ignore it and return result from the |
| + // legacy directory. |
| + return base.Promise.withTimeout( |
| + gcdPromise, GCD_TIMEOUT_MS); |
| + }); |
| +}; |
| + |
| +/** @override */ |
| +remoting.CombinedHostListApi.prototype.getSupportHost = function(supportId) { |
| + return this.legacyImpl_.getSupportHost(supportId); |
| +}; |
| + |
| +})(); |