Index: cloud_print/gcp20/prototype/print_job_handler.cc |
diff --git a/cloud_print/gcp20/prototype/print_job_handler.cc b/cloud_print/gcp20/prototype/print_job_handler.cc |
index 7c285607faafa4389f6152d7bc742c063126892b..7bbc1af701e83ced8dc6703df0ae59418dd19408 100644 |
--- a/cloud_print/gcp20/prototype/print_job_handler.cc |
+++ b/cloud_print/gcp20/prototype/print_job_handler.cc |
@@ -4,22 +4,66 @@ |
#include "cloud_print/gcp20/prototype/print_job_handler.h" |
+#include "base/bind.h" |
+#include "base/command_line.h" |
#include "base/file_util.h" |
#include "base/format_macros.h" |
#include "base/guid.h" |
#include "base/logging.h" |
+#include "base/message_loop/message_loop.h" |
+#include "base/rand_util.h" |
#include "base/strings/string_util.h" |
#include "base/strings/stringprintf.h" |
#include "base/time/time.h" |
namespace { |
-const int kLocalPrintJobInitExpiration = 5*60; // in seconds |
+const int kDraftExpirationSec = 10; |
+const int kLocalPrintJobExpirationSec = 20; |
+const int kErrorTimeoutSec = 30; |
+ |
+// Errors simulation constants: |
+const double kPaperJamProbability = 0.2; |
+const int kTooManyDraftsTimeout = 10; |
+const int kMaxDrafts = 5; |
const base::FilePath::CharType kJobsPath[] = FILE_PATH_LITERAL("printjobs"); |
+bool ValidateTicket(const std::string& ticket) { |
+ return true; |
+} |
+ |
+std::string GenerateId() { |
+ return StringToLowerASCII(base::GenerateGUID()); |
+} |
+ |
} // namespace |
+struct PrintJobHandler::LocalPrintJobExtended { |
+ LocalPrintJobExtended(const LocalPrintJob& job, const std::string& ticket) |
+ : data(job), |
+ ticket(ticket), |
+ state(LocalPrintJob::STATE_DRAFT) {} |
+ LocalPrintJobExtended() : state(LocalPrintJob::STATE_DRAFT) {} |
+ ~LocalPrintJobExtended() {} |
+ |
+ LocalPrintJob data; |
+ std::string ticket; |
+ LocalPrintJob::State state; |
+ base::Time expiration; |
+}; |
+ |
+struct PrintJobHandler::LocalPrintJobDraft { |
+ LocalPrintJobDraft() {} |
+ LocalPrintJobDraft(const std::string& ticket, const base::Time& expiration) |
+ : ticket(ticket), |
+ expiration(expiration) {} |
+ ~LocalPrintJobDraft() {} |
+ |
+ std::string ticket; |
+ base::Time expiration; |
+}; |
+ |
using base::StringPrintf; |
PrintJobHandler::PrintJobHandler() { |
@@ -28,11 +72,87 @@ PrintJobHandler::PrintJobHandler() { |
PrintJobHandler::~PrintJobHandler() { |
} |
+LocalPrintJob::CreateResult PrintJobHandler::CreatePrintJob( |
+ const std::string& ticket, |
+ std::string* job_id_out, |
+ // TODO(maksymb): Use base::TimeDelta for timeout values |
+ int* expires_in_out, |
+ // TODO(maksymb): Use base::TimeDelta for timeout values |
+ int* error_timeout_out, |
+ std::string* error_description) { |
+ if (!ValidateTicket(ticket)) |
+ return LocalPrintJob::CREATE_INVALID_TICKET; |
+ |
+ // Let's simulate at least some errors just for testing. |
+ if (CommandLine::ForCurrentProcess()->HasSwitch("simulate-printing-errors")) { |
+ if (base::RandDouble() <= kPaperJamProbability) { |
+ *error_description = "Paper jam, try again"; |
+ return LocalPrintJob::CREATE_PRINTER_ERROR; |
+ } |
+ |
+ if (drafts.size() > kMaxDrafts) { // Another simulation of error: business |
+ *error_timeout_out = kTooManyDraftsTimeout; |
+ return LocalPrintJob::CREATE_PRINTER_BUSY; |
+ } |
+ } |
+ |
+ std::string id = GenerateId(); |
+ drafts[id] = LocalPrintJobDraft( |
+ ticket, |
+ base::Time::Now() + base::TimeDelta::FromSeconds(kDraftExpirationSec)); |
+ base::MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, |
+ base::Bind(&PrintJobHandler::ForgetDraft, AsWeakPtr(), id), |
+ base::TimeDelta::FromSeconds(kDraftExpirationSec)); |
+ |
+ *job_id_out = id; |
+ *expires_in_out = kDraftExpirationSec; |
+ return LocalPrintJob::CREATE_SUCCESS; |
+} |
+ |
LocalPrintJob::SaveResult PrintJobHandler::SaveLocalPrintJob( |
const LocalPrintJob& job, |
- std::string* job_id, |
- std::string* error_description, |
- int* timeout) { |
+ std::string* job_id_out, |
+ int* expires_in_out, |
+ std::string* error_description_out, |
+ int* timeout_out) { |
+ std::string id; |
+ int expires_in; |
+ |
+ switch (CreatePrintJob(std::string(), &id, &expires_in, |
+ timeout_out, error_description_out)) { |
+ case LocalPrintJob::CREATE_INVALID_TICKET: |
+ NOTREACHED(); |
+ return LocalPrintJob::SAVE_SUCCESS; |
+ |
+ case LocalPrintJob::CREATE_PRINTER_BUSY: |
+ return LocalPrintJob::SAVE_PRINTER_BUSY; |
+ |
+ case LocalPrintJob::CREATE_PRINTER_ERROR: |
+ return LocalPrintJob::SAVE_PRINTER_ERROR; |
+ |
+ case LocalPrintJob::CREATE_SUCCESS: |
+ *job_id_out = id; |
+ return CompleteLocalPrintJob(job, id, expires_in_out, |
+ error_description_out, timeout_out); |
+ |
+ default: |
+ NOTREACHED(); |
+ return LocalPrintJob::SAVE_SUCCESS; |
+ } |
+} |
+ |
+LocalPrintJob::SaveResult PrintJobHandler::CompleteLocalPrintJob( |
+ const LocalPrintJob& job, |
+ const std::string& job_id, |
+ int* expires_in_out, |
+ std::string* error_description_out, |
+ int* timeout_out) { |
+ if (!drafts.count(job_id)) { |
+ *timeout_out = kErrorTimeoutSec; |
+ return LocalPrintJob::SAVE_INVALID_PRINT_JOB; |
+ } |
+ |
std::string suffix = StringPrintf("%s:%s", |
job.user_name.c_str(), |
job.client_name.c_str()); |
@@ -46,23 +166,50 @@ LocalPrintJob::SaveResult PrintJobHandler::SaveLocalPrintJob( |
} else if (job.content_type == "image/jpeg") { |
file_extension = "jpg"; |
} else { |
- error_description->clear(); |
+ error_description_out->clear(); |
return LocalPrintJob::SAVE_INVALID_DOCUMENT_TYPE; |
} |
+ CompleteDraft(job_id, job); |
+ std::map<std::string, LocalPrintJobExtended>::iterator current_job = |
+ jobs.find(job_id); |
- std::string id = StringToLowerASCII(base::GenerateGUID()); |
- if (!SavePrintJob(job.content, std::string(), |
- base::Time::Now(), |
- StringPrintf("%s", id.c_str()), |
- suffix, job.job_name, file_extension)) { |
- *error_description = "IO error"; |
+ if (!SavePrintJob(current_job->second.data.content, |
+ current_job->second.ticket, |
+ base::Time::Now(), |
+ StringPrintf("%s", job_id.c_str()), |
+ suffix, |
+ current_job->second.data.job_name, file_extension)) { |
+ SetJobState(job_id, LocalPrintJob::STATE_ABORTED); |
+ *error_description_out = "IO error"; |
return LocalPrintJob::SAVE_PRINTER_ERROR; |
} |
- *job_id = id; |
+ SetJobState(job_id, LocalPrintJob::STATE_DONE); |
+ *expires_in_out = static_cast<int>(GetJobExpiration(job_id).InSeconds()); |
return LocalPrintJob::SAVE_SUCCESS; |
} |
+bool PrintJobHandler::GetJobState(const std::string& id, |
+ LocalPrintJob::Info* info_out) { |
+ using base::Time; |
+ |
+ std::map<std::string, LocalPrintJobDraft>::iterator draft = drafts.find(id); |
+ if (draft != drafts.end()) { |
+ info_out->state = LocalPrintJob::STATE_DRAFT; |
+ info_out->expires_in = |
+ static_cast<int>((draft->second.expiration - Time::Now()).InSeconds()); |
+ return true; |
+ } |
+ |
+ std::map<std::string, LocalPrintJobExtended>::iterator job = jobs.find(id); |
+ if (job != jobs.end()) { |
+ info_out->state = job->second.state; |
+ info_out->expires_in = static_cast<int>(GetJobExpiration(id).InSeconds()); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
bool PrintJobHandler::SavePrintJob(const std::string& content, |
const std::string& ticket, |
const base::Time& create_time, |
@@ -123,3 +270,55 @@ bool PrintJobHandler::SavePrintJob(const std::string& content, |
return true; |
} |
+void PrintJobHandler::SetJobState(const std::string& id, |
+ LocalPrintJob::State state) { |
+ DCHECK(!drafts.count(id)) << "Draft should be completed at first"; |
+ |
+ std::map<std::string, LocalPrintJobExtended>::iterator job = jobs.find(id); |
+ DCHECK(job != jobs.end()); |
+ job->second.state = state; |
+ switch (state) { |
+ case LocalPrintJob::STATE_DRAFT: |
+ NOTREACHED(); |
+ break; |
+ case LocalPrintJob::STATE_ABORTED: |
+ case LocalPrintJob::STATE_DONE: |
+ job->second.expiration = |
+ base::Time::Now() + |
+ base::TimeDelta::FromSeconds(kLocalPrintJobExpirationSec); |
+ base::MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, |
+ base::Bind(&PrintJobHandler::ForgetLocalJob, AsWeakPtr(), id), |
+ base::TimeDelta::FromSeconds(kLocalPrintJobExpirationSec)); |
+ break; |
+ default: |
+ NOTREACHED(); |
+ } |
+} |
+ |
+void PrintJobHandler::CompleteDraft(const std::string& id, |
+ const LocalPrintJob& job) { |
+ std::map<std::string, LocalPrintJobDraft>::iterator draft = drafts.find(id); |
+ if (draft != drafts.end()) { |
+ jobs[id] = LocalPrintJobExtended(job, draft->second.ticket); |
+ drafts.erase(draft); |
+ } |
+} |
+ |
+// TODO(maksymb): Use base::Time for expiration |
+base::TimeDelta PrintJobHandler::GetJobExpiration(const std::string& id) const { |
+ DCHECK(jobs.count(id)); |
+ base::Time expiration = jobs.at(id).expiration; |
+ if (expiration.is_null()) |
+ return base::TimeDelta::FromSeconds(kLocalPrintJobExpirationSec); |
+ return expiration - base::Time::Now(); |
+} |
+ |
+void PrintJobHandler::ForgetDraft(const std::string& id) { |
+ drafts.erase(id); |
+} |
+ |
+void PrintJobHandler::ForgetLocalJob(const std::string& id) { |
+ jobs.erase(id); |
+} |
+ |