1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/service/cloud_print/job_status_updater.h"
6
7#include "base/bind.h"
8#include "base/json/json_reader.h"
9#include "base/metrics/histogram.h"
10#include "base/strings/string_util.h"
11#include "base/strings/utf_string_conversions.h"
12#include "base/values.h"
13#include "chrome/common/cloud_print/cloud_print_constants.h"
14#include "chrome/service/cloud_print/cloud_print_service_helpers.h"
15#include "url/gurl.h"
16
17namespace cloud_print {
18
19namespace {
20
21bool IsTerminalJobState(PrintJobStatus status) {
22  return status == PRINT_JOB_STATUS_ERROR ||
23         status == PRINT_JOB_STATUS_COMPLETED;
24}
25
26}  // namespace
27
28JobStatusUpdater::JobStatusUpdater(const std::string& printer_name,
29                                   const std::string& job_id,
30                                   PlatformJobId& local_job_id,
31                                   const GURL& cloud_print_server_url,
32                                   PrintSystem* print_system,
33                                   Delegate* delegate)
34    : start_time_(base::Time::Now()),
35      printer_name_(printer_name),
36      job_id_(job_id),
37      local_job_id_(local_job_id),
38      cloud_print_server_url_(cloud_print_server_url),
39      print_system_(print_system),
40      delegate_(delegate),
41      stopped_(false) {
42  DCHECK(delegate_);
43}
44
45// Start checking the status of the local print job.
46void JobStatusUpdater::UpdateStatus() {
47  // It does not matter if we had already sent out an update and are waiting for
48  // a response. This is a new update and we will simply cancel the old request
49  // and send a new one.
50  if (!stopped_) {
51    bool need_update = false;
52    // If the job has already been completed, we just need to update the server
53    // with that status. The *only* reason we would come back here in that case
54    // is if our last server update attempt failed.
55    if (IsTerminalJobState(last_job_details_.status)) {
56      need_update = true;
57    } else {
58      PrintJobDetails details;
59      if (print_system_->GetJobDetails(printer_name_, local_job_id_,
60                                       &details)) {
61        if (details != last_job_details_) {
62          last_job_details_ = details;
63          need_update = true;
64        }
65      } else {
66        // If GetJobDetails failed, the most likely case is that the job no
67        // longer exists in the OS queue. We are going to assume it is done in
68        // this case.
69        last_job_details_.Clear();
70        last_job_details_.status = PRINT_JOB_STATUS_COMPLETED;
71        need_update = true;
72      }
73      UMA_HISTOGRAM_ENUMERATION("CloudPrint.NativeJobStatus",
74                                last_job_details_.status, PRINT_JOB_STATUS_MAX);
75    }
76    if (need_update) {
77      request_ = CloudPrintURLFetcher::Create();
78      request_->StartGetRequest(
79          CloudPrintURLFetcher::REQUEST_UPDATE_JOB,
80          GetUrlForJobStatusUpdate(
81              cloud_print_server_url_, job_id_, last_job_details_),
82          this,
83          kCloudPrintAPIMaxRetryCount,
84          std::string());
85    }
86  }
87}
88
89void JobStatusUpdater::Stop() {
90  request_ = NULL;
91  DCHECK(delegate_);
92  stopped_ = true;
93  delegate_->OnJobCompleted(this);
94}
95
96// CloudPrintURLFetcher::Delegate implementation.
97CloudPrintURLFetcher::ResponseAction JobStatusUpdater::HandleJSONData(
98      const net::URLFetcher* source,
99      const GURL& url,
100      base::DictionaryValue* json_data,
101      bool succeeded) {
102  if (IsTerminalJobState(last_job_details_.status)) {
103    base::MessageLoop::current()->PostTask(
104        FROM_HERE, base::Bind(&JobStatusUpdater::Stop, this));
105  }
106  return CloudPrintURLFetcher::STOP_PROCESSING;
107}
108
109CloudPrintURLFetcher::ResponseAction JobStatusUpdater::OnRequestAuthError() {
110  // We got an Auth error and have no idea how long it will take to refresh
111  // auth information (may take forever). We'll drop current request and
112  // propagate this error to the upper level. After auth issues will be
113  // resolved, GCP connector will restart.
114  if (delegate_)
115    delegate_->OnAuthError();
116  return CloudPrintURLFetcher::STOP_PROCESSING;
117}
118
119std::string JobStatusUpdater::GetAuthHeader() {
120  return GetCloudPrintAuthHeaderFromStore();
121}
122
123JobStatusUpdater::~JobStatusUpdater() {}
124
125}  // namespace cloud_print
126