Chromium Code Reviews| Index: chrome/browser/resources/print_preview/cloud_print_interface.js |
| diff --git a/chrome/browser/resources/print_preview/cloud_print_interface.js b/chrome/browser/resources/print_preview/cloud_print_interface.js |
| index ea6b271bb31bb0f2ffcd11a020c55d0a3937b8bd..35da404ef3a38e1d1b260eb9bb05cf1f02b18d51 100644 |
| --- a/chrome/browser/resources/print_preview/cloud_print_interface.js |
| +++ b/chrome/browser/resources/print_preview/cloud_print_interface.js |
| @@ -10,10 +10,12 @@ cr.define('cloudprint', function() { |
| * @param {string} baseUrl Base part of the Google Cloud Print service URL |
| * with no trailing slash. For example, |
| * 'https://www.google.com/cloudprint'. |
| + * @param {!print_preview.NativeLayer} nativeLayer Native layer used to get |
| + * Auth2 tokens. |
| * @constructor |
| * @extends {cr.EventTarget} |
| */ |
| - function CloudPrintInterface(baseUrl) { |
| + function CloudPrintInterface(baseUrl, nativeLayer) { |
| /** |
| * The base URL of the Google Cloud Print API. |
| * @type {string} |
| @@ -22,6 +24,13 @@ cr.define('cloudprint', function() { |
| this.baseUrl_ = baseUrl; |
| /** |
| + * Used to get Auth2 tokens. |
| + * @type {!print_preview.NativeLayer} |
| + * @private |
| + */ |
| + this.nativeLayer_ = nativeLayer; |
| + |
| + /** |
| * Last received XSRF token. Sent as a parameter in every request. |
| * @type {string} |
| * @private |
| @@ -29,11 +38,27 @@ cr.define('cloudprint', function() { |
| this.xsrfToken_ = ''; |
| /** |
| + * Pending requests delayed until we get access token. |
| + * @type {!Array<objects>} |
|
Toscano
2013/04/19 17:04:33
The type looks like: {!Array.<Object>}
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
Actually i have type so * @type {!Array<!ClourPrin
|
| + * @private |
| + */ |
| + this.requestQueue_ = []; |
| + |
| + /** |
| * Number of outstanding cloud destination search requests. |
| * @type {number} |
| * @private |
| */ |
| this.outstandingCloudSearchRequestCount_ = 0; |
| + |
| + /** |
| + * Event tracker used to keep track of native layer events. |
| + * @type {!EventTracker} |
| + * @private |
| + */ |
| + this.tracker_ = new EventTracker(); |
| + |
| + this.addEventListeners_(); |
| }; |
| /** |
| @@ -97,6 +122,19 @@ cr.define('cloudprint', function() { |
| PRINTER: 'printer' |
| }; |
| + /** |
| + * Could Print origins used to search printers. |
| + * @type {!Array<!print_preview.Destination.Origin>} |
|
Toscano
2013/04/19 17:04:33
Missing the "." between "Array" and "<!...":
{!Ar
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
Done.
|
| + * @const |
| + * @private |
| + */ |
| + CloudPrintInterface.CLOUD_ORIGINS_ = [ |
| + print_preview.Destination.Origin.COOKIES, |
| + print_preview.Destination.Origin.DEVICE |
| + // TODO(vitalybuka): Enable when implemented. |
| + // ready print_preview.Destination.Origin.PROFILE |
| + ]; |
| + |
| CloudPrintInterface.prototype = { |
| __proto__: cr.EventTarget.prototype, |
| @@ -126,9 +164,12 @@ cr.define('cloudprint', function() { |
| if (isRecent) { |
| params.push(new HttpParam('q', '^recent')); |
| } |
| - ++this.outstandingCloudSearchRequestCount_; |
| - this.sendRequest_('GET', 'search', params, |
| - this.onSearchDone_.bind(this, isRecent)); |
| + CloudPrintInterface.CLOUD_ORIGINS_.forEach(function(origin) { |
| + ++this.outstandingCloudSearchRequestCount_; |
| + var cpRequest = this.buildRequest_('GET', 'search', params, origin); |
| + this.sendOrQueueRequest_(cpRequest, |
| + this.onSearchDone_.bind(this, isRecent)); |
| + }, this); |
| }, |
| /** |
| @@ -157,21 +198,24 @@ cr.define('cloudprint', function() { |
| '__google__chrome_version=' + chromeVersion), |
| new HttpParam('tag', '__google__os=' + navigator.platform) |
| ]; |
| - this.sendRequest_('POST', 'submit', params, |
| - this.onSubmitDone_.bind(this)); |
| + var cpRequest = this.buildRequest_('POST', 'submit', params, |
| + destination.origin); |
| + this.sendOrQueueRequest_(cpRequest, this.onSubmitDone_.bind(this)); |
| }, |
| /** |
| * Sends a Google Cloud Print printer API request. |
| * @param {string} printerId ID of the printer to lookup. |
| + * @param {!print_preview.Destination.Origin} origin Origin of the printer. |
| */ |
| - printer: function(printerId) { |
| + printer: function(printerId, origin) { |
| var params = [ |
| new HttpParam('printerid', printerId), |
| new HttpParam('use_cdd', 'true') |
| ]; |
| - this.sendRequest_('GET', 'printer', params, |
| - this.onPrinterDone_.bind(this, printerId)); |
| + var cpRequest = this.buildRequest_('GET', 'printer', params, origin); |
| + this.sendOrQueueRequest_(cpRequest, |
| + this.onPrinterDone_.bind(this, printerId)); |
| }, |
| /** |
| @@ -179,16 +223,55 @@ cr.define('cloudprint', function() { |
| * terms-of-service of the given printer. |
| * @param {string} printerId ID of the printer to accept the |
| * terms-of-service for. |
| + * @param {!print_preview.Destination.Origin} origin Origin of the printer. |
| * @param {boolean} isAccepted Whether the user accepted the |
| * terms-of-service. |
| */ |
| - updatePrinterTosAcceptance: function(printerId, isAccepted) { |
| + updatePrinterTosAcceptance: function(printerId, origin, isAccepted) { |
| var params = [ |
| new HttpParam('printerid', printerId), |
| new HttpParam('is_tos_accepted', isAccepted) |
| ]; |
| - this.sendRequest_('POST', 'update', params, |
| - this.onUpdatePrinterTosAcceptanceDone_.bind(this)); |
| + var cpRequest = this.buildRequest_('POST', 'update', params, origin); |
| + this.sendOrQueueRequest_(cpRequest, |
| + this.onUpdateTosAcceptanceDone_.bind(this)); |
|
Toscano
2013/04/19 17:04:33
Why did you change the name of the callback? Now i
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
Done.
|
| + }, |
| + |
| + /** |
| + * Adds event listeners to the relevant native layer events. |
| + * @private |
| + */ |
| + addEventListeners_: function() { |
| + this.tracker_.add( |
| + this.nativeLayer_, |
| + print_preview.NativeLayer.EventType.ACCESS_TOKEN_READY, |
| + this.onAccessTokenReady_.bind(this)); |
| + }, |
| + |
| + /** |
| + * Called when a native layer receives access token. |
| + * @param {cr.Event} evt Contains the authetication type and access token. |
| + * @private |
| + */ |
| + onAccessTokenReady_: function(event) { |
|
Toscano
2013/04/19 17:04:33
private handlers should come after all other priva
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
Done.
|
| + assert(event.authType == print_preview.Destination.Origin.DEVICE); |
| + this.requestQueue_ = this.requestQueue_.filter(function(request) { |
| + assert(request.origin == print_preview.Destination.Origin.DEVICE); |
|
Toscano
2013/04/19 17:04:33
Can you add a TODO to remove this assert once we s
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
Done.
|
| + if (request.origin != event.authType) |
|
Toscano
2013/04/19 17:04:33
Please enclose "if" body with {}
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
Done.
|
| + return true; |
| + if (event.accessToken) { |
| + request.xhr.setRequestHeader('Authorization', |
| + 'Bearer ' + event.accessToken); |
| + this.sendRequest_(request); |
| + } else { |
| + // No valid token. |
| + request.callback(401, { |
|
Toscano
2013/04/19 17:04:33
Should be 403. With a string as the second paramet
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
403 cause sign in promo
|
| + 'errorCode' : -1, |
| + 'message' : 'No access token.' |
| + }, request.origin); |
| + } |
| + return false; |
| + }, this); |
| }, |
| /** |
| @@ -246,22 +329,25 @@ cr.define('cloudprint', function() { |
| }, |
| /** |
| - * Sends a request to the Google Cloud Print API. |
| + * Builds request to the Google Cloud Print API. |
| * @param {string} method HTTP method of the request. |
| * @param {string} action Google Cloud Print action to perform. |
| * @param {Array.<!HttpParam>} params HTTP parameters to include in the |
| * request. |
| - * @param {function(number, Object)} callback Callback to invoke when |
| - * request completes. |
| + * @param {!print_preview.Destination.Origin} origin Origin for destination. |
| + * @private |
|
Toscano
2013/04/19 17:04:33
Where is the @return statement?
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
Done.
|
| */ |
| - sendRequest_: function(method, action, params, callback) { |
| - if (!this.xsrfToken_) { |
| - // TODO(rltoscano): Should throw an error if not a read-only action or |
| - // issue an xsrf token request. |
| + buildRequest_: function(method, action, params, origin) { |
| + var url = this.baseUrl_ + '/' + action + '?xsrf='; |
|
Toscano
2013/04/19 17:04:33
You add "xsrf=" to the url, but you only provide a
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
that's how search request worked before, the first
Toscano
2013/04/19 22:32:33
Ok, not a big deal. As long as it works.
On 2013/
|
| + if (origin == print_preview.Destination.Origin.COOKIES) { |
| + if (!this.xsrfToken_) { |
| + // TODO(rltoscano): Should throw an error if not a read-only action or |
| + // issue an xsrf token request. |
| + } else { |
| + url = url + this.xsrfToken_; |
| + } |
| } |
| - var url = this.baseUrl_ + '/' + action + '?xsrf=' + this.xsrfToken_; |
| var body = null; |
| - |
| if (params) { |
| if (method == 'GET') { |
| url = params.reduce(function(partialUrl, param) { |
| @@ -286,14 +372,38 @@ cr.define('cloudprint', function() { |
| } |
| var xhr = new XMLHttpRequest(); |
| - xhr.onreadystatechange = |
| - this.onReadyStateChange_.bind(this, xhr, callback); |
| xhr.open(method, url, true); |
| - xhr.withCredentials = true; |
| + xhr.withCredentials = |
| + (origin == print_preview.Destination.Origin.COOKIES); |
| for (var header in headers) { |
| xhr.setRequestHeader(header, headers[header]); |
| } |
| - xhr.send(body); |
| + |
| + return new ClourPrintRequest(xhr, body, origin); |
|
Toscano
2013/04/19 17:04:33
Cloud*PrintRequest.
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
Done.
|
| + }, |
| + |
| + /** |
| + * Sends a request to the Google Cloud Print API. Or queue if it needs to |
|
Toscano
2013/04/19 17:04:33
This is one sentence. No need for a period before
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
Done.
|
| + * wait OAuth2 access token. |
| + * @param {!CloudPrintRequest} request Request to send or queue. |
| + * @param {function(number, Object, !print_preview.Destination.Origin)} |
| + * callback Callback to invoke when request completes. |
| + * @private |
| + */ |
| + sendOrQueueRequest_: function(request, callback) { |
|
Toscano
2013/04/19 17:04:33
It actually looks like it makes more sense to incl
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
Done.
|
| + request.callback = callback; |
|
Toscano
2013/04/19 17:04:33
The CloudPrintRequest does not have a callback fie
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
Done.
|
| + if (request.origin == print_preview.Destination.Origin.COOKIES) { |
| + return this.sendRequest_(request); |
| + } else { |
| + this.requestQueue_.push(request); |
| + this.nativeLayer_.startGetAccessToken(request.origin); |
| + } |
| + }, |
| + |
| + sendRequest_: function(request) { |
|
Toscano
2013/04/19 17:04:33
Please add jsdoc for this method.
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
Done.
|
| + request.xhr.onreadystatechange = |
| + this.onReadyStateChange_.bind(this, request); |
| + request.xhr.send(request.body); |
| }, |
| /** |
| @@ -316,20 +426,19 @@ cr.define('cloudprint', function() { |
| /** |
| * Called when the ready-state of a XML http request changes. |
| * Calls the successCallback with the result or dispatches an ERROR event. |
| - * @param {XMLHttpRequest} xhr XML http request that changed. |
| - * @param {function(number, Object)} callback Callback to invoke when |
| - * request completes. |
| + * @param {!CloudPrintRequest} request Request that changed. |
| * @private |
| */ |
| - onReadyStateChange_: function(xhr, callback) { |
| - if (xhr.readyState == 4) { |
| - if (xhr.status == 200) { |
| - var result = JSON.parse(xhr.responseText); |
| - if (result['success']) { |
| + onReadyStateChange_: function(request) { |
| + if (request.xhr.readyState == 4) { |
| + if (request.xhr.status == 200) { |
| + var result = JSON.parse(request.xhr.responseText); |
| + if (request.origin == print_preview.Destination.Origin.COOKIES && |
| + result['success']) { |
| this.xsrfToken_ = result['xsrf_token']; |
| } |
| } |
| - callback(xhr.status, result); |
| + request.callback(request.xhr.status, result, request.origin); |
|
Toscano
2013/04/19 17:04:33
Let's just add a result field to CloudPrintRequest
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
Done.
|
| } |
| }, |
| @@ -339,9 +448,10 @@ cr.define('cloudprint', function() { |
| * destinations. |
| * @param {number} status Status of the HTTP request. |
| * @param {Object} result JSON response. |
| + * @param {!print_preview.Destination.Origin} origin Origin for destination. |
| * @private |
| */ |
| - onSearchDone_: function(isRecent, status, result) { |
| + onSearchDone_: function(isRecent, status, result, origin) { |
| --this.outstandingCloudSearchRequestCount_; |
| if (status == 200 && result['success']) { |
| var printerListJson = result['printers'] || []; |
| @@ -349,8 +459,7 @@ cr.define('cloudprint', function() { |
| printerListJson.forEach(function(printerJson) { |
| try { |
| printerList.push( |
| - cloudprint.CloudDestinationParser.parse( |
| - printerJson, print_preview.Destination.Origin.COOKIES)); |
| + cloudprint.CloudDestinationParser.parse(printerJson, origin)); |
| } catch (err) { |
| console.error('Unable to parse cloud print destination: ' + err); |
| } |
| @@ -358,6 +467,7 @@ cr.define('cloudprint', function() { |
| var searchDoneEvent = |
| new cr.Event(CloudPrintInterface.EventType.SEARCH_DONE); |
| searchDoneEvent.printers = printerList; |
| + searchDoneEvent.origin = origin; |
| searchDoneEvent.isRecent = isRecent; |
| searchDoneEvent.email = result['request']['user']; |
| this.dispatchEvent(searchDoneEvent); |
| @@ -372,9 +482,10 @@ cr.define('cloudprint', function() { |
| * Called when the submit request completes. |
| * @param {number} status Status of the HTTP request. |
| * @param {Object} result JSON response. |
| + * @param {!print_preview.Destination.Origin} origin Origin for destination. |
| * @private |
| */ |
| - onSubmitDone_: function(status, result) { |
| + onSubmitDone_: function(status, result, origin) { |
| if (status == 200 && result['success']) { |
| var submitDoneEvent = new cr.Event( |
| CloudPrintInterface.EventType.SUBMIT_DONE); |
| @@ -392,15 +503,16 @@ cr.define('cloudprint', function() { |
| * @param {string} destinationId ID of the destination that was looked up. |
| * @param {number} status Status of the HTTP request. |
| * @param {Object} result JSON response. |
| + * @param {!print_preview.Destination.Origin} origin Origin for destination. |
| * @private |
| */ |
| - onPrinterDone_: function(destinationId, status, result) { |
| + onPrinterDone_: function(destinationId, status, result, origin) { |
| if (status == 200 && result['success']) { |
| var printerJson = result['printers'][0]; |
| var printer; |
| try { |
| - printer = cloudprint.CloudDestinationParser.parse( |
| - printerJson, print_preview.Destination.Origin.COOKIES); |
| + printer = cloudprint.CloudDestinationParser.parse(printerJson, |
| + origin); |
| } catch (err) { |
| console.error('Failed to parse cloud print destination: ' + |
| JSON.stringify(printerJson)); |
| @@ -414,8 +526,8 @@ cr.define('cloudprint', function() { |
| var errorEvent = this.createErrorEvent_( |
| CloudPrintInterface.EventType.PRINTER_FAILED, status, result); |
| errorEvent.destinationId = destinationId; |
| - errorEvent.destinationOrigin = print_preview.Destination.Origin.COOKIES; |
| - this.dispatchEvent(errorEvent); |
| + errorEvent.destinationOrigin = origin; |
| + this.dispatchEvent(errorEvent, origin); |
| } |
| }, |
| @@ -423,9 +535,10 @@ cr.define('cloudprint', function() { |
| * Called when the update printer TOS acceptance request completes. |
| * @param {number} status Status of the HTTP request. |
| * @param {Object} result JSON response. |
| + * @param {!print_preview.Destination.Origin} origin Origin for destination. |
| * @private |
| */ |
| - onUpdatePrinterTosAcceptanceDone_: function(status, result) { |
| + onUpdateTosAcceptanceDone_: function(status, result, origin) { |
| if (status == 200 && result['success']) { |
| // Do nothing. |
| } else { |
| @@ -437,6 +550,33 @@ cr.define('cloudprint', function() { |
| }; |
| /** |
| + * Data structure that holds data for delayed Cloud Print requests. |
|
Toscano
2013/04/19 17:04:33
delayed: not all of them are delayed.
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
Done.
|
| + * @param {!XMLHttpRequest} xhr Partially prepared http request. |
| + * @param {string} body Data to send with POST requests. |
| + * @param {!print_preview.Destination.Origin} origin Origin for destination. |
| + * @constructor |
| + */ |
| + function ClourPrintRequest(xhr, body, origin) { |
|
Toscano
2013/04/19 17:04:33
Cloud*PrintRequest
Toscano
2013/04/19 17:04:33
Please add callback parameter.
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
Done.
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
Done.
|
| + /** |
| + * Partially prepared http request. |
| + * @type {!XMLHttpRequest} |
| + */ |
| + this.xhr = xhr; |
| + |
| + /** |
| + * Data to send with POST requests. |
| + * @type {string} |
| + */ |
| + this.body = body; |
| + |
| + /** |
| + * Origin for destination. |
| + * @type {!print_preview.Destination.Origin} |
| + */ |
| + this.origin = origin; |
| + }; |
|
Toscano
2013/04/19 17:04:33
Please add "callback" and "result" fields.
Vitaly Buka (NO REVIEWS)
2013/04/19 22:14:29
Done.
|
| + |
| + /** |
| * Data structure that represents an HTTP parameter. |
| * @param {string} name Name of the parameter. |
| * @param {string} value Value of the parameter. |