summaryrefslogtreecommitdiffstats
path: root/cloud_print
diff options
context:
space:
mode:
authormaksymb@chromium.org <maksymb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-20 00:50:02 +0000
committermaksymb@chromium.org <maksymb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-20 00:50:02 +0000
commitb4d45877a4e0dcc77fff031cdd59ab46878b8c2f (patch)
tree7ad1c98f5a8e5e01c2b38f3676f770b8e4e920b3 /cloud_print
parentb8f6d6a77991a11c28beb33b0cfc65a8de6cd0f5 (diff)
downloadchromium_src-b4d45877a4e0dcc77fff031cdd59ab46878b8c2f.zip
chromium_src-b4d45877a4e0dcc77fff031cdd59ab46878b8c2f.tar.gz
chromium_src-b4d45877a4e0dcc77fff031cdd59ab46878b8c2f.tar.bz2
GCP2.0 Device: Adding advanced printing.
BUG= Review URL: https://chromiumcodereview.appspot.com/23271004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@218380 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cloud_print')
-rw-r--r--cloud_print/gcp20/prototype/gcp20_device.cc27
-rw-r--r--cloud_print/gcp20/prototype/local_print_job.cc6
-rw-r--r--cloud_print/gcp20/prototype/local_print_job.h14
-rw-r--r--cloud_print/gcp20/prototype/print_job_handler.cc223
-rw-r--r--cloud_print/gcp20/prototype/print_job_handler.h66
-rw-r--r--cloud_print/gcp20/prototype/printer.cc39
-rw-r--r--cloud_print/gcp20/prototype/printer.h19
-rw-r--r--cloud_print/gcp20/prototype/privet_http_server.cc114
-rw-r--r--cloud_print/gcp20/prototype/privet_http_server.h32
9 files changed, 480 insertions, 60 deletions
diff --git a/cloud_print/gcp20/prototype/gcp20_device.cc b/cloud_print/gcp20/prototype/gcp20_device.cc
index 2d2c1d5..57972a3 100644
--- a/cloud_print/gcp20/prototype/gcp20_device.cc
+++ b/cloud_print/gcp20/prototype/gcp20_device.cc
@@ -20,21 +20,22 @@ const char kHelpMessage[] =
"usage: gcp20_device [switches] [options]\n"
"\n"
"switches:\n"
- " --disable-confirmation disables confirmation of registration\n"
- " --disable-method-check disables HTTP method checking (POST, GET)\n"
- " --disable-x-token disables checking of X-Privet-Token "
- "HTTP header\n"
- " -h, --help prints this message\n"
- " --no-announcement disables DNS announcements\n"
- " --unicast-respond DNS responses will be sent in unicast "
- "instead of multicast\n"
+ " --disable-confirmation disables confirmation of registration\n"
+ " --disable-method-check disables HTTP method checking (POST, GET)\n"
+ " --disable-x-token disables checking of X-Privet-Token "
+ "HTTP header\n"
+ " -h, --help prints this message\n"
+ " --no-announcement disables DNS announcements\n"
+ " --simulate-printing-errors simulates some errors for local printing\n"
+ " --unicast-respond DNS responses will be sent in unicast "
+ "instead of multicast\n"
"\n"
"options:\n"
- " --domain-name=<name> sets, should ends with '.local'\n"
- " --http-port=<value> sets port for HTTP server\n"
- " --service-name=<name> sets DNS service name\n"
- " --state-path=<path> sets path to file with registration state\n"
- " --ttl=<value> sets TTL for DNS announcements\n"
+ " --domain-name=<name> sets, should ends with '.local'\n"
+ " --http-port=<value> sets port for HTTP server\n"
+ " --service-name=<name> sets DNS service name\n"
+ " --state-path=<path> sets path to file with registration state\n"
+ " --ttl=<value> sets TTL for DNS announcements\n"
"\n"
"WARNING: mDNS probing is not implemented\n";
diff --git a/cloud_print/gcp20/prototype/local_print_job.cc b/cloud_print/gcp20/prototype/local_print_job.cc
index b795c30..cafdecf 100644
--- a/cloud_print/gcp20/prototype/local_print_job.cc
+++ b/cloud_print/gcp20/prototype/local_print_job.cc
@@ -10,3 +10,9 @@ LocalPrintJob::LocalPrintJob() : offline(false) {
LocalPrintJob::~LocalPrintJob() {
}
+LocalPrintJob::Info::Info() : state(STATE_DRAFT), expires_in(-1) {
+}
+
+LocalPrintJob::Info::~Info() {
+}
+
diff --git a/cloud_print/gcp20/prototype/local_print_job.h b/cloud_print/gcp20/prototype/local_print_job.h
index b28e024..4959aff 100644
--- a/cloud_print/gcp20/prototype/local_print_job.h
+++ b/cloud_print/gcp20/prototype/local_print_job.h
@@ -25,6 +25,20 @@ struct LocalPrintJob {
SAVE_PRINTER_ERROR,
};
+ enum State {
+ STATE_DRAFT,
+ STATE_ABORTED,
+ STATE_DONE,
+ };
+
+ struct Info {
+ Info();
+ ~Info();
+
+ State state;
+ int expires_in;
+ };
+
LocalPrintJob();
~LocalPrintJob();
diff --git a/cloud_print/gcp20/prototype/print_job_handler.cc b/cloud_print/gcp20/prototype/print_job_handler.cc
index 7c28560..7bbc1af 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);
+}
+
diff --git a/cloud_print/gcp20/prototype/print_job_handler.h b/cloud_print/gcp20/prototype/print_job_handler.h
index fc48a1e..fe59c7f 100644
--- a/cloud_print/gcp20/prototype/print_job_handler.h
+++ b/cloud_print/gcp20/prototype/print_job_handler.h
@@ -5,9 +5,12 @@
#ifndef CLOUD_PRINT_GCP20_PROTOTYPE_PRINT_JOB_HANDLER_H_
#define CLOUD_PRINT_GCP20_PROTOTYPE_PRINT_JOB_HANDLER_H_
+#include <map>
#include <string>
#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "cloud_print/gcp20/prototype/local_print_job.h"
namespace base {
@@ -17,18 +20,39 @@ class Time;
} // namespace base
-class PrintJobHandler {
+class PrintJobHandler : public base::SupportsWeakPtr<PrintJobHandler> {
public:
PrintJobHandler();
~PrintJobHandler();
- LocalPrintJob::CreateResult CreatePrintJob(std::string* job_id,
- int* expires_in);
- LocalPrintJob::SaveResult SaveLocalPrintJob(const LocalPrintJob& job,
- std::string* job_id,
- std::string* error_description,
- int* timeout);
+ // Creates printer job draft
+ LocalPrintJob::CreateResult CreatePrintJob(
+ const std::string& ticket,
+ std::string* job_id_out,
+ int* expires_in_out,
+ int* error_timeout_out,
+ std::string* error_description_out);
+ // Creates printer job with empty ticket and "prints" it
+ LocalPrintJob::SaveResult SaveLocalPrintJob(
+ const LocalPrintJob& job,
+ std::string* job_id_out,
+ int* expires_in_out,
+ std::string* error_description_out,
+ int* timeout_out);
+
+ // Completes printer job from draft
+ LocalPrintJob::SaveResult CompleteLocalPrintJob(
+ const LocalPrintJob& job,
+ const std::string& job_id,
+ int* expires_in_out,
+ std::string* error_description_out,
+ int* timeout_out);
+
+ // Gives info about job
+ bool GetJobState(const std::string& id, LocalPrintJob::Info* info_out);
+
+ // Saving print job directly to drive
bool SavePrintJob(const std::string& content,
const std::string& ticket,
const base::Time& create_time,
@@ -38,6 +62,34 @@ class PrintJobHandler {
const std::string& file_extension);
private:
+ // Contains ticket info and job info together
+ struct LocalPrintJobExtended;
+
+ // Contains job ticket
+ struct LocalPrintJobDraft;
+
+ // Contains all unexpired drafts
+ std::map<std::string, LocalPrintJobDraft> drafts; // id -> draft
+
+ // Contains all unexpired jobs
+ std::map<std::string, LocalPrintJobExtended> jobs; // id -> printjob
+
+ // Changes job state and creates timeouts to delete old jobs from memory
+ void SetJobState(const std::string& id, LocalPrintJob::State);
+
+ // Moves draft to jobs
+ void CompleteDraft(const std::string& id, const LocalPrintJob& job);
+
+ // Calculates expiration for job
+ // TODO(maksymb): Use base::Time for expiration
+ base::TimeDelta GetJobExpiration(const std::string& id) const;
+
+ // Erases draft from memory
+ void ForgetDraft(const std::string& id);
+
+ // Erases job from memory
+ void ForgetLocalJob(const std::string& id);
+
DISALLOW_COPY_AND_ASSIGN(PrintJobHandler);
};
diff --git a/cloud_print/gcp20/prototype/printer.cc b/cloud_print/gcp20/prototype/printer.cc
index 197f70d..9513979 100644
--- a/cloud_print/gcp20/prototype/printer.cc
+++ b/cloud_print/gcp20/prototype/printer.cc
@@ -342,12 +342,15 @@ void Printer::CreateInfo(PrivetHttpServer::DeviceInfo* info) {
// TODO(maksymb): Create enum for available APIs and replace
// this API text names with constants from enum. API text names should be only
// known in PrivetHttpServer.
- if (state_.registration_state == PrinterState::UNREGISTERED) {
+ if (!IsRegistered()) {
info->api.push_back("/privet/register");
} else {
- if (IsLocalPrintingAllowed())
- info->api.push_back("/privet/printer/submitdoc");
info->api.push_back("/privet/capabilities");
+ if (IsLocalPrintingAllowed()) {
+ info->api.push_back("/privet/printer/createjob");
+ info->api.push_back("/privet/printer/submitdoc");
+ info->api.push_back("/privet/printer/jobstate");
+ }
}
info->type.push_back("printer");
@@ -372,22 +375,36 @@ scoped_ptr<base::DictionaryValue> Printer::GetCapabilities() {
return scoped_ptr<base::DictionaryValue>(dictionary_value->DeepCopy());
}
-void Printer::CreateJob(const std::string& ticket) {
- // TODO(maksymb): Implement advanced printing
- NOTIMPLEMENTED();
+LocalPrintJob::CreateResult Printer::CreateJob(const std::string& ticket,
+ std::string* job_id,
+ int* expires_in,
+ int* error_timeout,
+ std::string* error_description) {
+ return print_job_handler_->CreatePrintJob(ticket, job_id, expires_in,
+ error_timeout, error_description);
}
LocalPrintJob::SaveResult Printer::SubmitDoc(const LocalPrintJob& job,
std::string* job_id,
+ int* expires_in,
std::string* error_description,
int* timeout) {
- return print_job_handler_->SaveLocalPrintJob(job, job_id, error_description,
- timeout);
+ return print_job_handler_->SaveLocalPrintJob(job, job_id, expires_in,
+ error_description, timeout);
+}
+
+LocalPrintJob::SaveResult Printer::SubmitDocWithId(
+ const LocalPrintJob& job,
+ const std::string& job_id,
+ int* expires_in,
+ std::string* error_description,
+ int* timeout) {
+ return print_job_handler_->CompleteLocalPrintJob(job, job_id, expires_in,
+ error_description, timeout);
}
-void Printer::GetJobStatus(int job_id) {
- // TODO(maksymb): Implement advanced printing
- NOTIMPLEMENTED();
+bool Printer::GetJobState(const std::string& id, LocalPrintJob::Info* info) {
+ return print_job_handler_->GetJobState(id, info);
}
void Printer::OnRegistrationStartResponseParsed(
diff --git a/cloud_print/gcp20/prototype/printer.h b/cloud_print/gcp20/prototype/printer.h
index ccc97b3..69e8874 100644
--- a/cloud_print/gcp20/prototype/printer.h
+++ b/cloud_print/gcp20/prototype/printer.h
@@ -20,8 +20,6 @@
extern const base::FilePath::CharType kPrinterStatePath[];
-struct LocalPrintJob;
-
// This class maintains work of DNS-SD server, HTTP server and others.
class Printer : public base::SupportsWeakPtr<Printer>,
public PrivetHttpServer::Delegate,
@@ -74,13 +72,26 @@ class Printer : public base::SupportsWeakPtr<Printer>,
virtual bool IsLocalPrintingAllowed() const OVERRIDE;
virtual bool CheckXPrivetTokenHeader(const std::string& token) const OVERRIDE;
virtual scoped_ptr<base::DictionaryValue> GetCapabilities() OVERRIDE;
- virtual void CreateJob(const std::string& ticket) OVERRIDE;
+ virtual LocalPrintJob::CreateResult CreateJob(
+ const std::string& ticket,
+ std::string* job_id,
+ int* expires_in,
+ int* error_timeout,
+ std::string* error_description) OVERRIDE;
virtual LocalPrintJob::SaveResult SubmitDoc(
const LocalPrintJob& job,
std::string* job_id,
+ int* expires_in,
+ std::string* error_description,
+ int* timeout) OVERRIDE;
+ virtual LocalPrintJob::SaveResult SubmitDocWithId(
+ const LocalPrintJob& job,
+ const std::string& job_id,
+ int* expires_in,
std::string* error_description,
int* timeout) OVERRIDE;
- virtual void GetJobStatus(int job_id) OVERRIDE;
+ virtual bool GetJobState(const std::string& id,
+ LocalPrintJob::Info* info) OVERRIDE;
// CloudRequester::Delegate methods:
virtual void OnRegistrationStartResponseParsed(
diff --git a/cloud_print/gcp20/prototype/privet_http_server.cc b/cloud_print/gcp20/prototype/privet_http_server.cc
index cb34b9a..4251a4fe 100644
--- a/cloud_print/gcp20/prototype/privet_http_server.cc
+++ b/cloud_print/gcp20/prototype/privet_http_server.cc
@@ -52,15 +52,36 @@ scoped_ptr<base::DictionaryValue> CreateErrorWithTimeout(
return error.Pass();
}
+// Converts state to string.
+std::string LocalPrintJobStateToString(LocalPrintJob::State state) {
+ switch (state) {
+ case LocalPrintJob::STATE_DRAFT:
+ return "draft";
+ break;
+ case LocalPrintJob::STATE_ABORTED:
+ return "done";
+ break;
+ case LocalPrintJob::STATE_DONE:
+ return "done";
+ break;
+ default:
+ NOTREACHED();
+ return std::string();
+ }
+}
+
+
// Returns |true| if |request| should be GET method.
bool IsGetMethod(const std::string& request) {
return request == kPrivetInfo ||
- request == kPrivetCapabilities;
+ request == kPrivetCapabilities ||
+ request == kPrivetPrinterJobState;
}
// Returns |true| if |request| should be POST method.
bool IsPostMethod(const std::string& request) {
return request == kPrivetRegister ||
+ request == kPrivetPrinterCreateJob ||
request == kPrivetPrinterSubmitDoc;
}
@@ -191,8 +212,12 @@ net::HttpStatusCode PrivetHttpServer::ProcessHttpRequest(
json_response = ProcessRegister(url, &status_code);
} else if (url.path() == kPrivetCapabilities) {
json_response = ProcessCapabilities(&status_code);
+ } else if (url.path() == kPrivetPrinterCreateJob) {
+ json_response = ProcessCreateJob(url, info.data, &status_code);
} else if (url.path() == kPrivetPrinterSubmitDoc) {
json_response = ProcessSubmitDoc(url, info, &status_code);
+ } else if (url.path() == kPrivetPrinterJobState) {
+ json_response = ProcessJobState(url, &status_code);
} else {
NOTREACHED();
}
@@ -255,6 +280,45 @@ scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessCapabilities(
return delegate_->GetCapabilities();
}
+scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessCreateJob(
+ const GURL& url,
+ const std::string& body,
+ net::HttpStatusCode* status_code) const {
+ if (!delegate_->IsRegistered() || !delegate_->IsLocalPrintingAllowed()) {
+ *status_code = net::HTTP_NOT_FOUND;
+ return scoped_ptr<base::DictionaryValue>();
+ }
+
+ std::string job_id;
+ // TODO(maksymb): Use base::Time for expiration
+ int expires_in = 0;
+ // TODO(maksymb): Use base::TimeDelta for timeout values
+ int error_timeout = -1;
+ std::string error_description;
+
+ LocalPrintJob::CreateResult result =
+ delegate_->CreateJob(body, &job_id, &expires_in,
+ &error_timeout, &error_description);
+
+ scoped_ptr<base::DictionaryValue> response;
+ *status_code = net::HTTP_OK;
+ switch (result) {
+ case LocalPrintJob::CREATE_SUCCESS:
+ response.reset(new DictionaryValue);
+ response->SetString("job_id", job_id);
+ response->SetInteger("expires_in", expires_in);
+ return response.Pass();
+
+ case LocalPrintJob::CREATE_INVALID_TICKET:
+ return CreateError("invalid_ticket");
+ case LocalPrintJob::CREATE_PRINTER_BUSY:
+ return CreateErrorWithTimeout("printer_busy", error_timeout);
+ case LocalPrintJob::CREATE_PRINTER_ERROR:
+ return CreateErrorWithDescription("printer_error", error_description);
+ }
+ return scoped_ptr<base::DictionaryValue>();
+}
+
scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessSubmitDoc(
const GURL& url,
const net::HttpServerRequestInfo& info,
@@ -264,24 +328,31 @@ scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessSubmitDoc(
return scoped_ptr<base::DictionaryValue>();
}
+ using net::GetValueForKeyInQuery;
+
// Parse query
LocalPrintJob job;
std::string offline;
- net::GetValueForKeyInQuery(url, "client_name", &job.client_name);
- bool job_name_present =
- net::GetValueForKeyInQuery(url, "job_name", &job.job_name);
- net::GetValueForKeyInQuery(url, "user_name", &job.user_name);
- net::GetValueForKeyInQuery(url, "offline", &offline);
+ std::string job_id;
+ bool job_name_present = GetValueForKeyInQuery(url, "job_name", &job.job_name);
+ bool job_id_present = GetValueForKeyInQuery(url, "job_id", &job_id);
+ GetValueForKeyInQuery(url, "client_name", &job.client_name);
+ GetValueForKeyInQuery(url, "user_name", &job.user_name);
+ GetValueForKeyInQuery(url, "offline", &offline);
job.offline = (offline == "1");
job.content_type = info.GetHeaderValue("content-type");
job.content = info.data;
// Call delegate
- std::string job_id;
+ // TODO(maksymb): Use base::Time for expiration
+ int expires_in = 0;
std::string error_description;
int timeout;
- LocalPrintJob::SaveResult status =
- delegate_->SubmitDoc(job, &job_id, &error_description, &timeout);
+ LocalPrintJob::SaveResult status = job_id_present
+ ? delegate_->SubmitDocWithId(job, job_id, &expires_in,
+ &error_description, &timeout)
+ : delegate_->SubmitDoc(job, &job_id, &expires_in,
+ &error_description, &timeout);
// Create response
*status_code = net::HTTP_OK;
@@ -289,7 +360,7 @@ scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessSubmitDoc(
switch (status) {
case LocalPrintJob::SAVE_SUCCESS:
response->SetString("job_id", job_id);
- response->SetInteger("expires_in", -1);
+ response->SetInteger("expires_in", expires_in);
response->SetString("job_type", job.content_type);
response->SetString(
"job_size",
@@ -299,7 +370,7 @@ scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessSubmitDoc(
return response.Pass();
case LocalPrintJob::SAVE_INVALID_PRINT_JOB:
- return CreateError("invalid_print_job");
+ return CreateErrorWithTimeout("invalid_print_job", timeout);
case LocalPrintJob::SAVE_INVALID_DOCUMENT_TYPE:
return CreateError("invalid_document_type");
case LocalPrintJob::SAVE_INVALID_DOCUMENT:
@@ -316,6 +387,27 @@ scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessSubmitDoc(
}
}
+scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessJobState(
+ const GURL& url,
+ net::HttpStatusCode* status_code) const {
+ if (!delegate_->IsRegistered() || !delegate_->IsLocalPrintingAllowed()) {
+ *status_code = net::HTTP_NOT_FOUND;
+ return scoped_ptr<base::DictionaryValue>();
+ }
+
+ std::string job_id;
+ net::GetValueForKeyInQuery(url, "job_id", &job_id);
+ LocalPrintJob::Info info;
+ if (!delegate_->GetJobState(job_id, &info))
+ return CreateError("invalid_print_job");
+
+ scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue);
+ response->SetString("job_id", job_id);
+ response->SetString("state", LocalPrintJobStateToString(info.state));
+ response->SetInteger("expires_in", info.expires_in);
+ return response.Pass();
+}
+
scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessRegister(
const GURL& url,
net::HttpStatusCode* status_code) const {
diff --git a/cloud_print/gcp20/prototype/privet_http_server.h b/cloud_print/gcp20/prototype/privet_http_server.h
index db113de..eb082c6 100644
--- a/cloud_print/gcp20/prototype/privet_http_server.h
+++ b/cloud_print/gcp20/prototype/privet_http_server.h
@@ -98,17 +98,33 @@ class PrivetHttpServer: public net::HttpServer::Delegate {
virtual scoped_ptr<base::DictionaryValue> GetCapabilities() = 0;
// Invoked for creating a job.
- virtual void CreateJob(const std::string& ticket) = 0;
+ virtual LocalPrintJob::CreateResult CreateJob(
+ const std::string& ticket,
+ std::string* job_id,
+ int* expires_in,
+ // TODO(maksymb): Use base::TimeDelta for timeouts
+ int* error_timeout,
+ std::string* error_description) = 0;
// Invoked for simple local printing.
virtual LocalPrintJob::SaveResult SubmitDoc(
const LocalPrintJob& job,
std::string* job_id,
+ int* expires_in,
+ std::string* error_description,
+ int* timeout) = 0;
+
+ // Invoked for advanced local printing.
+ virtual LocalPrintJob::SaveResult SubmitDocWithId(
+ const LocalPrintJob& job,
+ const std::string& job_id,
+ int* expires_in,
std::string* error_description,
int* timeout) = 0;
// Invoked for getting job status.
- virtual void GetJobStatus(int job_id) = 0;
+ virtual bool GetJobState(const std::string& job_id,
+ LocalPrintJob::Info* info) = 0;
};
// Constructor doesn't start server.
@@ -155,12 +171,24 @@ class PrivetHttpServer: public net::HttpServer::Delegate {
// Pivet API methods. Return reference to NULL if output should be empty.
scoped_ptr<base::DictionaryValue> ProcessInfo(
net::HttpStatusCode* status_code) const;
+
scoped_ptr<base::DictionaryValue> ProcessCapabilities(
net::HttpStatusCode* status_code) const;
+
+ scoped_ptr<base::DictionaryValue> ProcessCreateJob(
+ const GURL& url,
+ const std::string& body,
+ net::HttpStatusCode* status_code) const;
+
scoped_ptr<base::DictionaryValue> ProcessSubmitDoc(
const GURL& url,
const net::HttpServerRequestInfo& info,
net::HttpStatusCode* status_code) const;
+
+ scoped_ptr<base::DictionaryValue> ProcessJobState(
+ const GURL& url,
+ net::HttpStatusCode* status_code) const;
+
scoped_ptr<base::DictionaryValue> ProcessRegister(
const GURL& url,
net::HttpStatusCode* status_code) const;