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

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: assign default values to id and state 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:
(...skipping 16 matching lines...) Expand all
62 } 65 }
63 66
64 // Returns true if |state| represents a terminal state. 67 // Returns true if |state| represents a terminal state.
65 bool JobFinished(chromeos::CupsPrintJob::State state) { 68 bool JobFinished(chromeos::CupsPrintJob::State state) {
66 using chromeos::CupsPrintJob; 69 using chromeos::CupsPrintJob;
67 return state == CupsPrintJob::State::STATE_CANCELLED || 70 return state == CupsPrintJob::State::STATE_CANCELLED ||
68 state == CupsPrintJob::State::STATE_ERROR || 71 state == CupsPrintJob::State::STATE_ERROR ||
69 state == CupsPrintJob::State::STATE_DOCUMENT_DONE; 72 state == CupsPrintJob::State::STATE_DOCUMENT_DONE;
70 } 73 }
71 74
75 chromeos::QueryResult QueryCups(::printing::CupsConnection* connection,
76 const std::vector<std::string>& printer_ids) {
77 chromeos::QueryResult result;
78 result.success = connection->GetJobs(printer_ids, &(result.queues));
79 return result;
80 }
81
72 } // namespace 82 } // namespace
73 83
74 namespace chromeos { 84 namespace chromeos {
75 85
76 CupsPrintJobManagerImpl::CupsPrintJobManagerImpl(Profile* profile) 86 CupsPrintJobManagerImpl::CupsPrintJobManagerImpl(Profile* profile)
77 : CupsPrintJobManager(profile), 87 : CupsPrintJobManager(profile),
78 cups_connection_(GURL(), HTTP_ENCRYPT_NEVER, false), 88 cups_connection_(GURL(), HTTP_ENCRYPT_NEVER, false),
79 weak_ptr_factory_(this) { 89 weak_ptr_factory_(this) {
80 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT, 90 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
81 content::NotificationService::AllSources()); 91 content::NotificationService::AllSources());
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 LOG(WARNING) << "Printer was removed while job was in progress. It cannot " 145 LOG(WARNING) << "Printer was removed while job was in progress. It cannot "
136 "be tracked"; 146 "be tracked";
137 return false; 147 return false;
138 } 148 }
139 149
140 // Create a new print job. 150 // Create a new print job.
141 auto cpj = base::MakeUnique<CupsPrintJob>(*printer, job_id, title, 151 auto cpj = base::MakeUnique<CupsPrintJob>(*printer, job_id, title,
142 total_page_number); 152 total_page_number);
143 std::string key = cpj->GetUniqueId(); 153 std::string key = cpj->GetUniqueId();
144 jobs_[key] = std::move(cpj); 154 jobs_[key] = std::move(cpj);
155
145 CupsPrintJob* job = jobs_[key].get(); 156 CupsPrintJob* job = jobs_[key].get();
146 NotifyJobCreated(job); 157 NotifyJobCreated(job);
147 158
148 // Always start jobs in the waiting state. 159 // Always start jobs in the waiting state.
149 job->set_state(CupsPrintJob::State::STATE_WAITING); 160 job->set_state(CupsPrintJob::State::STATE_WAITING);
150 NotifyJobUpdated(job); 161 NotifyJobUpdated(job);
151 162
152 ScheduleQuery(base::TimeDelta()); 163 ScheduleQuery(base::TimeDelta());
153 164
154 return true; 165 return true;
155 } 166 }
156 167
157 void CupsPrintJobManagerImpl::ScheduleQuery() { 168 void CupsPrintJobManagerImpl::ScheduleQuery() {
158 ScheduleQuery(base::TimeDelta::FromMilliseconds(kPollRate)); 169 ScheduleQuery(base::TimeDelta::FromMilliseconds(kPollRate));
159 } 170 }
160 171
161 void CupsPrintJobManagerImpl::ScheduleQuery(const base::TimeDelta& delay) { 172 void CupsPrintJobManagerImpl::ScheduleQuery(const base::TimeDelta& delay) {
162 if (!in_query_) { 173 if (!in_query_) {
163 in_query_ = true; 174 in_query_ = true;
164 content::BrowserThread::PostDelayedTask( 175
165 content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE, 176 base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
166 base::Bind(&CupsPrintJobManagerImpl::QueryCups, 177 FROM_HERE,
178 base::Bind(&CupsPrintJobManagerImpl::PostQuery,
167 weak_ptr_factory_.GetWeakPtr()), 179 weak_ptr_factory_.GetWeakPtr()),
168 base::TimeDelta::FromMilliseconds(kPollRate)); 180 delay);
169 } 181 }
170 } 182 }
171 183
172 // Query CUPS asynchronously. Post results back to UI thread. 184 // Query CUPS asynchronously. Post results back to UI thread.
173 void CupsPrintJobManagerImpl::QueryCups() { 185 void CupsPrintJobManagerImpl::PostQuery() {
174 std::vector<::printing::CupsJob> jobs = cups_connection_.GetJobs(); 186 // The set of active printers is expected to be small.
187 std::set<std::string> printer_ids;
188 for (const auto& entry : jobs_) {
189 printer_ids.insert(entry.second->printer().id());
190 }
191 std::vector<std::string> ids{printer_ids.begin(), printer_ids.end()};
175 192
176 content::BrowserThread::PostTask( 193 content::BrowserThread::PostTaskAndReplyWithResult(
177 content::BrowserThread::ID::UI, FROM_HERE, 194 content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE,
195 base::Bind(&QueryCups, &cups_connection_, ids),
178 base::Bind(&CupsPrintJobManagerImpl::UpdateJobs, 196 base::Bind(&CupsPrintJobManagerImpl::UpdateJobs,
179 weak_ptr_factory_.GetWeakPtr(), jobs)); 197 weak_ptr_factory_.GetWeakPtr()));
180 } 198 }
181 199
182 // Use job information to update local job states. Previously completed jobs 200 // Use job information to update local job states. Previously completed jobs
183 // could be in |jobs| but those are ignored as we will not emit updates for them 201 // could be in |jobs| but those are ignored as we will not emit updates for them
184 // after they are completed. 202 // after they are completed.
185 void CupsPrintJobManagerImpl::UpdateJobs( 203 void CupsPrintJobManagerImpl::UpdateJobs(const QueryResult& result) {
186 const std::vector<::printing::CupsJob>& jobs) { 204 const std::vector<::printing::QueueStatus>& queues = result.queues;
205
206 // Query has completed. Allow more queries.
187 in_query_ = false; 207 in_query_ = false;
188 208
209 // If the query failed, either retry or purge.
210 if (!result.success) {
211 retry_count++;
212 LOG(WARNING) << "Failed to query CUPS for queue status. Schedule retry ("
213 << retry_count << ")";
214 if (retry_count > kRetryMax) {
215 PurgeJobs();
Carlson 2017/02/24 00:02:08 Does this deserve a "Giving up" log message?
skau 2017/02/28 00:59:58 Done.
216 } else {
217 // Schedule another query with a larger delay.
218 DCHECK_GE(1, retry_count);
219 ScheduleQuery(base::TimeDelta::FromMilliseconds(kPollRate * retry_count));
220 }
221
Carlson 2017/02/24 00:02:08 Nit: Remove blank line
skau 2017/02/28 00:59:58 Done.
222 return;
223 }
224
225 // A query has completed. Reset retry counter.
226 retry_count = 0;
227
189 std::vector<std::string> active_jobs; 228 std::vector<std::string> active_jobs;
190 for (auto& job : jobs) { 229 for (const auto& queue : queues) {
191 std::string key = CupsPrintJob::GetUniqueId(job.printer_id, job.id); 230 for (auto& job : queue.jobs) {
192 const auto& entry = jobs_.find(key); 231 std::string key = CupsPrintJob::GetUniqueId(job.printer_id, job.id);
193 if (entry != jobs_.end()) { 232 const auto& entry = jobs_.find(key);
233 if (entry == jobs_.end())
234 continue;
235
194 CupsPrintJob* print_job = entry->second.get(); 236 CupsPrintJob* print_job = entry->second.get();
195 237
196 // Update a job we're tracking. 238 // Update a job we're tracking.
197 JobStateUpdated(print_job, ConvertState(job.state)); 239 JobStateUpdated(print_job, ConvertState(job.state));
198 240
199 // Cleanup completed jobs. 241 // Cleanup completed jobs.
200 if (JobFinished(print_job->state())) { 242 if (JobFinished(print_job->state())) {
201 jobs_.erase(entry); 243 jobs_.erase(entry);
202 } else { 244 } else {
203 active_jobs.push_back(key); 245 active_jobs.push_back(key);
204 } 246 }
205 } 247 }
206 } 248 }
207 249
208 // Keep polling until all jobs complete or error. 250 // Keep polling until all jobs complete or error.
209 if (!active_jobs.empty()) { 251 if (!active_jobs.empty()) {
210 ScheduleQuery(); 252 ScheduleQuery();
Carlson 2017/02/24 00:02:08 The fact that the reschedule here doesn't take int
skau 2017/02/28 00:59:58 Hmm. The interval isn't intended to be configurab
Carlson 2017/02/28 01:29:47 The custom poll rate option is just for testing?
Carlson 2017/02/28 18:32:02 Upon reading this more closely, I'm complaining ab
211 } else if (!jobs_.empty()) { 253 } else if (!jobs_.empty()) {
212 // We're tracking jobs that we didn't receive an update for. Something bad 254 // We're tracking jobs that we didn't receive an update for. Something bad
213 // has happened. 255 // has happened.
214 LOG(ERROR) << "Lost track of (" << jobs_.size() << ") jobs"; 256 LOG(ERROR) << "Lost track of (" << jobs_.size() << ") jobs";
215 for (const auto& entry : jobs_) { 257 PurgeJobs();
216 // Declare all lost jobs errors.
217 JobStateUpdated(entry.second.get(), CupsPrintJob::State::STATE_ERROR);
218 }
219
220 jobs_.clear();
221 } 258 }
222 } 259 }
223 260
261 void CupsPrintJobManagerImpl::PurgeJobs() {
262 for (const auto& entry : jobs_) {
263 // Declare all lost jobs errors.
264 JobStateUpdated(entry.second.get(), CupsPrintJob::State::STATE_ERROR);
265 }
266
267 jobs_.clear();
268 }
269
224 void CupsPrintJobManagerImpl::JobStateUpdated(CupsPrintJob* job, 270 void CupsPrintJobManagerImpl::JobStateUpdated(CupsPrintJob* job,
225 CupsPrintJob::State new_state) { 271 CupsPrintJob::State new_state) {
226 if (job->state() == new_state) 272 if (job->state() == new_state)
227 return; 273 return;
228 274
229 // We don't track state transitions because some of them might be missed due 275 // We don't track state transitions because some of them might be missed due
230 // to how we query jobs. 276 // to how we query jobs.
231 job->set_state(new_state); 277 job->set_state(new_state);
232 switch (new_state) { 278 switch (new_state) {
233 case CupsPrintJob::State::STATE_NONE: 279 case CupsPrintJob::State::STATE_NONE:
(...skipping 25 matching lines...) Expand all
259 break; 305 break;
260 } 306 }
261 } 307 }
262 308
263 // static 309 // static
264 CupsPrintJobManager* CupsPrintJobManager::CreateInstance(Profile* profile) { 310 CupsPrintJobManager* CupsPrintJobManager::CreateInstance(Profile* profile) {
265 return new CupsPrintJobManagerImpl(profile); 311 return new CupsPrintJobManagerImpl(profile);
266 } 312 }
267 313
268 } // namespace chromeos 314 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698