Index: remoting/webapp/crd/js/identity.js |
diff --git a/remoting/webapp/crd/js/identity.js b/remoting/webapp/crd/js/identity.js |
index 96afd69470659ba092bae74d288fc470b3747371..28258168aad4a887bdd3ed35123cd7d54c4ac2b2 100644 |
--- a/remoting/webapp/crd/js/identity.js |
+++ b/remoting/webapp/crd/js/identity.js |
@@ -31,8 +31,8 @@ remoting.Identity = function(opt_consentDialog) { |
this.email_ = ''; |
/** @type {string} @private */ |
this.fullName_ = ''; |
- /** @type {Array<remoting.Identity.Callbacks>} */ |
- this.pendingCallbacks_ = []; |
+ /** @type {base.Deferred<string>} */ |
+ this.authTokenDeferred_ = null; |
}; |
/** |
@@ -51,122 +51,120 @@ remoting.Identity.ConsentDialog = function() {}; |
remoting.Identity.ConsentDialog.prototype.show = function() {}; |
/** |
- * Call a function with an access token. |
+ * Gets an access token. |
* |
- * @param {function(string):void} onOk Function to invoke with access token if |
- * an access token was successfully retrieved. |
- * @param {function(remoting.Error):void} onError Function to invoke with an |
- * error code on failure. |
- * @return {void} Nothing. |
+ * @return {!Promise<string>} A promise resolved with an access token |
+ * or rejected with a remoting.Error. |
*/ |
-remoting.Identity.prototype.callWithToken = function(onOk, onError) { |
- this.pendingCallbacks_.push(new remoting.Identity.Callbacks(onOk, onError)); |
- if (this.pendingCallbacks_.length == 1) { |
+remoting.Identity.prototype.getToken = function() { |
+ /** @const */ |
+ var that = this; |
+ |
+ if (this.authTokenDeferred_ == null) { |
+ this.authTokenDeferred_ = new base.Deferred(); |
chrome.identity.getAuthToken( |
{ 'interactive': false }, |
- this.onAuthComplete_.bind(this, false)); |
+ that.onAuthComplete_.bind(that, false)); |
} |
+ return this.authTokenDeferred_.promise(); |
}; |
/** |
- * Call a function with a fresh access token. |
+ * Gets a fresh access token. |
* |
- * @param {function(string):void} onOk Function to invoke with access token if |
- * an access token was successfully retrieved. |
- * @param {function(remoting.Error):void} onError Function to invoke with an |
- * error code on failure. |
- * @return {void} Nothing. |
+ * @return {!Promise<string>} A promise resolved with an access token |
+ * or rejected with a remoting.Error. |
*/ |
-remoting.Identity.prototype.callWithNewToken = function(onOk, onError) { |
+remoting.Identity.prototype.getNewToken = function() { |
/** @type {remoting.Identity} */ |
var that = this; |
- /** |
- * @param {string} token |
- */ |
- function revokeToken(token) { |
- chrome.identity.removeCachedAuthToken( |
- {'token': token }, |
- that.callWithToken.bind(that, onOk, onError)); |
- } |
- |
- this.callWithToken(revokeToken, onError); |
+ return this.getToken().then(function(/** string */ token) { |
+ return new Promise(function(resolve, reject) { |
+ chrome.identity.removeCachedAuthToken({'token': token }, function() { |
+ resolve(that.getToken()); |
+ }); |
+ }); |
+ }); |
}; |
/** |
- * Remove the cached auth token, if any. |
+ * Removes the cached auth token, if any. |
* |
- * @param {function():void=} opt_onDone Completion callback. |
- * @return {void} Nothing. |
+ * @return {!Promise<null>} A promise resolved with the operation completes. |
*/ |
-remoting.Identity.prototype.removeCachedAuthToken = function(opt_onDone) { |
- var onDone = (opt_onDone) ? opt_onDone : base.doNothing; |
- |
- /** @param {string} token */ |
- var onToken = function(token) { |
- if (token) { |
- chrome.identity.removeCachedAuthToken({'token': token}, onDone); |
- } else { |
- onDone(); |
- } |
- }; |
- chrome.identity.getAuthToken({'interactive': false}, onToken); |
+remoting.Identity.prototype.removeCachedAuthToken = function() { |
+ return new Promise(function(resolve, reject) { |
+ /** @param {string} token */ |
+ var onToken = function(token) { |
+ if (token) { |
+ chrome.identity.removeCachedAuthToken( |
+ {'token': token}, resolve.bind(null, null)); |
+ } else { |
+ resolve(null); |
+ } |
+ }; |
+ chrome.identity.getAuthToken({'interactive': false}, onToken); |
+ }); |
}; |
/** |
- * Get the user's email address and full name. |
- * The full name will be null unless the webapp has requested and been |
- * granted the userinfo.profile permission. |
+ * Gets the user's email address and full name. The full name will be |
+ * null unless the webapp has requested and been granted the |
+ * userinfo.profile permission. |
+ * |
+ * TODO(jrw): Type declarations say the name can't be null. Are the |
+ * types wrong, or is the documentation wrong? |
* |
- * @param {function(string,string):void} onOk Callback invoked when the user's |
- * email address and full name are available. |
- * @param {function(remoting.Error):void} onError Callback invoked if an |
- * error occurs. |
- * @return {void} Nothing. |
+ * @return {!Promise<{email:string, name:string}>} Promise |
+ * resolved with the user's email address and full name, or rejected |
+ * with a remoting.Error. |
*/ |
-remoting.Identity.prototype.getUserInfo = function(onOk, onError) { |
+remoting.Identity.prototype.getUserInfo = function() { |
if (this.isAuthenticated()) { |
- onOk(this.email_, this.fullName_); |
- return; |
+ /** |
+ * The temp variable is needed to work around a compiler bug. |
+ * @type {{email: string, name: string}} |
+ */ |
+ var result = {email: this.email_, name: this.fullName_}; |
+ return Promise.resolve(result); |
} |
/** @type {remoting.Identity} */ |
var that = this; |
- /** |
- * @param {string} email |
- * @param {string} name |
- */ |
- var onResponse = function(email, name) { |
- that.email_ = email; |
- that.fullName_ = name; |
- onOk(email, name); |
- }; |
- |
- this.callWithToken( |
- remoting.oauth2Api.getUserInfo.bind( |
- remoting.oauth2Api, onResponse, onError), |
- onError); |
+ return this.getToken().then(function(token) { |
+ return new Promise(function(resolve, reject) { |
+ /** |
+ * @param {string} email |
+ * @param {string} name |
+ */ |
+ var onResponse = function(email, name) { |
+ that.email_ = email; |
+ that.fullName_ = name; |
+ resolve({email: email, name: name}); |
+ }; |
+ |
+ remoting.oauth2Api.getUserInfo(onResponse, reject, token); |
+ }); |
+ }); |
}; |
/** |
- * Get the user's email address. |
+ * Gets the user's email address. |
* |
- * @param {function(string):void} onOk Callback invoked when the email |
- * address is available. |
- * @param {function(remoting.Error):void} onError Callback invoked if an |
- * error occurs. |
- * @return {void} Nothing. |
+ * @return {!Promise<string>} Promise resolved with the user's email |
+ * address or rejected with a remoting.Error. |
*/ |
-remoting.Identity.prototype.getEmail = function(onOk, onError) { |
- this.getUserInfo(function(email, name) { |
- onOk(email); |
- }, onError); |
+remoting.Identity.prototype.getEmail = function() { |
+ this.getUserInfo().then(function(userInfo) { |
+ return userInfo.email; |
+ }); |
}; |
/** |
- * Get the user's email address, or null if no successful call to getUserInfo |
- * has been made. |
+ * Gets the user's email address, or null if no successful call to |
+ * getUserInfo has been made. |
* |
* @return {?string} The cached email address, if available. |
*/ |
@@ -175,7 +173,8 @@ remoting.Identity.prototype.getCachedEmail = function() { |
}; |
/** |
- * Get the user's full name. |
+ * Gets the user's full name. |
+ * |
* This will return null if either: |
* No successful call to getUserInfo has been made, or |
* The webapp doesn't have permission to access this value. |
@@ -195,13 +194,15 @@ remoting.Identity.prototype.getCachedUserFullName = function() { |
* @private |
*/ |
remoting.Identity.prototype.onAuthComplete_ = function(interactive, token) { |
+ var authTokenDeferred = this.authTokenDeferred_; |
+ if (authTokenDeferred == null) { |
+ return; |
+ } |
+ this.authTokenDeferred_ = null; |
+ |
// Pass the token to the callback(s) if it was retrieved successfully. |
if (token) { |
- while (this.pendingCallbacks_.length > 0) { |
- var callback = /** @type {remoting.Identity.Callbacks} */ |
- (this.pendingCallbacks_.shift()); |
- callback.onOk(token); |
- } |
+ authTokenDeferred.resolve(token); |
return; |
} |
@@ -212,11 +213,7 @@ remoting.Identity.prototype.onAuthComplete_ = function(interactive, token) { |
chrome.runtime.lastError ? chrome.runtime.lastError.message |
: 'Unknown error.'; |
console.error(error_message); |
- while (this.pendingCallbacks_.length > 0) { |
- var callback = /** @type {remoting.Identity.Callbacks} */ |
- (this.pendingCallbacks_.shift()); |
- callback.onError(remoting.Error.NOT_AUTHENTICATED); |
- } |
+ authTokenDeferred.reject(remoting.Error.NOT_AUTHENTICATED); |
return; |
} |
@@ -226,27 +223,12 @@ remoting.Identity.prototype.onAuthComplete_ = function(interactive, token) { |
var showConsentDialog = |
(this.consentDialog_) ? this.consentDialog_.show() : Promise.resolve(); |
showConsentDialog.then(function() { |
- chrome.identity.getAuthToken({'interactive': true}, |
- that.onAuthComplete_.bind(that, true)); |
+ chrome.identity.getAuthToken( |
+ {'interactive': true}, that.onAuthComplete_.bind(that, true)); |
}); |
}; |
/** |
- * Internal representation for pair of callWithToken callbacks. |
- * |
- * @param {function(string):void} onOk |
- * @param {function(remoting.Error):void} onError |
- * @constructor |
- * @private |
- */ |
-remoting.Identity.Callbacks = function(onOk, onError) { |
- /** @type {function(string):void} */ |
- this.onOk = onOk; |
- /** @type {function(remoting.Error):void} */ |
- this.onError = onError; |
-}; |
- |
-/** |
* Returns whether the web app has authenticated with the Google services. |
* |
* @return {boolean} |