Index: cloud_print/gcp20/prototype/printer.cc |
diff --git a/cloud_print/gcp20/prototype/printer.cc b/cloud_print/gcp20/prototype/printer.cc |
index 2a0086b3b9f31405fefc8dc547d55d2c656f85ff..b6ff2c4182f0753c45cae9e038fd5e91f77b6e4f 100644 |
--- a/cloud_print/gcp20/prototype/printer.cc |
+++ b/cloud_print/gcp20/prototype/printer.cc |
@@ -42,7 +42,8 @@ const char kUserConfirmationTitle[] = "Confirm registration: type 'y' if you " |
const int64 kUserConfirmationTimeout = 30; // in seconds |
const uint32 kReconnectTimeout = 5; // in seconds |
-const uint32 kPrintJobsTimeout = 10; // in seconds |
+ |
+const double kTimeToNextAccessTokenUpdate = 0.8; // relatively to living time. |
const char kCdd[] = |
"{\n" |
@@ -98,6 +99,10 @@ net::IPAddressNumber GetLocalIp(const std::string& interface_name, |
return net::IPAddressNumber(); |
} |
+scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() { |
+ return base::MessageLoop::current()->message_loop_proxy(); |
+} |
+ |
} // namespace |
using cloud_print_response_parser::Job; |
@@ -110,7 +115,12 @@ Printer::RegistrationInfo::RegistrationInfo() |
Printer::RegistrationInfo::~RegistrationInfo() { |
} |
-Printer::Printer() : http_server_(this), connection_state_(OFFLINE) { |
+Printer::Printer() |
+ : http_server_(this), |
+ connection_state_(OFFLINE), |
+ on_idle_posted_(false), |
+ pending_local_settings_check_(false), |
+ pending_print_jobs_check_(false) { |
} |
Printer::~Printer() { |
@@ -118,7 +128,7 @@ Printer::~Printer() { |
} |
bool Printer::Start() { |
- if (IsOnline()) |
+ if (IsRunning()) |
return true; |
// TODO(maksymb): Add switch for command line to control interface name. |
@@ -152,33 +162,16 @@ bool Printer::Start() { |
return false; |
} |
- // Creating Cloud Requester. |
- requester_.reset( |
- new CloudPrintRequester( |
- base::MessageLoop::current()->message_loop_proxy(), |
- this)); |
- |
+ print_job_handler_.reset(new PrintJobHandler); |
xtoken_ = XPrivetToken(); |
starttime_ = base::Time::Now(); |
- print_job_handler_.reset(new PrintJobHandler); |
- connection_state_ = CONNECTING; |
- WakeUp(); |
- |
+ TryConnect(); |
return true; |
} |
-bool Printer::IsOnline() const { |
- return requester_; |
-} |
- |
-void Printer::WakeUp() { |
- VLOG(3) << "Function: " << __FUNCTION__; |
- |
- if (!IsRegistered()) |
- return; |
- |
- FetchPrintJobs(); |
+bool Printer::IsRunning() const { |
+ return print_job_handler_; |
} |
void Printer::Stop() { |
@@ -186,6 +179,17 @@ void Printer::Stop() { |
http_server_.Shutdown(); |
requester_.reset(); |
print_job_handler_.reset(); |
+ xmpp_listener_.reset(); |
+} |
+ |
+void Printer::OnAuthError() { |
+ access_token_update_ = base::Time::Now(); |
+ ChangeState(OFFLINE); |
+ // TODO(maksymb): Implement *instant* updating of access_token. |
+} |
+ |
+std::string Printer::GetAccessToken() { |
+ return access_token_; |
} |
PrivetHttpServer::RegistrationErrorStatus Printer::RegistrationStart( |
@@ -285,9 +289,7 @@ PrivetHttpServer::RegistrationErrorStatus Printer::RegistrationCancel( |
return PrivetHttpServer::REG_ERROR_INVALID_ACTION; |
reg_info_ = RegistrationInfo(); |
- requester_.reset(new CloudPrintRequester( |
- base::MessageLoop::current()->message_loop_proxy(), |
- this)); // Forget all old queries. |
+ requester_.reset(new CloudPrintRequester(GetTaskRunner(), this)); |
return PrivetHttpServer::REG_ERROR_OK; |
} |
@@ -342,11 +344,36 @@ void Printer::OnRegistrationStartResponseParsed( |
reg_info_.complete_invite_url = complete_invite_url; |
} |
-void Printer::OnGetAuthCodeResponseParsed(const std::string& refresh_token) { |
+void Printer::OnGetAuthCodeResponseParsed(const std::string& refresh_token, |
+ const std::string& access_token, |
+ int access_token_expires_in_seconds) { |
reg_info_.state = RegistrationInfo::DEV_REG_REGISTERED; |
reg_info_.refresh_token = refresh_token; |
- SaveToFile(base::FilePath(kPrinterStatePath)); |
- FetchPrintJobs(); |
+ RememberAccessToken(access_token, access_token_expires_in_seconds); |
+ |
+ ConnectXmpp(); |
+} |
+ |
+void Printer::OnAccesstokenReceviced(const std::string& access_token, |
+ int expires_in_seconds) { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ RememberAccessToken(access_token, expires_in_seconds); |
+ switch (connection_state_) { |
+ case ONLINE: |
+ PostOnIdle(); |
+ break; |
+ |
+ case CONNECTING: |
+ TryConnect(); |
+ break; |
+ |
+ default: |
+ NOTREACHED(); |
+ } |
+} |
+ |
+void Printer::OnXmppJidReceived(const std::string& xmpp_jid) { |
+ reg_info_.xmpp_jid = xmpp_jid; |
} |
void Printer::OnRegistrationError(const std::string& description) { |
@@ -357,32 +384,30 @@ void Printer::OnRegistrationError(const std::string& description) { |
reg_info_.error_description = description; |
} |
-void Printer::OnServerError(const std::string& description) { |
+void Printer::OnNetworkError() { |
VLOG(3) << "Function: " << __FUNCTION__; |
- LOG(ERROR) << "Server error: " << description; |
- |
- PostDelayedWakeUp(base::TimeDelta::FromSeconds(kReconnectTimeout)); |
+ ChangeState(OFFLINE); |
} |
-void Printer::OnNetworkError() { |
+void Printer::OnServerError(const std::string& description) { |
VLOG(3) << "Function: " << __FUNCTION__; |
+ LOG(ERROR) << "Server error: " << description; |
+ |
ChangeState(OFFLINE); |
- PostDelayedWakeUp(base::TimeDelta::FromSeconds(kReconnectTimeout)); |
} |
void Printer::OnPrintJobsAvailable(const std::vector<Job>& jobs) { |
VLOG(3) << "Function: " << __FUNCTION__; |
- ChangeState(ONLINE); |
LOG(INFO) << "Available printjobs: " << jobs.size(); |
if (jobs.empty()) { |
- PostDelayedWakeUp(base::TimeDelta::FromSeconds(kPrintJobsTimeout)); |
+ pending_print_jobs_check_ = false; |
+ PostOnIdle(); |
return; |
} |
- // TODO(maksymb): After finishing XMPP add 'Printjobs available' flag. |
- LOG(INFO) << "Downloading first printjob."; |
+ LOG(INFO) << "Downloading printjob."; |
requester_->RequestPrintJob(jobs[0]); |
return; |
} |
@@ -399,8 +424,121 @@ void Printer::OnPrintJobDownloaded(const Job& job) { |
void Printer::OnPrintJobDone() { |
VLOG(3) << "Function: " << __FUNCTION__; |
- // TODO(maksymb): Replace PostTask with with XMPP notifications. |
- PostWakeUp(); |
+ PostOnIdle(); |
+} |
+ |
+void Printer::OnXmppConnected() { |
+ pending_local_settings_check_ = true; |
+ pending_print_jobs_check_ = true; |
+ ChangeState(ONLINE); |
+ PostOnIdle(); |
+} |
+ |
+void Printer::OnXmppAuthError() { |
+ OnAuthError(); |
+} |
+ |
+void Printer::OnXmppNetworkError() { |
+ ChangeState(OFFLINE); |
+} |
+ |
+void Printer::OnXmppNewPrintJob(const std::string& device_id) { |
+ DCHECK_EQ(reg_info_.device_id, device_id) << "Data should contain printer_id"; |
+ pending_print_jobs_check_ = true; |
+} |
+ |
+void Printer::OnXmppNewLocalSettings(const std::string& device_id) { |
+ DCHECK_EQ(reg_info_.device_id, device_id) << "Data should contain printer_id"; |
+ NOTIMPLEMENTED(); |
+} |
+ |
+void Printer::OnXmppDeleteNotification(const std::string& device_id) { |
+ DCHECK_EQ(reg_info_.device_id, device_id) << "Data should contain printer_id"; |
+ NOTIMPLEMENTED(); |
+} |
+ |
+void Printer::TryConnect() { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ |
+ ChangeState(CONNECTING); |
+ if (!requester_) |
+ requester_.reset(new CloudPrintRequester(GetTaskRunner(), this)); |
+ |
+ if (IsRegistered()) { |
+ if (access_token_update_ < base::Time::Now()) { |
+ requester_->UpdateAccesstoken(reg_info_.refresh_token); |
+ } else { |
+ ConnectXmpp(); |
+ } |
+ } else { |
+ // TODO(maksymb): Ping google.com to check connection state. |
+ ChangeState(ONLINE); |
+ } |
+} |
+ |
+void Printer::ConnectXmpp() { |
+ xmpp_listener_.reset( |
+ new CloudPrintXmppListener(reg_info_.xmpp_jid, GetTaskRunner(), this)); |
+ xmpp_listener_->Connect(access_token_); |
+} |
+ |
+void Printer::OnIdle() { |
+ DCHECK(IsRegistered()); |
+ DCHECK(on_idle_posted_) << "Instant call is not allowed"; |
+ on_idle_posted_ = false; |
+ |
+ if (connection_state_ != ONLINE) |
+ return; |
+ |
+ if (access_token_update_ < base::Time::Now()) { |
+ requester_->UpdateAccesstoken(reg_info_.refresh_token); |
+ return; |
+ } |
+ |
+ // TODO(maksymb): Check if privet-accesstoken was requested. |
+ |
+ // TODO(maksymb): Check if local-printing was requested. |
+ |
+ if (pending_local_settings_check_) { |
+ GetLocalSettings(); |
+ return; |
+ } |
+ |
+ if (pending_print_jobs_check_) { |
+ FetchPrintJobs(); |
+ return; |
+ } |
+ |
+ base::MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, |
+ base::Bind(&Printer::PostOnIdle, AsWeakPtr()), |
+ base::TimeDelta::FromMilliseconds(1000)); |
+} |
+ |
+void Printer::GetLocalSettings() { |
+ DCHECK(IsRegistered()); |
+ |
+ pending_local_settings_check_ = false; |
+ PostOnIdle(); |
+} |
+ |
+void Printer::FetchPrintJobs() { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ |
+ DCHECK(IsRegistered()); |
+ requester_->FetchPrintJobs(reg_info_.device_id); |
+} |
+ |
+void Printer::RememberAccessToken(const std::string& access_token, |
+ int expires_in_seconds) { |
+ using base::Time; |
+ using base::TimeDelta; |
+ access_token_ = access_token; |
+ int64 time_to_update = static_cast<int64>(expires_in_seconds * |
+ kTimeToNextAccessTokenUpdate); |
+ access_token_update_ = Time::Now() + TimeDelta::FromSeconds(time_to_update); |
+ VLOG(1) << "Current access_token: " << access_token; |
+ SaveToFile(base::FilePath(kPrinterStatePath)); |
} |
PrivetHttpServer::RegistrationErrorStatus Printer::CheckCommonRegErrors( |
@@ -460,19 +598,6 @@ std::vector<std::string> Printer::CreateTxt() const { |
return txt; |
} |
-void Printer::FetchPrintJobs() { |
- VLOG(3) << "Function: " << __FUNCTION__; |
- |
- if (!IsRegistered()) |
- return; |
- |
- if (requester_->IsBusy()) { |
- PostDelayedWakeUp(base::TimeDelta::FromSeconds(kReconnectTimeout)); |
- } else { |
- requester_->FetchPrintJobs(reg_info_.refresh_token, reg_info_.device_id); |
- } |
-} |
- |
void Printer::SaveToFile(const base::FilePath& file_path) const { |
base::DictionaryValue json; |
// TODO(maksymb): Get rid of in-place constants. |
@@ -481,6 +606,10 @@ void Printer::SaveToFile(const base::FilePath& file_path) const { |
json.SetString("user", reg_info_.user); |
json.SetString("device_id", reg_info_.device_id); |
json.SetString("refresh_token", reg_info_.refresh_token); |
+ json.SetString("xmpp_jid", reg_info_.xmpp_jid); |
+ json.SetString("access_token", access_token_); |
+ json.SetInteger("access_token_update", |
+ static_cast<int>(access_token_update_.ToTimeT())); |
} else { |
json.SetBoolean("registered", false); |
} |
@@ -497,10 +626,8 @@ void Printer::SaveToFile(const base::FilePath& file_path) const { |
} |
bool Printer::LoadFromFile(const base::FilePath& file_path) { |
- if (!base::PathExists(file_path)) { |
- LOG(INFO) << "Registration info is not found. Printer is unregistered."; |
+ if (!base::PathExists(file_path)) |
return false; |
- } |
LOG(INFO) << "Loading registration info from file."; |
std::string json_str; |
@@ -545,28 +672,45 @@ bool Printer::LoadFromFile(const base::FilePath& file_path) { |
return false; |
} |
+ std::string xmpp_jid; |
+ if (!json->GetString("xmpp_jid", &xmpp_jid)) { |
+ LOG(ERROR) << "Cannot parse |xmpp_jid|."; |
+ return false; |
+ } |
+ |
+ std::string access_token; |
+ if (!json->GetString("access_token", &access_token)) { |
+ LOG(ERROR) << "Cannot parse |access_token|."; |
+ return false; |
+ } |
+ |
+ int access_token_update; |
+ if (!json->GetInteger("access_token_update", &access_token_update)) { |
+ LOG(ERROR) << "Cannot parse |access_token_update|."; |
+ return false; |
+ } |
+ |
reg_info_ = RegistrationInfo(); |
reg_info_.state = RegistrationInfo::DEV_REG_REGISTERED; |
reg_info_.user = user; |
reg_info_.device_id = device_id; |
reg_info_.refresh_token = refresh_token; |
+ reg_info_.xmpp_jid = xmpp_jid; |
+ using base::Time; |
+ access_token_ = access_token; |
+ access_token_update_ = Time::FromTimeT(access_token_update); |
return true; |
} |
-void Printer::PostWakeUp() { |
+void Printer::PostOnIdle() { |
VLOG(3) << "Function: " << __FUNCTION__; |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&Printer::WakeUp, AsWeakPtr())); |
-} |
+ DCHECK(!on_idle_posted_) << "Only one instance can be posted."; |
+ on_idle_posted_ = true; |
-void Printer::PostDelayedWakeUp(const base::TimeDelta& delay) { |
- VLOG(3) << "Function: " << __FUNCTION__; |
- base::MessageLoop::current()->PostDelayedTask( |
+ base::MessageLoop::current()->PostTask( |
FROM_HERE, |
- base::Bind(&Printer::WakeUp, AsWeakPtr()), |
- delay); |
+ base::Bind(&Printer::OnIdle, AsWeakPtr())); |
} |
PrivetHttpServer::RegistrationErrorStatus |
@@ -609,9 +753,36 @@ bool Printer::ChangeState(ConnectionState new_state) { |
if (connection_state_ == new_state) |
return false; |
- VLOG(1) << "Printer is now " << ConnectionStateToString(new_state); |
connection_state_ = new_state; |
+ LOG(INFO) << base::StringPrintf( |
+ "Printer is now %s (%s)", |
+ ConnectionStateToString(connection_state_).c_str(), |
+ IsRegistered() ? "registered" : "unregistered"); |
+ |
dns_server_.UpdateMetadata(CreateTxt()); |
+ |
+ switch (connection_state_) { |
+ case CONNECTING: |
+ break; |
+ |
+ case ONLINE: |
+ break; |
+ |
+ case OFFLINE: |
+ requester_.reset(); |
+ xmpp_listener_.reset(); |
+ base::MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, |
+ base::Bind(&Printer::TryConnect, AsWeakPtr()), |
+ base::TimeDelta::FromSeconds(kReconnectTimeout)); |
+ |
+ case NOT_CONFIGURED: |
+ break; |
+ |
+ default: |
+ NOTREACHED(); |
+ } |
+ |
return true; |
} |