15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/service/cloud_print/job_status_updater.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_reader.h"
90f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "base/metrics/histogram.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/cloud_print/cloud_print_constants.h"
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/service/cloud_print/cloud_print_service_helpers.h"
157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace cloud_print {
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace {
20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool IsTerminalJobState(PrintJobStatus status) {
22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return status == PRINT_JOB_STATUS_ERROR ||
23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)         status == PRINT_JOB_STATUS_COMPLETED;
24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}  // namespace
27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JobStatusUpdater::JobStatusUpdater(const std::string& printer_name,
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   const std::string& job_id,
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   PlatformJobId& local_job_id,
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   const GURL& cloud_print_server_url,
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   PrintSystem* print_system,
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   Delegate* delegate)
340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    : start_time_(base::Time::Now()),
350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      printer_name_(printer_name),
360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      job_id_(job_id),
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      local_job_id_(local_job_id),
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cloud_print_server_url_(cloud_print_server_url),
390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      print_system_(print_system),
400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      delegate_(delegate),
410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      stopped_(false) {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(delegate_);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Start checking the status of the local print job.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JobStatusUpdater::UpdateStatus() {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It does not matter if we had already sent out an update and are waiting for
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a response. This is a new update and we will simply cancel the old request
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and send a new one.
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!stopped_) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool need_update = false;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the job has already been completed, we just need to update the server
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // with that status. The *only* reason we would come back here in that case
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // is if our last server update attempt failed.
55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (IsTerminalJobState(last_job_details_.status)) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      need_update = true;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      PrintJobDetails details;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (print_system_->GetJobDetails(printer_name_, local_job_id_,
600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                                       &details)) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (details != last_job_details_) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          last_job_details_ = details;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          need_update = true;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If GetJobDetails failed, the most likely case is that the job no
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // longer exists in the OS queue. We are going to assume it is done in
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // this case.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        last_job_details_.Clear();
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        last_job_details_.status = PRINT_JOB_STATUS_COMPLETED;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        need_update = true;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      UMA_HISTOGRAM_ENUMERATION("CloudPrint.NativeJobStatus",
740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                                last_job_details_.status, PRINT_JOB_STATUS_MAX);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (need_update) {
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      request_ = CloudPrintURLFetcher::Create();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request_->StartGetRequest(
790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          CloudPrintURLFetcher::REQUEST_UPDATE_JOB,
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          GetUrlForJobStatusUpdate(
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              cloud_print_server_url_, job_id_, last_job_details_),
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this,
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          kCloudPrintAPIMaxRetryCount,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          std::string());
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JobStatusUpdater::Stop() {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_ = NULL;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(delegate_);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stopped_ = true;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->OnJobCompleted(this);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CloudPrintURLFetcher::Delegate implementation.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CloudPrintURLFetcher::ResponseAction JobStatusUpdater::HandleJSONData(
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const net::URLFetcher* source,
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const GURL& url,
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::DictionaryValue* json_data,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool succeeded) {
102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (IsTerminalJobState(last_job_details_.status)) {
103a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE, base::Bind(&JobStatusUpdater::Stop, this));
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CloudPrintURLFetcher::STOP_PROCESSING;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CloudPrintURLFetcher::ResponseAction JobStatusUpdater::OnRequestAuthError() {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We got an Auth error and have no idea how long it will take to refresh
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // auth information (may take forever). We'll drop current request and
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // propagate this error to the upper level. After auth issues will be
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // resolved, GCP connector will restart.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnAuthError();
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CloudPrintURLFetcher::STOP_PROCESSING;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string JobStatusUpdater::GetAuthHeader() {
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return GetCloudPrintAuthHeaderFromStore();
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JobStatusUpdater::~JobStatusUpdater() {}
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace cloud_print
126