Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(470)

Side by Side Diff: chrome/service/cloud_print/cloud_print_proxy_backend.cc

Issue 8387011: Chrome proxy refactoring. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/service/cloud_print/cloud_print_proxy_backend.h" 5 #include "chrome/service/cloud_print/cloud_print_proxy_backend.h"
6 6
7 #include <map> 7 #include <map>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/file_util.h" 10 #include "base/file_util.h"
11 #include "base/md5.h"
12 #include "base/rand_util.h" 11 #include "base/rand_util.h"
13 #include "base/string_number_conversions.h"
14 #include "base/string_split.h"
15 #include "base/stringprintf.h"
16 #include "base/utf_string_conversions.h"
17 #include "base/values.h" 12 #include "base/values.h"
18 #include "chrome/common/net/gaia/gaia_oauth_client.h" 13 #include "chrome/common/net/gaia/gaia_oauth_client.h"
19 #include "chrome/common/net/gaia/gaia_urls.h" 14 #include "chrome/common/net/gaia/gaia_urls.h"
15 #include "chrome/service/cloud_print/cloud_print_auth.h"
16 #include "chrome/service/cloud_print/cloud_print_connector.h"
20 #include "chrome/service/cloud_print/cloud_print_consts.h" 17 #include "chrome/service/cloud_print/cloud_print_consts.h"
21 #include "chrome/service/cloud_print/cloud_print_helpers.h" 18 #include "chrome/service/cloud_print/cloud_print_helpers.h"
22 #include "chrome/service/cloud_print/cloud_print_token_store.h" 19 #include "chrome/service/cloud_print/cloud_print_token_store.h"
23 #include "chrome/service/cloud_print/cloud_print_url_fetcher.h"
24 #include "chrome/service/cloud_print/printer_job_handler.h"
25 #include "chrome/service/gaia/service_gaia_authenticator.h" 20 #include "chrome/service/gaia/service_gaia_authenticator.h"
26 #include "chrome/service/net/service_url_request_context.h" 21 #include "chrome/service/net/service_url_request_context.h"
27 #include "chrome/service/service_process.h" 22 #include "chrome/service/service_process.h"
28 #include "googleurl/src/gurl.h" 23 #include "googleurl/src/gurl.h"
29 #include "grit/generated_resources.h" 24 #include "grit/generated_resources.h"
30 #include "jingle/notifier/base/notifier_options.h" 25 #include "jingle/notifier/base/notifier_options.h"
31 #include "jingle/notifier/listener/mediator_thread_impl.h" 26 #include "jingle/notifier/listener/mediator_thread_impl.h"
32 #include "jingle/notifier/listener/talk_mediator_impl.h" 27 #include "jingle/notifier/listener/talk_mediator_impl.h"
33 #include "net/url_request/url_request_status.h"
34 #include "ui/base/l10n/l10n_util.h" 28 #include "ui/base/l10n/l10n_util.h"
35 29
36 // The real guts of CloudPrintProxyBackend, to keep the public client API clean. 30 // The real guts of CloudPrintProxyBackend, to keep the public client API clean.
37 class CloudPrintProxyBackend::Core 31 class CloudPrintProxyBackend::Core
38 : public base::RefCountedThreadSafe<CloudPrintProxyBackend::Core>, 32 : public base::RefCountedThreadSafe<CloudPrintProxyBackend::Core>,
39 public CloudPrintURLFetcherDelegate, 33 public CloudPrintAuth::Client,
40 public cloud_print::PrintServerWatcherDelegate, 34 public CloudPrintConnector::Client,
41 public PrinterJobHandlerDelegate, 35 public notifier::TalkMediator::Delegate {
42 public notifier::TalkMediator::Delegate,
43 public gaia::GaiaOAuthClient::Delegate {
44 public: 36 public:
45 // It is OK for print_server_url to be empty. In this case system should 37 // It is OK for print_server_url to be empty. In this case system should
46 // use system default (local) print server. 38 // use system default (local) print server.
47 Core(CloudPrintProxyBackend* backend, 39 Core(CloudPrintProxyBackend* backend,
40 const std::string& proxy_id,
48 const GURL& cloud_print_server_url, 41 const GURL& cloud_print_server_url,
49 const DictionaryValue* print_system_settings, 42 const DictionaryValue* print_system_settings,
50 const gaia::OAuthClientInfo& oauth_client_info, 43 const gaia::OAuthClientInfo& oauth_client_info,
51 bool enable_job_poll); 44 bool enable_job_poll);
52 45
53 // Note: 46 // Note:
54 // 47 //
55 // The Do* methods are the various entry points from CloudPrintProxyBackend 48 // The Do* methods are the various entry points from CloudPrintProxyBackend
56 // It calls us on a dedicated thread to actually perform synchronous 49 // It calls us on a dedicated thread to actually perform synchronous
57 // (and potentially blocking) operations. 50 // (and potentially blocking) operations.
(...skipping 15 matching lines...) Expand all
73 void DoInitializeWithRobotAuthCode(const std::string& robot_oauth_auth_code, 66 void DoInitializeWithRobotAuthCode(const std::string& robot_oauth_auth_code,
74 const std::string& robot_email, 67 const std::string& robot_email,
75 const std::string& proxy_id); 68 const std::string& proxy_id);
76 69
77 // Called on the CloudPrintProxyBackend core_thread_ to perform 70 // Called on the CloudPrintProxyBackend core_thread_ to perform
78 // shutdown. 71 // shutdown.
79 void DoShutdown(); 72 void DoShutdown();
80 void DoRegisterSelectedPrinters( 73 void DoRegisterSelectedPrinters(
81 const printing::PrinterList& printer_list); 74 const printing::PrinterList& printer_list);
82 75
83 // CloudPrintURLFetcher::Delegate implementation. 76 // CloudPrintAuth::Client implementation.
84 virtual CloudPrintURLFetcher::ResponseAction HandleJSONData( 77 virtual void OnAuthenticationComplete(
85 const content::URLFetcher* source, 78 const std::string& access_token,
86 const GURL& url, 79 const std::string& robot_oauth_refresh_token,
87 DictionaryValue* json_data, 80 const std::string& robot_email,
88 bool succeeded); 81 const std::string& user_email);
82 virtual void OnInvalidCredentials();
89 83
90 virtual void OnRequestAuthError(); 84 // CloudPrintConnector::Client implementation.
91 85 virtual void OnPrintersAvailable(const printing::PrinterList& printers);
92 // cloud_print::PrintServerWatcherDelegate implementation 86 virtual void OnAuthFailed();
93 virtual void OnPrinterAdded();
94 // PrinterJobHandler::Delegate implementation
95 virtual void OnPrinterJobHandlerShutdown(PrinterJobHandler* job_handler,
96 const std::string& printer_id);
97 virtual void OnAuthError();
98 virtual void OnPrinterNotFound(const std::string& printer_name,
99 bool* delete_from_server);
100 87
101 // notifier::TalkMediator::Delegate implementation. 88 // notifier::TalkMediator::Delegate implementation.
102 virtual void OnNotificationStateChange( 89 virtual void OnNotificationStateChange(
103 bool notifications_enabled); 90 bool notifications_enabled);
104 virtual void OnIncomingNotification( 91 virtual void OnIncomingNotification(
105 const notifier::Notification& notification); 92 const notifier::Notification& notification);
106 virtual void OnOutgoingNotification(); 93 virtual void OnOutgoingNotification();
107 94
108 // gaia::GaiaOAuthClient::Delegate implementation.
109 virtual void OnGetTokensResponse(const std::string& refresh_token,
110 const std::string& access_token,
111 int expires_in_seconds);
112 virtual void OnRefreshTokenResponse(const std::string& access_token,
113 int expires_in_seconds);
114 virtual void OnOAuthError();
115 virtual void OnNetworkError(int response_code);
116
117 private: 95 private:
118 // Prototype for a response handler.
119 typedef CloudPrintURLFetcher::ResponseAction
120 (CloudPrintProxyBackend::Core::*ResponseHandler)(
121 const content::URLFetcher* source,
122 const GURL& url,
123 DictionaryValue* json_data,
124 bool succeeded);
125 // Begin response handlers
126 CloudPrintURLFetcher::ResponseAction HandlePrinterListResponse(
127 const content::URLFetcher* source,
128 const GURL& url,
129 DictionaryValue* json_data,
130 bool succeeded);
131
132 CloudPrintURLFetcher::ResponseAction HandleRegisterPrinterResponse(
133 const content::URLFetcher* source,
134 const GURL& url,
135 DictionaryValue* json_data,
136 bool succeeded);
137
138 CloudPrintURLFetcher::ResponseAction HandleRegisterFailedStatusResponse(
139 const content::URLFetcher* source,
140 const GURL& url,
141 DictionaryValue* json_data,
142 bool succeeded);
143
144 CloudPrintURLFetcher::ResponseAction HandlePrintSystemUnavailableResponse(
145 const content::URLFetcher* source,
146 const GURL& url,
147 DictionaryValue* json_data,
148 bool succeeded);
149
150 CloudPrintURLFetcher::ResponseAction HandleEnumPrintersFailedResponse(
151 const content::URLFetcher* source,
152 const GURL& url,
153 DictionaryValue* json_data,
154 bool succeeded);
155
156 CloudPrintURLFetcher::ResponseAction HandleGetAuthCodeResponse(
157 const content::URLFetcher* source,
158 const GURL& url,
159 DictionaryValue* json_data,
160 bool succeeded);
161
162 // End response handlers
163
164 // NotifyXXX is how the Core communicates with the frontend across 96 // NotifyXXX is how the Core communicates with the frontend across
165 // threads. 97 // threads.
166 void NotifyPrinterListAvailable( 98 void NotifyPrinterListAvailable(
167 const printing::PrinterList& printer_list); 99 const printing::PrinterList& printer_list);
168 void NotifyAuthenticated( 100 void NotifyAuthenticated(
169 const std::string& robot_oauth_refresh_token, 101 const std::string& robot_oauth_refresh_token,
170 const std::string& robot_email, 102 const std::string& robot_email,
171 const std::string& user_email); 103 const std::string& user_email);
172 void NotifyAuthenticationFailed(); 104 void NotifyAuthenticationFailed();
173 void NotifyPrintSystemUnavailable(); 105 void NotifyPrintSystemUnavailable();
174 106
175 // Once we have robot credentials, this method gets the ball rolling. 107 // Init XMPP channel
176 void PostAuthInitialization(); 108 void InitNotifications(const std::string& robot_email,
177 // Starts a new printer registration process. 109 const std::string& access_token);
178 void StartRegistration();
179 // Ends the printer registration process.
180 void EndRegistration();
181 // Registers printer capabilities and defaults for the next printer in the
182 // list with the cloud print server.
183 void RegisterNextPrinter();
184 // Retrieves the list of registered printers for this user/proxy combination
185 // from the cloud print server.
186 void GetRegisteredPrinters();
187 // Removes the given printer from the list. Returns false if the printer
188 // did not exist in the list.
189 bool RemovePrinterFromList(const std::string& printer_name);
190 // Initializes a job handler object for the specified printer. The job
191 // handler is responsible for checking for pending print jobs for this
192 // printer and print them.
193 void InitJobHandlerForPrinter(DictionaryValue* printer_data);
194 // Reports a diagnostic message to the server.
195 void ReportUserMessage(const std::string& message_id,
196 const std::string& failure_message,
197 ResponseHandler handler);
198 // Make a GAIA request to refresh the access token.
199 void RefreshAccessToken();
200
201 // Callback method for GetPrinterCapsAndDefaults.
202 void OnReceivePrinterCaps(
203 bool succeeded,
204 const std::string& printer_name,
205 const printing::PrinterCapsAndDefaults& caps_and_defaults);
206 110
207 void HandlePrinterNotification(const std::string& printer_id); 111 void HandlePrinterNotification(const std::string& printer_id);
208 void PollForJobs(); 112 void PollForJobs();
209 // Schedules a task to poll for jobs. Does nothing if a task is already 113 // Schedules a task to poll for jobs. Does nothing if a task is already
210 // scheduled. 114 // scheduled.
211 void ScheduleJobPoll(); 115 void ScheduleJobPoll();
212 CloudPrintTokenStore* GetTokenStore(); 116 CloudPrintTokenStore* GetTokenStore();
213 117
214 // Our parent CloudPrintProxyBackend 118 // Our parent CloudPrintProxyBackend
215 CloudPrintProxyBackend* backend_; 119 CloudPrintProxyBackend* backend_;
216 120
121 // Cloud Print authenticator.
122 scoped_refptr<CloudPrintAuth> auth_;
123
124 // Cloud Print connector.
125 scoped_refptr<CloudPrintConnector> connector_;
126
127 // Server URL.
217 GURL cloud_print_server_url_; 128 GURL cloud_print_server_url_;
218 gaia::OAuthClientInfo oauth_client_info_; 129 // Proxy Id.
219 scoped_ptr<DictionaryValue> print_system_settings_;
220 // Pointer to current print system.
221 scoped_refptr<cloud_print::PrintSystem> print_system_;
222 // The list of printers to be registered with the cloud print server.
223 // To begin with,this list is initialized with the list of local and network
224 // printers available. Then we query the server for the list of printers
225 // already registered. We trim this list to remove the printers already
226 // registered. We then pass a copy of this list to the frontend to give the
227 // user a chance to further trim the list. When the frontend gives us the
228 // final list we make a copy into this so that we can start registering.
229 printing::PrinterList printer_list_;
230 // Indicates whether the printers in printer_list_ is the complete set of
231 // printers to be registered for this proxy.
232 bool complete_list_available_;
233 // The CloudPrintURLFetcher instance for the current request.
234 scoped_refptr<CloudPrintURLFetcher> request_;
235 // The index of the nex printer to be uploaded.
236 size_t next_upload_index_;
237 // The unique id for this proxy
238 std::string proxy_id_; 130 std::string proxy_id_;
239 // The OAuth2 refresh token for the robot.
240 std::string refresh_token_;
241 // The email address of the user. This is only used during initial
242 // authentication with an LSID. This is only used for storing in prefs for
243 // display purposes.
244 std::string user_email_;
245 // The email address of the robot account.
246 std::string robot_email_;
247 // Cached info about the last printer that we tried to upload. We cache this
248 // so we won't have to requery the printer if the upload fails and we need
249 // to retry.
250 std::string last_uploaded_printer_name_;
251 printing::PrinterCapsAndDefaults last_uploaded_printer_info_;
252 // A map of printer id to job handler.
253 typedef std::map<std::string, scoped_refptr<PrinterJobHandler> >
254 JobHandlerMap;
255 JobHandlerMap job_handler_map_;
256 ResponseHandler next_response_handler_;
257 scoped_refptr<cloud_print::PrintSystem::PrintServerWatcher>
258 print_server_watcher_;
259 bool new_printers_available_;
260 bool registration_in_progress_;
261 // Notification (xmpp) handler. 131 // Notification (xmpp) handler.
262 scoped_ptr<notifier::TalkMediator> talk_mediator_; 132 scoped_ptr<notifier::TalkMediator> talk_mediator_;
263 // Indicates whether XMPP notifications are currently enabled. 133 // Indicates whether XMPP notifications are currently enabled.
264 bool notifications_enabled_; 134 bool notifications_enabled_;
265 // The time when notifications were enabled. Valid only when 135 // The time when notifications were enabled. Valid only when
266 // notifications_enabled_ is true. 136 // notifications_enabled_ is true.
267 base::TimeTicks notifications_enabled_since_; 137 base::TimeTicks notifications_enabled_since_;
268 // Indicates whether a task to poll for jobs has been scheduled. 138 // Indicates whether a task to poll for jobs has been scheduled.
269 bool job_poll_scheduled_; 139 bool job_poll_scheduled_;
270 // Indicates whether we should poll for jobs when we lose XMPP connection. 140 // Indicates whether we should poll for jobs when we lose XMPP connection.
271 bool enable_job_poll_; 141 bool enable_job_poll_;
272 scoped_ptr<gaia::GaiaOAuthClient> oauth_client_;
273 scoped_ptr<CloudPrintTokenStore> token_store_; 142 scoped_ptr<CloudPrintTokenStore> token_store_;
274 143
275 DISALLOW_COPY_AND_ASSIGN(Core); 144 DISALLOW_COPY_AND_ASSIGN(Core);
276 }; 145 };
277 146
278 CloudPrintProxyBackend::CloudPrintProxyBackend( 147 CloudPrintProxyBackend::CloudPrintProxyBackend(
279 CloudPrintProxyFrontend* frontend, 148 CloudPrintProxyFrontend* frontend,
149 const std::string& proxy_id,
280 const GURL& cloud_print_server_url, 150 const GURL& cloud_print_server_url,
281 const DictionaryValue* print_system_settings, 151 const DictionaryValue* print_system_settings,
282 const gaia::OAuthClientInfo& oauth_client_info, 152 const gaia::OAuthClientInfo& oauth_client_info,
283 bool enable_job_poll) 153 bool enable_job_poll)
284 : core_thread_("Chrome_CloudPrintProxyCoreThread"), 154 : core_thread_("Chrome_CloudPrintProxyCoreThread"),
285 frontend_loop_(MessageLoop::current()), 155 frontend_loop_(MessageLoop::current()),
286 frontend_(frontend) { 156 frontend_(frontend) {
287 DCHECK(frontend_); 157 DCHECK(frontend_);
288 core_ = new Core(this, 158 core_ = new Core(this,
159 proxy_id,
289 cloud_print_server_url, 160 cloud_print_server_url,
290 print_system_settings, 161 print_system_settings,
291 oauth_client_info, 162 oauth_client_info,
292 enable_job_poll); 163 enable_job_poll);
293 } 164 }
294 165
295 CloudPrintProxyBackend::~CloudPrintProxyBackend() { 166 CloudPrintProxyBackend::~CloudPrintProxyBackend() {
296 DCHECK(!core_); 167 DCHECK(!core_);
297 } 168 }
298 169
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
372 const printing::PrinterList& printer_list) { 243 const printing::PrinterList& printer_list) {
373 core_thread_.message_loop()->PostTask(FROM_HERE, 244 core_thread_.message_loop()->PostTask(FROM_HERE,
374 NewRunnableMethod( 245 NewRunnableMethod(
375 core_.get(), 246 core_.get(),
376 &CloudPrintProxyBackend::Core::DoRegisterSelectedPrinters, 247 &CloudPrintProxyBackend::Core::DoRegisterSelectedPrinters,
377 printer_list)); 248 printer_list));
378 } 249 }
379 250
380 CloudPrintProxyBackend::Core::Core( 251 CloudPrintProxyBackend::Core::Core(
381 CloudPrintProxyBackend* backend, 252 CloudPrintProxyBackend* backend,
253 const std::string& proxy_id,
382 const GURL& cloud_print_server_url, 254 const GURL& cloud_print_server_url,
383 const DictionaryValue* print_system_settings, 255 const DictionaryValue* print_system_settings,
384 const gaia::OAuthClientInfo& oauth_client_info, 256 const gaia::OAuthClientInfo& oauth_client_info,
385 bool enable_job_poll) 257 bool enable_job_poll)
386 : backend_(backend), 258 : backend_(backend),
387 cloud_print_server_url_(cloud_print_server_url), 259 cloud_print_server_url_(cloud_print_server_url),
388 oauth_client_info_(oauth_client_info), 260 proxy_id_(proxy_id),
389 complete_list_available_(false),
390 next_upload_index_(0),
391 next_response_handler_(NULL),
392 new_printers_available_(false),
393 registration_in_progress_(false),
394 notifications_enabled_(false),
395 job_poll_scheduled_(false), 261 job_poll_scheduled_(false),
396 enable_job_poll_(enable_job_poll) { 262 enable_job_poll_(enable_job_poll) {
397 if (print_system_settings) { 263 auth_ = new CloudPrintAuth(this,
398 // It is possible to have no print settings specified. 264 cloud_print_server_url,
399 print_system_settings_.reset(print_system_settings->DeepCopy()); 265 print_system_settings,
400 } 266 oauth_client_info,
267 proxy_id);
268 connector_ = new CloudPrintConnector(this,
269 proxy_id,
270 cloud_print_server_url,
271 print_system_settings);
401 } 272 }
402 273
403 void CloudPrintProxyBackend::Core::DoInitializeWithLsid( 274 void CloudPrintProxyBackend::Core::DoInitializeWithLsid(
404 const std::string& lsid, 275 const std::string& lsid,
405 const std::string& proxy_id, 276 const std::string& proxy_id,
406 const std::string& last_robot_refresh_token, 277 const std::string& last_robot_refresh_token,
407 const std::string& last_robot_email, 278 const std::string& last_robot_email,
408 const std::string& last_user_email) { 279 const std::string& last_user_email) {
409 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); 280 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
410 // Note: The GAIA login is synchronous but that should be OK because we are in 281 // Note: The GAIA login is synchronous but that should be OK because we are in
411 // the CloudPrintProxyCoreThread and we cannot really do anything else until 282 // the CloudPrintProxyCoreThread and we cannot really do anything else until
412 // the GAIA signin is successful. 283 // the GAIA signin is successful.
413 std::string user_agent = "ChromiumBrowser"; 284 auth_->AuthenticateWithLsid(lsid, last_robot_refresh_token,
414 scoped_refptr<ServiceGaiaAuthenticator> gaia_auth_for_print( 285 last_robot_email, last_user_email);
415 new ServiceGaiaAuthenticator(
416 user_agent, kCloudPrintGaiaServiceId,
417 GaiaUrls::GetInstance()->client_login_url(),
418 g_service_process->io_thread()->message_loop_proxy()));
419 gaia_auth_for_print->set_message_loop(MessageLoop::current());
420 if (gaia_auth_for_print->AuthenticateWithLsid(lsid)) {
421 // Stash away the user email so we can save it in prefs.
422 user_email_ = gaia_auth_for_print->email();
423 // If the same user is re-enabling Cloud Print and we have stashed robot
424 // credentials, we will use those.
425 if ((0 == base::strcasecmp(user_email_.c_str(), last_user_email.c_str())) &&
426 !last_robot_refresh_token.empty() &&
427 !last_robot_email.empty()) {
428 DoInitializeWithRobotToken(last_robot_refresh_token,
429 last_robot_email,
430 proxy_id);
431 }
432 DoInitializeWithToken(gaia_auth_for_print->auth_token(),
433 proxy_id);
434 } else {
435 // Let the frontend know the of authentication failure.
436 OnAuthError();
437 }
438 } 286 }
439 287
440 void CloudPrintProxyBackend::Core::DoInitializeWithToken( 288 void CloudPrintProxyBackend::Core::DoInitializeWithToken(
441 const std::string cloud_print_token, 289 const std::string cloud_print_token,
442 const std::string& proxy_id) { 290 const std::string& proxy_id) {
443 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); 291 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
444 VLOG(1) << "CP_PROXY: Starting proxy, id: " << proxy_id; 292 auth_->AuthenticateWithToken(cloud_print_token);
445 proxy_id_ = proxy_id;
446 GetTokenStore()->SetToken(cloud_print_token, false);
447
448 // We need to get the credentials of the robot here.
449 GURL get_authcode_url =
450 CloudPrintHelpers::GetUrlForGetAuthCode(cloud_print_server_url_,
451 oauth_client_info_.client_id,
452 proxy_id_);
453 next_response_handler_ =
454 &CloudPrintProxyBackend::Core::HandleGetAuthCodeResponse;
455 request_ = new CloudPrintURLFetcher;
456 request_->StartGetRequest(get_authcode_url,
457 this,
458 kCloudPrintAPIMaxRetryCount,
459 std::string());
460 } 293 }
461 294
462 void CloudPrintProxyBackend::Core::DoInitializeWithRobotToken( 295 void CloudPrintProxyBackend::Core::DoInitializeWithRobotToken(
463 const std::string& robot_oauth_refresh_token, 296 const std::string& robot_oauth_refresh_token,
464 const std::string& robot_email, 297 const std::string& robot_email,
465 const std::string& proxy_id) { 298 const std::string& proxy_id) {
466 robot_email_ = robot_email; 299 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
467 proxy_id_ = proxy_id; 300 auth_->AuthenticateWithRobotToken(robot_oauth_refresh_token, robot_email);
468 refresh_token_ = robot_oauth_refresh_token;
469 RefreshAccessToken();
470 } 301 }
471 302
472 void CloudPrintProxyBackend::Core::DoInitializeWithRobotAuthCode( 303 void CloudPrintProxyBackend::Core::DoInitializeWithRobotAuthCode(
473 const std::string& robot_oauth_auth_code, 304 const std::string& robot_oauth_auth_code,
474 const std::string& robot_email, 305 const std::string& robot_email,
475 const std::string& proxy_id) { 306 const std::string& proxy_id) {
476 robot_email_ = robot_email; 307 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
477 proxy_id_ = proxy_id; 308 auth_->AuthenticateWithRobotAuthCode(robot_oauth_auth_code, robot_email);
478 // Now that we have an auth code we need to get the refresh and access tokens.
479 oauth_client_.reset(new gaia::GaiaOAuthClient(
480 gaia::kGaiaOAuth2Url,
481 g_service_process->GetServiceURLRequestContextGetter()));
482 oauth_client_->GetTokensFromAuthCode(oauth_client_info_,
483 robot_oauth_auth_code,
484 kCloudPrintAPIMaxRetryCount,
485 this);
486 } 309 }
487 310
488 void CloudPrintProxyBackend::Core::PostAuthInitialization() { 311 void CloudPrintProxyBackend::Core::OnAuthenticationComplete(
489 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); 312 const std::string& access_token,
490 // Now we can get down to registering printers. 313 const std::string& robot_oauth_refresh_token,
491 print_system_ = 314 const std::string& robot_email,
492 cloud_print::PrintSystem::CreateInstance(print_system_settings_.get()); 315 const std::string& user_email) {
493 if (!print_system_.get()) { 316 CloudPrintTokenStore* token_store = GetTokenStore();
494 NOTREACHED(); 317 bool first_time = token_store->token().empty();
495 return; // No print system available, fail initalization. 318 token_store->SetToken(access_token);
319 // Let the frontend know that we have authenticated.
320 backend_->frontend_loop_->PostTask(
321 FROM_HERE, NewRunnableMethod(this,
322 &Core::NotifyAuthenticated,
323 robot_oauth_refresh_token,
324 robot_email,
325 user_email));
326 if (first_time) {
327 InitNotifications(robot_email, access_token);
328 } else {
329 // If we are refreshing a token, update the XMPP token too.
330 DCHECK(talk_mediator_.get());
331 talk_mediator_->SetAuthToken(robot_email,
332 access_token,
333 kSyncGaiaServiceId);
496 } 334 }
497 cloud_print::PrintSystem::PrintSystemResult result = print_system_->Init(); 335 // Start cloud print connector if needed.
498 336 if (!connector_->IsRunning()) {
499 if (result.succeeded()) { 337 if (!connector_->Start()) {
500 notifier::NotifierOptions notifier_options; 338 // Let the frontend know that we do not have a print system.
501 notifier_options.request_context_getter = 339 backend_->frontend_loop_->PostTask(
502 g_service_process->GetServiceURLRequestContextGetter(); 340 FROM_HERE,
503 notifier_options.auth_mechanism = "X-OAUTH2"; 341 NewRunnableMethod(this,
504 talk_mediator_.reset(new notifier::TalkMediatorImpl( 342 &Core::NotifyPrintSystemUnavailable));
505 new notifier::MediatorThreadImpl(notifier_options), 343 }
506 notifier_options));
507 notifier::Subscription subscription;
508 subscription.channel = kCloudPrintPushNotificationsSource;
509 subscription.from = kCloudPrintPushNotificationsSource;
510 talk_mediator_->AddSubscription(subscription);
511 talk_mediator_->SetDelegate(this);
512 talk_mediator_->SetAuthToken(
513 robot_email_,
514 CloudPrintTokenStore::current()->token(),
515 kSyncGaiaServiceId);
516 talk_mediator_->Login();
517
518 print_server_watcher_ = print_system_->CreatePrintServerWatcher();
519 print_server_watcher_->StartWatching(this);
520
521 StartRegistration();
522 } else {
523 // We could not initialize the print system. We need to notify the server.
524 ReportUserMessage(
525 kPrintSystemFailedMessageId,
526 result.message(),
527 &CloudPrintProxyBackend::Core::HandlePrintSystemUnavailableResponse);
528 } 344 }
529 } 345 }
530 346
531 void CloudPrintProxyBackend::Core::StartRegistration() { 347 void CloudPrintProxyBackend::Core::OnInvalidCredentials() {
532 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); 348 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
533 printer_list_.clear(); 349 VLOG(1) << "CP_CONNECTOR: Auth Error";
534 cloud_print::PrintSystem::PrintSystemResult result = 350 backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
535 print_system_->EnumeratePrinters(&printer_list_); 351 &Core::NotifyAuthenticationFailed));
536 complete_list_available_ = result.succeeded();
537 registration_in_progress_ = true;
538 if (!result.succeeded()) {
539 std::string message = result.message();
540 if (message.empty())
541 message = l10n_util::GetStringUTF8(IDS_CLOUD_PRINT_ENUM_FAILED);
542 // There was a failure enumerating printers. Send a message to the server.
543 ReportUserMessage(
544 kEnumPrintersFailedMessageId,
545 message,
546 &CloudPrintProxyBackend::Core::HandleEnumPrintersFailedResponse);
547 } else {
548 // Now we need to ask the server about printers that were registered on the
549 // server so that we can trim this list.
550 GetRegisteredPrinters();
551 }
552 } 352 }
553 353
554 void CloudPrintProxyBackend::Core::EndRegistration() { 354 void CloudPrintProxyBackend::Core::OnPrintersAvailable(
355 const printing::PrinterList& printers) {
356 // Let the frontend know that we have a list of printers available.
357 backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
358 &Core::NotifyPrinterListAvailable, printers));
359 }
360
361 void CloudPrintProxyBackend::Core::OnAuthFailed() {
362 VLOG(1) << "CP_CONNECTOR: Authentication failed in connector.";
363 // Let's stop connecter and refresh token. We'll restart connecter once
364 // new token available.
365 if (connector_->IsRunning())
366 connector_->Stop();
367
368 // Refresh Auth token.
369 auth_->RefreshAccessToken();
370 }
371
372 void CloudPrintProxyBackend::Core::InitNotifications(
373 const std::string& robot_email,
374 const std::string& access_token) {
555 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); 375 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
556 request_ = NULL; 376
557 registration_in_progress_ = false; 377 notifier::NotifierOptions notifier_options;
558 if (new_printers_available_) { 378 notifier_options.request_context_getter =
559 new_printers_available_ = false; 379 g_service_process->GetServiceURLRequestContextGetter();
560 StartRegistration(); 380 notifier_options.auth_mechanism = "X-OAUTH2";
561 } 381 talk_mediator_.reset(new notifier::TalkMediatorImpl(
382 new notifier::MediatorThreadImpl(notifier_options),
383 notifier_options));
384 notifier::Subscription subscription;
385 subscription.channel = kCloudPrintPushNotificationsSource;
386 subscription.from = kCloudPrintPushNotificationsSource;
387 talk_mediator_->AddSubscription(subscription);
388 talk_mediator_->SetDelegate(this);
389 talk_mediator_->SetAuthToken(robot_email, access_token, kSyncGaiaServiceId);
390 talk_mediator_->Login();
562 } 391 }
563 392
564 void CloudPrintProxyBackend::Core::DoShutdown() { 393 void CloudPrintProxyBackend::Core::DoShutdown() {
565 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); 394 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
566 VLOG(1) << "CP_PROXY: Shutdown proxy, id: " << proxy_id_; 395 VLOG(1) << "CP_CONNECTOR: Shutdown connector, id: " << proxy_id_;
567 if (print_server_watcher_ != NULL)
568 print_server_watcher_->StopWatching();
569 396
570 // Need to kill all running jobs. 397 if (connector_->IsRunning())
571 while (!job_handler_map_.empty()) { 398 connector_->Stop();
572 JobHandlerMap::iterator index = job_handler_map_.begin(); 399
573 // Shutdown will call our OnPrinterJobHandlerShutdown method which will
574 // remove this from the map.
575 index->second->Shutdown();
576 }
577 // Important to delete the TalkMediator on this thread. 400 // Important to delete the TalkMediator on this thread.
578 if (talk_mediator_.get()) 401 if (talk_mediator_.get())
579 talk_mediator_->Logout(); 402 talk_mediator_->Logout();
580 talk_mediator_.reset(); 403 talk_mediator_.reset();
581 notifications_enabled_ = false; 404 notifications_enabled_ = false;
582 notifications_enabled_since_ = base::TimeTicks(); 405 notifications_enabled_since_ = base::TimeTicks();
583 request_ = NULL;
584 token_store_.reset(); 406 token_store_.reset();
585 } 407 }
586 408
587 void CloudPrintProxyBackend::Core::DoRegisterSelectedPrinters( 409 void CloudPrintProxyBackend::Core::DoRegisterSelectedPrinters(
588 const printing::PrinterList& printer_list) { 410 const printing::PrinterList& printer_list) {
589 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); 411 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
590 if (!print_system_.get()) 412 connector_->RegisterPrinters(printer_list);
591 return; // No print system available.
592 printer_list_.assign(printer_list.begin(), printer_list.end());
593 next_upload_index_ = 0;
594 RegisterNextPrinter();
595 }
596
597 void CloudPrintProxyBackend::Core::GetRegisteredPrinters() {
598 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
599 GURL printer_list_url =
600 CloudPrintHelpers::GetUrlForPrinterList(cloud_print_server_url_,
601 proxy_id_);
602 next_response_handler_ =
603 &CloudPrintProxyBackend::Core::HandlePrinterListResponse;
604 request_ = new CloudPrintURLFetcher;
605 request_->StartGetRequest(printer_list_url,
606 this,
607 kCloudPrintAPIMaxRetryCount,
608 std::string());
609 }
610
611 void CloudPrintProxyBackend::Core::RegisterNextPrinter() {
612 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
613 // For the next printer to be uploaded, create a multi-part post request to
614 // upload the printer capabilities and the printer defaults.
615 if (next_upload_index_ < printer_list_.size()) {
616 const printing::PrinterBasicInfo& info =
617 printer_list_.at(next_upload_index_);
618 // If we are retrying a previous upload, we don't need to fetch the caps
619 // and defaults again.
620 if (info.printer_name != last_uploaded_printer_name_) {
621 cloud_print::PrintSystem::PrinterCapsAndDefaultsCallback* callback =
622 NewCallback(this,
623 &CloudPrintProxyBackend::Core::OnReceivePrinterCaps);
624 // Asnchronously fetch the printer caps and defaults. The story will
625 // continue in OnReceivePrinterCaps.
626 print_system_->GetPrinterCapsAndDefaults(
627 info.printer_name.c_str(), callback);
628 } else {
629 OnReceivePrinterCaps(true,
630 last_uploaded_printer_name_,
631 last_uploaded_printer_info_);
632 }
633 } else {
634 EndRegistration();
635 }
636 }
637
638 void CloudPrintProxyBackend::Core::OnReceivePrinterCaps(
639 bool succeeded,
640 const std::string& printer_name,
641 const printing::PrinterCapsAndDefaults& caps_and_defaults) {
642 DCHECK(next_upload_index_ < printer_list_.size());
643 if (succeeded) {
644 const printing::PrinterBasicInfo& info =
645 printer_list_.at(next_upload_index_);
646
647 last_uploaded_printer_name_ = info.printer_name;
648 last_uploaded_printer_info_ = caps_and_defaults;
649
650 std::string mime_boundary;
651 CloudPrintHelpers::CreateMimeBoundaryForUpload(&mime_boundary);
652 std::string post_data;
653
654 CloudPrintHelpers::AddMultipartValueForUpload(kProxyIdValue, proxy_id_,
655 mime_boundary,
656 std::string(), &post_data);
657 CloudPrintHelpers::AddMultipartValueForUpload(kPrinterNameValue,
658 info.printer_name,
659 mime_boundary,
660 std::string(), &post_data);
661 CloudPrintHelpers::AddMultipartValueForUpload(kPrinterDescValue,
662 info.printer_description,
663 mime_boundary,
664 std::string() , &post_data);
665 CloudPrintHelpers::AddMultipartValueForUpload(
666 kPrinterStatusValue, base::StringPrintf("%d", info.printer_status),
667 mime_boundary, std::string(), &post_data);
668 // Add printer options as tags.
669 CloudPrintHelpers::GenerateMultipartPostDataForPrinterTags(info.options,
670 mime_boundary,
671 &post_data);
672
673 CloudPrintHelpers::AddMultipartValueForUpload(
674 kPrinterCapsValue, last_uploaded_printer_info_.printer_capabilities,
675 mime_boundary, last_uploaded_printer_info_.caps_mime_type,
676 &post_data);
677 CloudPrintHelpers::AddMultipartValueForUpload(
678 kPrinterDefaultsValue, last_uploaded_printer_info_.printer_defaults,
679 mime_boundary, last_uploaded_printer_info_.defaults_mime_type,
680 &post_data);
681 // Send a hash of the printer capabilities to the server. We will use this
682 // later to check if the capabilities have changed
683 CloudPrintHelpers::AddMultipartValueForUpload(
684 kPrinterCapsHashValue,
685 base::MD5String(last_uploaded_printer_info_.printer_capabilities),
686 mime_boundary, std::string(), &post_data);
687 GURL post_url = CloudPrintHelpers::GetUrlForPrinterRegistration(
688 cloud_print_server_url_);
689
690 next_response_handler_ =
691 &CloudPrintProxyBackend::Core::HandleRegisterPrinterResponse;
692 // Terminate the request body
693 post_data.append("--" + mime_boundary + "--\r\n");
694 std::string mime_type("multipart/form-data; boundary=");
695 mime_type += mime_boundary;
696 request_ = new CloudPrintURLFetcher;
697 request_->StartPostRequest(post_url,
698 this,
699 kCloudPrintAPIMaxRetryCount,
700 mime_type,
701 post_data,
702 std::string());
703 } else {
704 LOG(ERROR) << "CP_PROXY: Failed to get printer info for: " <<
705 printer_name;
706 // This printer failed to register, notify the server of this failure.
707 string16 printer_name_utf16 = UTF8ToUTF16(printer_name);
708 std::string status_message = l10n_util::GetStringFUTF8(
709 IDS_CLOUD_PRINT_REGISTER_PRINTER_FAILED,
710 printer_name_utf16);
711 ReportUserMessage(
712 kGetPrinterCapsFailedMessageId,
713 status_message,
714 &CloudPrintProxyBackend::Core::HandleRegisterFailedStatusResponse);
715 }
716 } 413 }
717 414
718 void CloudPrintProxyBackend::Core::HandlePrinterNotification( 415 void CloudPrintProxyBackend::Core::HandlePrinterNotification(
719 const std::string& printer_id) { 416 const std::string& printer_id) {
720 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); 417 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
721 VLOG(1) << "CP_PROXY: Handle printer notification, id: " << printer_id; 418 VLOG(1) << "CP_CONNECTOR: Handle printer notification, id: " << printer_id;
722 JobHandlerMap::iterator index = job_handler_map_.find(printer_id); 419 connector_->CheckForJobs(kJobFetchReasonNotified, printer_id);
723 if (index != job_handler_map_.end())
724 index->second->CheckForJobs(kJobFetchReasonNotified);
725 } 420 }
726 421
727 void CloudPrintProxyBackend::Core::PollForJobs() { 422 void CloudPrintProxyBackend::Core::PollForJobs() {
728 VLOG(1) << "CP_PROXY: Polling for jobs."; 423 VLOG(1) << "CP_CONNECTOR: Polling for jobs.";
729 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); 424 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
730 for (JobHandlerMap::iterator index = job_handler_map_.begin(); 425 // Check all printers for jobs.
731 index != job_handler_map_.end(); index++) { 426 connector_->CheckForJobs(kJobFetchReasonPoll, std::string());
732 // If notifications are on, then we should poll for this printer only if 427
733 // the last time it fetched jobs was before notifications were last enabled.
734 bool should_poll =
735 !notifications_enabled_ ||
736 (index->second->last_job_fetch_time() <= notifications_enabled_since_);
737 if (should_poll)
738 index->second->CheckForJobs(kJobFetchReasonPoll);
739 }
740 job_poll_scheduled_ = false; 428 job_poll_scheduled_ = false;
741 // If we don't have notifications and job polling is enabled, poll again 429 // If we don't have notifications and job polling is enabled, poll again
742 // after a while. 430 // after a while.
743 if (!notifications_enabled_ && enable_job_poll_) 431 if (!notifications_enabled_ && enable_job_poll_)
744 ScheduleJobPoll(); 432 ScheduleJobPoll();
745 } 433 }
746 434
747 void CloudPrintProxyBackend::Core::ScheduleJobPoll() { 435 void CloudPrintProxyBackend::Core::ScheduleJobPoll() {
748 if (!job_poll_scheduled_) { 436 if (!job_poll_scheduled_) {
749 int interval_in_seconds = base::RandInt(kMinJobPollIntervalSecs, 437 int interval_in_seconds = base::RandInt(kMinJobPollIntervalSecs,
750 kMaxJobPollIntervalSecs); 438 kMaxJobPollIntervalSecs);
751 MessageLoop::current()->PostDelayedTask( 439 MessageLoop::current()->PostDelayedTask(
752 FROM_HERE, 440 FROM_HERE,
753 NewRunnableMethod(this, &CloudPrintProxyBackend::Core::PollForJobs), 441 NewRunnableMethod(this, &CloudPrintProxyBackend::Core::PollForJobs),
754 interval_in_seconds * 1000); 442 interval_in_seconds * 1000);
755 job_poll_scheduled_ = true; 443 job_poll_scheduled_ = true;
756 } 444 }
757 } 445 }
758 446
759 CloudPrintTokenStore* CloudPrintProxyBackend::Core::GetTokenStore() { 447 CloudPrintTokenStore* CloudPrintProxyBackend::Core::GetTokenStore() {
760 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); 448 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
761 if (!token_store_.get()) 449 if (!token_store_.get())
762 token_store_.reset(new CloudPrintTokenStore); 450 token_store_.reset(new CloudPrintTokenStore);
763 return token_store_.get(); 451 return token_store_.get();
764 } 452 }
765 453
766 // CloudPrintURLFetcher::Delegate implementation.
767 CloudPrintURLFetcher::ResponseAction
768 CloudPrintProxyBackend::Core::HandleJSONData(
769 const content::URLFetcher* source,
770 const GURL& url,
771 DictionaryValue* json_data,
772 bool succeeded) {
773 DCHECK(next_response_handler_);
774 return (this->*next_response_handler_)(source, url, json_data, succeeded);
775 }
776
777 void CloudPrintProxyBackend::Core::OnRequestAuthError() {
778 OnAuthError();
779 }
780
781 void CloudPrintProxyBackend::Core::NotifyPrinterListAvailable( 454 void CloudPrintProxyBackend::Core::NotifyPrinterListAvailable(
782 const printing::PrinterList& printer_list) { 455 const printing::PrinterList& printer_list) {
783 DCHECK(MessageLoop::current() == backend_->frontend_loop_); 456 DCHECK(MessageLoop::current() == backend_->frontend_loop_);
784 backend_->frontend_->OnPrinterListAvailable(printer_list); 457 backend_->frontend_->OnPrinterListAvailable(printer_list);
785 } 458 }
786 459
787 void CloudPrintProxyBackend::Core::NotifyAuthenticated( 460 void CloudPrintProxyBackend::Core::NotifyAuthenticated(
788 const std::string& robot_oauth_refresh_token, 461 const std::string& robot_oauth_refresh_token,
789 const std::string& robot_email, 462 const std::string& robot_email,
790 const std::string& user_email) { 463 const std::string& user_email) {
791 DCHECK(MessageLoop::current() == backend_->frontend_loop_); 464 DCHECK(MessageLoop::current() == backend_->frontend_loop_);
792 backend_->frontend_->OnAuthenticated(robot_oauth_refresh_token, 465 backend_->frontend_->OnAuthenticated(robot_oauth_refresh_token,
793 robot_email, 466 robot_email,
794 user_email); 467 user_email);
795 } 468 }
796 469
797 void CloudPrintProxyBackend::Core::NotifyAuthenticationFailed() { 470 void CloudPrintProxyBackend::Core::NotifyAuthenticationFailed() {
798 DCHECK(MessageLoop::current() == backend_->frontend_loop_); 471 DCHECK(MessageLoop::current() == backend_->frontend_loop_);
799 backend_->frontend_->OnAuthenticationFailed(); 472 backend_->frontend_->OnAuthenticationFailed();
800 } 473 }
801 474
802 void CloudPrintProxyBackend::Core::NotifyPrintSystemUnavailable() { 475 void CloudPrintProxyBackend::Core::NotifyPrintSystemUnavailable() {
803 DCHECK(MessageLoop::current() == backend_->frontend_loop_); 476 DCHECK(MessageLoop::current() == backend_->frontend_loop_);
804 backend_->frontend_->OnPrintSystemUnavailable(); 477 backend_->frontend_->OnPrintSystemUnavailable();
805 } 478 }
806 479
807 CloudPrintURLFetcher::ResponseAction
808 CloudPrintProxyBackend::Core::HandleGetAuthCodeResponse(
809 const content::URLFetcher* source,
810 const GURL& url,
811 DictionaryValue* json_data,
812 bool succeeded) {
813 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
814 if (!succeeded) {
815 OnAuthError();
816 return CloudPrintURLFetcher::STOP_PROCESSING;
817 }
818 std::string auth_code;
819 if (!json_data->GetString(kOAuthCodeValue, &auth_code)) {
820 OnAuthError();
821 return CloudPrintURLFetcher::STOP_PROCESSING;
822 }
823 json_data->GetString(kXMPPJidValue, &robot_email_);
824 // Now that we have an auth code we need to get the refresh and access tokens.
825 oauth_client_.reset(new gaia::GaiaOAuthClient(
826 gaia::kGaiaOAuth2Url,
827 g_service_process->GetServiceURLRequestContextGetter()));
828 oauth_client_->GetTokensFromAuthCode(oauth_client_info_,
829 auth_code,
830 kCloudPrintAPIMaxRetryCount,
831 this);
832
833 return CloudPrintURLFetcher::STOP_PROCESSING;
834 }
835
836 CloudPrintURLFetcher::ResponseAction
837 CloudPrintProxyBackend::Core::HandlePrinterListResponse(
838 const content::URLFetcher* source,
839 const GURL& url,
840 DictionaryValue* json_data,
841 bool succeeded) {
842 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
843 if (!succeeded) {
844 NOTREACHED();
845 return CloudPrintURLFetcher::RETRY_REQUEST;
846 }
847 ListValue* printer_list = NULL;
848 // There may be no "printers" value in the JSON
849 if (json_data->GetList(kPrinterListValue, &printer_list) && printer_list) {
850 for (size_t index = 0; index < printer_list->GetSize(); index++) {
851 DictionaryValue* printer_data = NULL;
852 if (printer_list->GetDictionary(index, &printer_data)) {
853 std::string printer_name;
854 printer_data->GetString(kNameValue, &printer_name);
855 RemovePrinterFromList(printer_name);
856 InitJobHandlerForPrinter(printer_data);
857 } else {
858 NOTREACHED();
859 }
860 }
861 }
862 request_ = NULL;
863 if (!printer_list_.empty()) {
864 // Let the frontend know that we have a list of printers available.
865 backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
866 &Core::NotifyPrinterListAvailable, printer_list_));
867 } else {
868 // No more work to be done here.
869 MessageLoop::current()->PostTask(
870 FROM_HERE, NewRunnableMethod(this, &Core::EndRegistration));
871 }
872 return CloudPrintURLFetcher::STOP_PROCESSING;
873 }
874
875 void CloudPrintProxyBackend::Core::InitJobHandlerForPrinter(
876 DictionaryValue* printer_data) {
877 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
878 DCHECK(printer_data);
879 PrinterJobHandler::PrinterInfoFromCloud printer_info_cloud;
880 printer_data->GetString(kIdValue, &printer_info_cloud.printer_id);
881 DCHECK(!printer_info_cloud.printer_id.empty());
882 VLOG(1) << "CP_PROXY: Init job handler for printer id: "
883 << printer_info_cloud.printer_id;
884 JobHandlerMap::iterator index = job_handler_map_.find(
885 printer_info_cloud.printer_id);
886 // We might already have a job handler for this printer
887 if (index == job_handler_map_.end()) {
888 printing::PrinterBasicInfo printer_info;
889 printer_data->GetString(kNameValue, &printer_info.printer_name);
890 DCHECK(!printer_info.printer_name.empty());
891 printer_data->GetString(kPrinterDescValue,
892 &printer_info.printer_description);
893 // Printer status is a string value which actually contains an integer.
894 std::string printer_status;
895 if (printer_data->GetString(kPrinterStatusValue, &printer_status)) {
896 base::StringToInt(printer_status, &printer_info.printer_status);
897 }
898 printer_data->GetString(kPrinterCapsHashValue,
899 &printer_info_cloud.caps_hash);
900 ListValue* tags_list = NULL;
901 if (printer_data->GetList(kTagsValue, &tags_list) && tags_list) {
902 for (size_t index = 0; index < tags_list->GetSize(); index++) {
903 std::string tag;
904 if (tags_list->GetString(index, &tag) &&
905 StartsWithASCII(tag, kTagsHashTagName, false)) {
906 std::vector<std::string> tag_parts;
907 base::SplitStringDontTrim(tag, '=', &tag_parts);
908 DCHECK_EQ(tag_parts.size(), 2U);
909 if (tag_parts.size() == 2)
910 printer_info_cloud.tags_hash = tag_parts[1];
911 }
912 }
913 }
914 scoped_refptr<PrinterJobHandler> job_handler;
915 job_handler = new PrinterJobHandler(printer_info,
916 printer_info_cloud,
917 cloud_print_server_url_,
918 print_system_.get(),
919 this);
920 job_handler_map_[printer_info_cloud.printer_id] = job_handler;
921 job_handler->Initialize();
922 }
923 }
924
925 void CloudPrintProxyBackend::Core::ReportUserMessage(
926 const std::string& message_id,
927 const std::string& failure_message,
928 ResponseHandler handler) {
929 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
930 std::string mime_boundary;
931 CloudPrintHelpers::CreateMimeBoundaryForUpload(&mime_boundary);
932 GURL post_url = CloudPrintHelpers::GetUrlForUserMessage(
933 cloud_print_server_url_,
934 message_id);
935 std::string post_data;
936 CloudPrintHelpers::AddMultipartValueForUpload(kMessageTextValue,
937 failure_message,
938 mime_boundary,
939 std::string(),
940 &post_data);
941 next_response_handler_ = handler;
942 // Terminate the request body
943 post_data.append("--" + mime_boundary + "--\r\n");
944 std::string mime_type("multipart/form-data; boundary=");
945 mime_type += mime_boundary;
946 request_ = new CloudPrintURLFetcher;
947 request_->StartPostRequest(post_url,
948 this,
949 kCloudPrintAPIMaxRetryCount,
950 mime_type,
951 post_data,
952 std::string());
953 }
954
955 CloudPrintURLFetcher::ResponseAction
956 CloudPrintProxyBackend::Core::HandleRegisterPrinterResponse(
957 const content::URLFetcher* source,
958 const GURL& url,
959 DictionaryValue* json_data,
960 bool succeeded) {
961 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
962 if (succeeded) {
963 ListValue* printer_list = NULL;
964 // There should be a "printers" value in the JSON
965 if (json_data->GetList(kPrinterListValue, &printer_list)) {
966 DictionaryValue* printer_data = NULL;
967 if (printer_list->GetDictionary(0, &printer_data))
968 InitJobHandlerForPrinter(printer_data);
969 }
970 }
971 next_upload_index_++;
972 MessageLoop::current()->PostTask(
973 FROM_HERE,
974 NewRunnableMethod(this,
975 &CloudPrintProxyBackend::Core::RegisterNextPrinter));
976 return CloudPrintURLFetcher::STOP_PROCESSING;
977 }
978
979 CloudPrintURLFetcher::ResponseAction
980 CloudPrintProxyBackend::Core::HandleRegisterFailedStatusResponse(
981 const content::URLFetcher* source,
982 const GURL& url,
983 DictionaryValue* json_data,
984 bool succeeded) {
985 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
986 next_upload_index_++;
987 MessageLoop::current()->PostTask(
988 FROM_HERE,
989 NewRunnableMethod(this,
990 &CloudPrintProxyBackend::Core::RegisterNextPrinter));
991 return CloudPrintURLFetcher::STOP_PROCESSING;
992 }
993
994 CloudPrintURLFetcher::ResponseAction
995 CloudPrintProxyBackend::Core::HandlePrintSystemUnavailableResponse(
996 const content::URLFetcher* source,
997 const GURL& url,
998 DictionaryValue* json_data,
999 bool succeeded) {
1000 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
1001 // Let the frontend know that we do not have a print system.
1002 backend_->frontend_loop_->PostTask(
1003 FROM_HERE,
1004 NewRunnableMethod(this,
1005 &Core::NotifyPrintSystemUnavailable));
1006 return CloudPrintURLFetcher::STOP_PROCESSING;
1007 }
1008
1009 CloudPrintURLFetcher::ResponseAction
1010 CloudPrintProxyBackend::Core::HandleEnumPrintersFailedResponse(
1011 const content::URLFetcher* source,
1012 const GURL& url,
1013 DictionaryValue* json_data,
1014 bool succeeded) {
1015 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
1016 // Now proceed with printer registration.
1017 GetRegisteredPrinters();
1018 return CloudPrintURLFetcher::STOP_PROCESSING;
1019 }
1020
1021
1022 bool CloudPrintProxyBackend::Core::RemovePrinterFromList(
1023 const std::string& printer_name) {
1024 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
1025 for (printing::PrinterList::iterator index = printer_list_.begin();
1026 index != printer_list_.end(); index++) {
1027 if (0 == base::strcasecmp(index->printer_name.c_str(),
1028 printer_name.c_str())) {
1029 index = printer_list_.erase(index);
1030 return true;
1031 }
1032 }
1033 return false;
1034 }
1035
1036 void CloudPrintProxyBackend::Core::RefreshAccessToken() {
1037 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
1038 oauth_client_.reset(new gaia::GaiaOAuthClient(
1039 gaia::kGaiaOAuth2Url,
1040 g_service_process->GetServiceURLRequestContextGetter()));
1041 oauth_client_->RefreshToken(oauth_client_info_,
1042 refresh_token_,
1043 kCloudPrintAPIMaxRetryCount,
1044 this);
1045 }
1046
1047 void CloudPrintProxyBackend::Core::OnNotificationStateChange( 480 void CloudPrintProxyBackend::Core::OnNotificationStateChange(
1048 bool notification_enabled) { 481 bool notification_enabled) {
1049 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); 482 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
1050 notifications_enabled_ = notification_enabled; 483 notifications_enabled_ = notification_enabled;
1051 if (notifications_enabled_) { 484 if (notifications_enabled_) {
1052 notifications_enabled_since_ = base::TimeTicks::Now(); 485 notifications_enabled_since_ = base::TimeTicks::Now();
1053 VLOG(1) << "Notifications for proxy " << proxy_id_ << " were enabled at " 486 VLOG(1) << "Notifications for connector " << proxy_id_
487 << " were enabled at "
1054 << notifications_enabled_since_.ToInternalValue(); 488 << notifications_enabled_since_.ToInternalValue();
1055 } else { 489 } else {
1056 LOG(ERROR) << "Notifications for proxy " << proxy_id_ << " disabled."; 490 LOG(ERROR) << "Notifications for connector " << proxy_id_ << " disabled.";
1057 notifications_enabled_since_ = base::TimeTicks(); 491 notifications_enabled_since_ = base::TimeTicks();
1058 } 492 }
1059 // A state change means one of two cases. 493 // A state change means one of two cases.
1060 // Case 1: We just lost notifications. This this case we want to schedule a 494 // Case 1: We just lost notifications. This this case we want to schedule a
1061 // job poll if enable_job_poll_ is true. 495 // job poll if enable_job_poll_ is true.
1062 // Case 2: Notifications just got re-enabled. In this case we want to schedule 496 // Case 2: Notifications just got re-enabled. In this case we want to schedule
1063 // a poll once for jobs we might have missed when we were dark. 497 // a poll once for jobs we might have missed when we were dark.
1064 // Note that ScheduleJobPoll will not schedule again if a job poll task is 498 // Note that ScheduleJobPoll will not schedule again if a job poll task is
1065 // already scheduled. 499 // already scheduled.
1066 if (enable_job_poll_ || notifications_enabled_) 500 if (enable_job_poll_ || notifications_enabled_)
1067 ScheduleJobPoll(); 501 ScheduleJobPoll();
1068 } 502 }
1069 503
1070 504
1071 void CloudPrintProxyBackend::Core::OnIncomingNotification( 505 void CloudPrintProxyBackend::Core::OnIncomingNotification(
1072 const notifier::Notification& notification) { 506 const notifier::Notification& notification) {
1073 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); 507 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
1074 VLOG(1) << "CP_PROXY: Incoming notification."; 508 VLOG(1) << "CP_CONNECTOR: Incoming notification.";
1075 if (0 == base::strcasecmp(kCloudPrintPushNotificationsSource, 509 if (0 == base::strcasecmp(kCloudPrintPushNotificationsSource,
1076 notification.channel.c_str())) 510 notification.channel.c_str()))
1077 HandlePrinterNotification(notification.data); 511 HandlePrinterNotification(notification.data);
1078 } 512 }
1079 513
1080 void CloudPrintProxyBackend::Core::OnOutgoingNotification() {} 514 void CloudPrintProxyBackend::Core::OnOutgoingNotification() {}
1081
1082 // cloud_print::PrinterChangeNotifier::Delegate implementation
1083 void CloudPrintProxyBackend::Core::OnPrinterAdded() {
1084 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
1085 if (registration_in_progress_)
1086 new_printers_available_ = true;
1087 else
1088 StartRegistration();
1089 }
1090
1091 // PrinterJobHandler::Delegate implementation
1092 void CloudPrintProxyBackend::Core::OnPrinterJobHandlerShutdown(
1093 PrinterJobHandler* job_handler, const std::string& printer_id) {
1094 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
1095 VLOG(1) << "CP_PROXY: Printer job handle shutdown, id " << printer_id;
1096 job_handler_map_.erase(printer_id);
1097 }
1098
1099 void CloudPrintProxyBackend::Core::OnAuthError() {
1100 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
1101 VLOG(1) << "CP_PROXY: Auth Error";
1102 backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
1103 &Core::NotifyAuthenticationFailed));
1104 }
1105
1106 void CloudPrintProxyBackend::Core::OnPrinterNotFound(
1107 const std::string& printer_name,
1108 bool* delete_from_server) {
1109 // If we have a complete list of local printers, then this needs to be deleted
1110 // from the server.
1111 *delete_from_server = complete_list_available_;
1112 }
1113
1114 // gaia::GaiaOAuthClient::Delegate implementation.
1115 void CloudPrintProxyBackend::Core::OnGetTokensResponse(
1116 const std::string& refresh_token,
1117 const std::string& access_token,
1118 int expires_in_seconds) {
1119 refresh_token_ = refresh_token;
1120 // After saving the refresh token, this is just like having just refreshed
1121 // the access token. Just call OnRefreshTokenResponse.
1122 OnRefreshTokenResponse(access_token, expires_in_seconds);
1123 }
1124
1125 void CloudPrintProxyBackend::Core::OnRefreshTokenResponse(
1126 const std::string& access_token, int expires_in_seconds) {
1127 // If our current token is not OAuth, we either have no token at all or we
1128 // have a ClientLogin token which we just exchanged for an OAuth token.
1129 // In this case we need to do the startup initialiazation.
1130 // TODO(sanjeevr): Use an enum for state instead of using this as a signal.
1131 // I will do this in a follow-up change.
1132 CloudPrintTokenStore* token_store = GetTokenStore();
1133 bool first_time = !token_store->token_is_oauth();
1134 token_store->SetToken(access_token, true);
1135 // Let the frontend know that we have authenticated.
1136 backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
1137 &Core::NotifyAuthenticated, refresh_token_, robot_email_, user_email_));
1138 if (first_time) {
1139 PostAuthInitialization();
1140 } else {
1141 // If we are refreshing a token, update the XMPP token too.
1142 DCHECK(talk_mediator_.get());
1143 talk_mediator_->SetAuthToken(robot_email_,
1144 access_token,
1145 kSyncGaiaServiceId);
1146 }
1147 // Schedule a task to refresh the access token again when it is about to
1148 // expire.
1149 DCHECK(expires_in_seconds > kTokenRefreshGracePeriodSecs);
1150 int64 refresh_delay =
1151 (expires_in_seconds - kTokenRefreshGracePeriodSecs)*1000;
1152 MessageLoop::current()->PostDelayedTask(
1153 FROM_HERE,
1154 NewRunnableMethod(this, &Core::RefreshAccessToken),
1155 refresh_delay);
1156 }
1157
1158 void CloudPrintProxyBackend::Core::OnOAuthError() {
1159 OnAuthError();
1160 }
1161
1162 void CloudPrintProxyBackend::Core::OnNetworkError(int response_code) {
1163 // Since we specify inifinite retries on network errors, this should never
1164 // be called.
1165 NOTREACHED() <<
1166 "OnNetworkError invoked when not expected, response code is " <<
1167 response_code;
1168 }
OLDNEW
« no previous file with comments | « chrome/service/cloud_print/cloud_print_proxy_backend.h ('k') | chrome/service/cloud_print/cloud_print_token_store.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698