1 // Copyright (c) 2013 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.
5 #include "chrome/service/cloud_print/printer_job_queue_handler.h"
11 #include "base/values.h"
13 namespace cloud_print
{
15 class TimeProviderImpl
: public PrinterJobQueueHandler::TimeProvider
{
17 base::Time
GetNow() override
;
20 base::Time
TimeProviderImpl::GetNow() {
21 return base::Time::Now();
24 JobDetails::JobDetails() {}
26 JobDetails::~JobDetails() {}
28 void JobDetails::Clear() {
32 print_ticket_
.clear();
33 print_ticket_mime_type_
.clear();
34 print_data_mime_type_
.clear();
35 print_data_file_path_
= base::FilePath();
36 print_data_url_
.clear();
37 print_ticket_url_
.clear();
39 time_remaining_
= base::TimeDelta();
43 bool JobDetails::ordering(const JobDetails
& first
, const JobDetails
& second
) {
44 return first
.time_remaining_
< second
.time_remaining_
;
47 PrinterJobQueueHandler::PrinterJobQueueHandler(TimeProvider
* time_provider
)
48 : time_provider_(time_provider
) {}
50 PrinterJobQueueHandler::PrinterJobQueueHandler()
51 : time_provider_(new TimeProviderImpl()) {}
53 PrinterJobQueueHandler::~PrinterJobQueueHandler() {}
55 void PrinterJobQueueHandler::ConstructJobDetailsFromJson(
56 const base::DictionaryValue
* job_data
,
57 JobDetails
* job_details
) {
60 job_data
->GetString(kIdValue
, &job_details
->job_id_
);
61 job_data
->GetString(kTitleValue
, &job_details
->job_title_
);
62 job_data
->GetString(kOwnerValue
, &job_details
->job_owner_
);
64 job_data
->GetString(kTicketUrlValue
, &job_details
->print_ticket_url_
);
65 job_data
->GetString(kFileUrlValue
, &job_details
->print_data_url_
);
67 // Get tags for print job.
68 const base::ListValue
* tags
= NULL
;
69 if (job_data
->GetList(kTagsValue
, &tags
)) {
70 for (size_t i
= 0; i
< tags
->GetSize(); i
++) {
72 if (tags
->GetString(i
, &value
))
73 job_details
->tags_
.push_back(value
);
78 base::TimeDelta
PrinterJobQueueHandler::ComputeBackoffTime(
79 const std::string
& job_id
) {
80 FailedJobMap::const_iterator job_location
= failed_job_map_
.find(job_id
);
81 if (job_location
== failed_job_map_
.end()) {
82 return base::TimeDelta();
85 base::TimeDelta backoff_time
=
86 base::TimeDelta::FromSeconds(kJobFirstWaitTimeSecs
);
88 // casting argument to double and result to uint64 to avoid compilation
90 static_cast<int64
>(pow(
91 static_cast<long double>(kJobWaitTimeExponentialMultiplier
),
92 job_location
->second
.retries_
) + 0.5);
93 base::Time scheduled_retry
=
94 job_location
->second
.last_retry_
+ backoff_time
;
95 base::Time now
= time_provider_
->GetNow();
96 base::TimeDelta time_remaining
;
98 if (scheduled_retry
< now
) {
99 return base::TimeDelta();
101 return scheduled_retry
- now
;
104 void PrinterJobQueueHandler::GetJobsFromQueue(
105 const base::DictionaryValue
* json_data
,
106 std::vector
<JobDetails
>* jobs
) {
107 std::vector
<JobDetails
> jobs_with_timeouts
;
111 const base::ListValue
* job_list
= NULL
;
112 if (!json_data
->GetList(kJobListValue
, &job_list
)) {
116 size_t list_size
= job_list
->GetSize();
117 for (size_t cur_job
= 0; cur_job
< list_size
; cur_job
++) {
118 const base::DictionaryValue
* job_data
= NULL
;
119 if (job_list
->GetDictionary(cur_job
, &job_data
)) {
120 JobDetails job_details_current
;
121 ConstructJobDetailsFromJson(job_data
, &job_details_current
);
123 job_details_current
.time_remaining_
=
124 ComputeBackoffTime(job_details_current
.job_id_
);
126 if (job_details_current
.time_remaining_
== base::TimeDelta()) {
127 jobs
->push_back(job_details_current
);
129 jobs_with_timeouts
.push_back(job_details_current
);
134 sort(jobs_with_timeouts
.begin(), jobs_with_timeouts
.end(),
135 &JobDetails::ordering
);
136 jobs
->insert(jobs
->end(), jobs_with_timeouts
.begin(),
137 jobs_with_timeouts
.end());
140 void PrinterJobQueueHandler::JobDone(const std::string
& job_id
) {
141 failed_job_map_
.erase(job_id
);
144 bool PrinterJobQueueHandler::JobFetchFailed(const std::string
& job_id
) {
145 FailedJobMetadata metadata
;
146 metadata
.retries_
= 0;
147 metadata
.last_retry_
= time_provider_
->GetNow();
149 std::pair
<FailedJobMap::iterator
, bool> job_found
=
150 failed_job_map_
.insert(FailedJobPair(job_id
, metadata
));
152 // If the job has already failed once, increment the number of retries.
153 // If it has failed too many times, remove it from the map and tell the caller
154 // to report a failure.
155 if (!job_found
.second
) {
156 if (job_found
.first
->second
.retries_
>= kNumRetriesBeforeAbandonJob
) {
157 failed_job_map_
.erase(job_found
.first
);
161 job_found
.first
->second
.retries_
+= 1;
162 job_found
.first
->second
.last_retry_
= time_provider_
->GetNow();
168 } // namespace cloud_print