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

Side by Side Diff: chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc

Issue 2691093006: Implement IPP Get-Jobs and Get-Printer-Attributes requests. (Closed)
Patch Set: rebase Created 3 years, 9 months 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
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 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/browser/chromeos/printing/cups_print_job_manager_impl.h" 5 #include "chrome/browser/chromeos/printing/cups_print_job_manager_impl.h"
6 6
7 #include <cups/cups.h> 7 #include <cups/cups.h>
8 #include <set> 8 #include <set>
9 #include <string> 9 #include <string>
10 #include <utility> 10 #include <utility>
(...skipping 15 matching lines...) Expand all
26 #include "content/public/browser/notification_registrar.h" 26 #include "content/public/browser/notification_registrar.h"
27 #include "content/public/browser/notification_service.h" 27 #include "content/public/browser/notification_service.h"
28 #include "printing/backend/cups_connection.h" 28 #include "printing/backend/cups_connection.h"
29 #include "printing/printed_document.h" 29 #include "printing/printed_document.h"
30 30
31 namespace { 31 namespace {
32 32
33 // The rate in milliseconds at which we will poll CUPS for print job updates. 33 // The rate in milliseconds at which we will poll CUPS for print job updates.
34 const int kPollRate = 1000; 34 const int kPollRate = 1000;
35 35
36 // Threshold for giving up on communicating with CUPS.
37 const int kRetryMax = 6;
38
36 // Returns the equivalient CupsPrintJob#State from a CupsJob#JobState. 39 // Returns the equivalient CupsPrintJob#State from a CupsJob#JobState.
37 chromeos::CupsPrintJob::State ConvertState(printing::CupsJob::JobState state) { 40 chromeos::CupsPrintJob::State ConvertState(printing::CupsJob::JobState state) {
38 using cpj = chromeos::CupsPrintJob::State; 41 using cpj = chromeos::CupsPrintJob::State;
39 42
40 switch (state) { 43 switch (state) {
41 case printing::CupsJob::PENDING: 44 case printing::CupsJob::PENDING:
42 return cpj::STATE_WAITING; 45 return cpj::STATE_WAITING;
43 case printing::CupsJob::HELD: 46 case printing::CupsJob::HELD:
44 return cpj::STATE_SUSPENDED; 47 return cpj::STATE_SUSPENDED;
45 case printing::CupsJob::PROCESSING: 48 case printing::CupsJob::PROCESSING:
46 return cpj::STATE_STARTED; 49 return cpj::STATE_STARTED;
47 case printing::CupsJob::CANCELED: 50 case printing::CupsJob::CANCELED:
48 return cpj::STATE_CANCELLED; 51 return cpj::STATE_CANCELLED;
49 case printing::CupsJob::COMPLETED: 52 case printing::CupsJob::COMPLETED:
50 return cpj::STATE_DOCUMENT_DONE; 53 return cpj::STATE_DOCUMENT_DONE;
51 case printing::CupsJob::STOPPED: 54 case printing::CupsJob::STOPPED:
52 return cpj::STATE_SUSPENDED; 55 return cpj::STATE_SUSPENDED;
53 case printing::CupsJob::ABORTED: 56 case printing::CupsJob::ABORTED:
54 return cpj::STATE_ERROR; 57 return cpj::STATE_ERROR;
55 case printing::CupsJob::UNKNOWN: 58 case printing::CupsJob::UNKNOWN:
56 break; 59 break;
57 } 60 }
58 61
59 NOTREACHED(); 62 NOTREACHED();
60 63
61 return cpj::STATE_NONE; 64 return cpj::STATE_NONE;
62 } 65 }
63 66
67 chromeos::QueryResult QueryCups(::printing::CupsConnection* connection,
68 const std::vector<std::string>& printer_ids) {
69 chromeos::QueryResult result;
70 result.success = connection->GetJobs(printer_ids, &(result.queues));
Lei Zhang 2017/03/07 23:31:29 nit: Do you need the extra parenthesis around resu
skau 2017/03/10 01:07:00 Done.
71 return result;
72 }
73
64 } // namespace 74 } // namespace
65 75
66 namespace chromeos { 76 namespace chromeos {
67 77
68 CupsPrintJobManagerImpl::CupsPrintJobManagerImpl(Profile* profile) 78 CupsPrintJobManagerImpl::CupsPrintJobManagerImpl(Profile* profile)
69 : CupsPrintJobManager(profile), 79 : CupsPrintJobManager(profile),
70 cups_connection_(GURL(), HTTP_ENCRYPT_NEVER, false), 80 cups_connection_(GURL(), HTTP_ENCRYPT_NEVER, false),
71 weak_ptr_factory_(this) { 81 weak_ptr_factory_(this) {
72 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT, 82 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
73 content::NotificationService::AllSources()); 83 content::NotificationService::AllSources());
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 LOG(WARNING) << "Printer was removed while job was in progress. It cannot " 137 LOG(WARNING) << "Printer was removed while job was in progress. It cannot "
128 "be tracked"; 138 "be tracked";
129 return false; 139 return false;
130 } 140 }
131 141
132 // Create a new print job. 142 // Create a new print job.
133 auto cpj = base::MakeUnique<CupsPrintJob>(*printer, job_id, title, 143 auto cpj = base::MakeUnique<CupsPrintJob>(*printer, job_id, title,
134 total_page_number); 144 total_page_number);
135 std::string key = cpj->GetUniqueId(); 145 std::string key = cpj->GetUniqueId();
136 jobs_[key] = std::move(cpj); 146 jobs_[key] = std::move(cpj);
147
137 CupsPrintJob* job = jobs_[key].get(); 148 CupsPrintJob* job = jobs_[key].get();
138 NotifyJobCreated(job); 149 NotifyJobCreated(job);
139 150
140 // Always start jobs in the waiting state. 151 // Always start jobs in the waiting state.
141 job->set_state(CupsPrintJob::State::STATE_WAITING); 152 job->set_state(CupsPrintJob::State::STATE_WAITING);
142 NotifyJobUpdated(job); 153 NotifyJobUpdated(job);
143 154
144 ScheduleQuery(base::TimeDelta()); 155 ScheduleQuery(base::TimeDelta());
145 156
146 return true; 157 return true;
147 } 158 }
148 159
149 void CupsPrintJobManagerImpl::ScheduleQuery() { 160 void CupsPrintJobManagerImpl::ScheduleQuery() {
150 ScheduleQuery(base::TimeDelta::FromMilliseconds(kPollRate)); 161 ScheduleQuery(base::TimeDelta::FromMilliseconds(kPollRate));
151 } 162 }
152 163
153 void CupsPrintJobManagerImpl::ScheduleQuery(const base::TimeDelta& delay) { 164 void CupsPrintJobManagerImpl::ScheduleQuery(const base::TimeDelta& delay) {
154 if (!in_query_) { 165 if (!in_query_) {
155 in_query_ = true; 166 in_query_ = true;
156 content::BrowserThread::PostDelayedTask( 167
157 content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE, 168 base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
158 base::Bind(&CupsPrintJobManagerImpl::QueryCups, 169 FROM_HERE,
170 base::Bind(&CupsPrintJobManagerImpl::PostQuery,
159 weak_ptr_factory_.GetWeakPtr()), 171 weak_ptr_factory_.GetWeakPtr()),
160 base::TimeDelta::FromMilliseconds(kPollRate)); 172 delay);
161 } 173 }
162 } 174 }
163 175
164 // Query CUPS asynchronously. Post results back to UI thread. 176 // Query CUPS asynchronously. Post results back to UI thread.
Lei Zhang 2017/03/07 23:31:29 Can you move this to the header and consolidate it
skau 2017/03/10 01:07:00 Done.
165 void CupsPrintJobManagerImpl::QueryCups() { 177 void CupsPrintJobManagerImpl::PostQuery() {
166 std::vector<::printing::CupsJob> jobs = cups_connection_.GetJobs(); 178 // The set of active printers is expected to be small.
179 std::set<std::string> printer_ids;
180 for (const auto& entry : jobs_) {
181 printer_ids.insert(entry.second->printer().id());
182 }
183 std::vector<std::string> ids{printer_ids.begin(), printer_ids.end()};
167 184
168 content::BrowserThread::PostTask( 185 content::BrowserThread::PostTaskAndReplyWithResult(
169 content::BrowserThread::ID::UI, FROM_HERE, 186 content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE,
187 base::Bind(&QueryCups, &cups_connection_, ids),
170 base::Bind(&CupsPrintJobManagerImpl::UpdateJobs, 188 base::Bind(&CupsPrintJobManagerImpl::UpdateJobs,
171 weak_ptr_factory_.GetWeakPtr(), jobs)); 189 weak_ptr_factory_.GetWeakPtr()));
172 } 190 }
173 191
174 // Use job information to update local job states. Previously completed jobs 192 // Use job information to update local job states. Previously completed jobs
175 // could be in |jobs| but those are ignored as we will not emit updates for them 193 // could be in |jobs| but those are ignored as we will not emit updates for them
176 // after they are completed. 194 // after they are completed.
177 void CupsPrintJobManagerImpl::UpdateJobs( 195 void CupsPrintJobManagerImpl::UpdateJobs(const QueryResult& result) {
178 const std::vector<::printing::CupsJob>& jobs) { 196 const std::vector<::printing::QueueStatus>& queues = result.queues;
197
198 // Query has completed. Allow more queries.
179 in_query_ = false; 199 in_query_ = false;
180 200
201 // If the query failed, either retry or purge.
202 if (!result.success) {
203 retry_count_++;
204 LOG(WARNING) << "Failed to query CUPS for queue status. Schedule retry ("
205 << retry_count_ << ")";
206 if (retry_count_ > kRetryMax) {
207 LOG(ERROR) << "CUPS is unreachable. Giving up on all jobs.";
208 PurgeJobs();
209 } else {
210 // Schedule another query with a larger delay.
211 DCHECK_GE(1, retry_count_);
212 ScheduleQuery(
213 base::TimeDelta::FromMilliseconds(kPollRate * retry_count_));
214 }
215 return;
216 }
217
218 // A query has completed. Reset retry counter.
219 retry_count_ = 0;
220
181 std::vector<std::string> active_jobs; 221 std::vector<std::string> active_jobs;
182 for (auto& job : jobs) { 222 for (const auto& queue : queues) {
183 std::string key = CupsPrintJob::GetUniqueId(job.printer_id, job.id); 223 for (auto& job : queue.jobs) {
184 const auto& entry = jobs_.find(key); 224 std::string key = CupsPrintJob::GetUniqueId(job.printer_id, job.id);
185 if (entry != jobs_.end()) { 225 const auto& entry = jobs_.find(key);
226 if (entry == jobs_.end())
227 continue;
228
186 CupsPrintJob* print_job = entry->second.get(); 229 CupsPrintJob* print_job = entry->second.get();
187 230
188 // Update a job we're tracking. 231 // Update a job we're tracking.
189 JobStateUpdated(print_job, ConvertState(job.state)); 232 JobStateUpdated(print_job, ConvertState(job.state));
190 233
191 // Cleanup completed jobs. 234 // Cleanup completed jobs.
192 if (print_job->IsJobFinished()) { 235 if (print_job->IsJobFinished()) {
193 jobs_.erase(entry); 236 jobs_.erase(entry);
194 } else { 237 } else {
195 active_jobs.push_back(key); 238 active_jobs.push_back(key);
196 } 239 }
197 } 240 }
198 } 241 }
199 242
200 // Keep polling until all jobs complete or error. 243 // Keep polling until all jobs complete or error.
201 if (!active_jobs.empty()) { 244 if (!active_jobs.empty()) {
245 // During normal operations, we poll at the default rate.
202 ScheduleQuery(); 246 ScheduleQuery();
203 } else if (!jobs_.empty()) { 247 } else if (!jobs_.empty()) {
204 // We're tracking jobs that we didn't receive an update for. Something bad 248 // We're tracking jobs that we didn't receive an update for. Something bad
205 // has happened. 249 // has happened.
206 LOG(ERROR) << "Lost track of (" << jobs_.size() << ") jobs"; 250 LOG(ERROR) << "Lost track of (" << jobs_.size() << ") jobs";
207 for (const auto& entry : jobs_) { 251 PurgeJobs();
208 // Declare all lost jobs errors.
209 JobStateUpdated(entry.second.get(), CupsPrintJob::State::STATE_ERROR);
210 }
211
212 jobs_.clear();
213 } 252 }
214 } 253 }
215 254
255 void CupsPrintJobManagerImpl::PurgeJobs() {
256 for (const auto& entry : jobs_) {
257 // Declare all lost jobs errors.
258 JobStateUpdated(entry.second.get(), CupsPrintJob::State::STATE_ERROR);
259 }
260
261 jobs_.clear();
262 }
263
216 void CupsPrintJobManagerImpl::JobStateUpdated(CupsPrintJob* job, 264 void CupsPrintJobManagerImpl::JobStateUpdated(CupsPrintJob* job,
217 CupsPrintJob::State new_state) { 265 CupsPrintJob::State new_state) {
218 if (job->state() == new_state) 266 if (job->state() == new_state)
219 return; 267 return;
220 268
221 // We don't track state transitions because some of them might be missed due 269 // We don't track state transitions because some of them might be missed due
222 // to how we query jobs. 270 // to how we query jobs.
223 job->set_state(new_state); 271 job->set_state(new_state);
224 switch (new_state) { 272 switch (new_state) {
225 case CupsPrintJob::State::STATE_NONE: 273 case CupsPrintJob::State::STATE_NONE:
(...skipping 25 matching lines...) Expand all
251 break; 299 break;
252 } 300 }
253 } 301 }
254 302
255 // static 303 // static
256 CupsPrintJobManager* CupsPrintJobManager::CreateInstance(Profile* profile) { 304 CupsPrintJobManager* CupsPrintJobManager::CreateInstance(Profile* profile) {
257 return new CupsPrintJobManagerImpl(profile); 305 return new CupsPrintJobManagerImpl(profile);
258 } 306 }
259 307
260 } // namespace chromeos 308 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698