Skip to content

Commit

Permalink
GCP2.0 Device: XMPP pings.
Browse files Browse the repository at this point in the history
BUG=

Review URL: https://chromiumcodereview.appspot.com/21916003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@216107 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
maksymb@chromium.org committed Aug 7, 2013
1 parent 06fb2c0 commit 98fae91
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 14 deletions.
90 changes: 84 additions & 6 deletions cloud_print/gcp20/prototype/cloud_print_xmpp_listener.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@

#include "cloud_print/gcp20/prototype/cloud_print_xmpp_listener.h"

#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/rand_util.h"
#include "base/single_thread_task_runner.h"
#include "cloud_print/gcp20/prototype/cloud_print_url_request_context_getter.h"
#include "jingle/notifier/base/notifier_options.h"
#include "jingle/notifier/listener/push_client.h"

namespace {

const int kUrgentPingInterval = 60; // in seconds
const int kPingTimeout = 30; // in seconds
const double kRandomDelayPercentage = 0.2;

const char kCloudPrintPushNotificationsSource[] = "cloudprint.google.com";

// Splits message into two parts (e.g. '<device_id>/delete' will be splitted
Expand All @@ -32,21 +39,29 @@ void TokenizeXmppMessage(const std::string& message, std::string* device_id,

CloudPrintXmppListener::CloudPrintXmppListener(
const std::string& robot_email,
int standard_ping_interval,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
Delegate* delegate)
: robot_email_(robot_email),
standard_ping_interval_(standard_ping_interval),
ping_timeouts_posted_(0),
ping_responses_pending_(0),
ping_scheduled_(false),
context_getter_(new CloudPrintURLRequestContextGetter(task_runner)),
delegate_(delegate) {
}

CloudPrintXmppListener::~CloudPrintXmppListener() {
push_client_->RemoveObserver(this);
push_client_.reset();
if (push_client_) {
push_client_->RemoveObserver(this);
push_client_.reset();
}
}

void CloudPrintXmppListener::Connect(const std::string& access_token) {
push_client_.reset();
access_token_ = access_token;
ping_responses_pending_ = 0;
ping_scheduled_ = 0;

notifier::NotifierOptions options;
options.request_context_getter = context_getter_;
Expand All @@ -66,8 +81,13 @@ void CloudPrintXmppListener::Connect(const std::string& access_token) {
push_client_->UpdateCredentials(robot_email_, access_token_);
}

void CloudPrintXmppListener::set_standard_ping_interval(int interval) {
standard_ping_interval_ = interval;
}

void CloudPrintXmppListener::OnNotificationsEnabled() {
delegate_->OnXmppConnected();
SchedulePing();
}

void CloudPrintXmppListener::OnNotificationsDisabled(
Expand All @@ -77,7 +97,7 @@ void CloudPrintXmppListener::OnNotificationsDisabled(
delegate_->OnXmppAuthError();
break;
case notifier::TRANSIENT_NOTIFICATION_ERROR:
delegate_->OnXmppNetworkError();
Disconnect();
break;
default:
NOTREACHED() << "XMPP failed with unexpected reason code: " << reason;
Expand All @@ -102,7 +122,65 @@ void CloudPrintXmppListener::OnIncomingNotification(
}

void CloudPrintXmppListener::OnPingResponse() {
// TODO(maksymb): Implement pings
NOTIMPLEMENTED();
ping_responses_pending_ = 0;
SchedulePing();
}

void CloudPrintXmppListener::Disconnect() {
push_client_.reset();
delegate_->OnXmppNetworkError();
}

void CloudPrintXmppListener::SchedulePing() {
if (ping_scheduled_)
return;

DCHECK_LE(kPingTimeout, kUrgentPingInterval);
int delay = (ping_responses_pending_ > 0)
? kUrgentPingInterval - kPingTimeout
: standard_ping_interval_;

delay += base::RandInt(0, delay*kRandomDelayPercentage);

base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&CloudPrintXmppListener::SendPing, AsWeakPtr()),
base::TimeDelta::FromSeconds(delay));

ping_scheduled_ = true;
}

void CloudPrintXmppListener::SendPing() {
ping_scheduled_ = false;

DCHECK(push_client_);
push_client_->SendPing();
++ping_responses_pending_;

base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&CloudPrintXmppListener::OnPingTimeoutReached, AsWeakPtr()),
base::TimeDelta::FromSeconds(kPingTimeout));
++ping_timeouts_posted_;
}

void CloudPrintXmppListener::OnPingTimeoutReached() {
DCHECK_GT(ping_timeouts_posted_, 0);
--ping_timeouts_posted_;
if (ping_timeouts_posted_ > 0)
return; // Fake (old) timeout.

switch (ping_responses_pending_) {
case 0:
break;
case 1:
SchedulePing();
break;
case 2:
Disconnect();
break;
default:
NOTREACHED();
}
}

42 changes: 36 additions & 6 deletions cloud_print/gcp20/prototype/cloud_print_xmpp_listener.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "jingle/notifier/listener/push_client_observer.h"

namespace base {
Expand All @@ -31,7 +32,9 @@ class PushClient;

} // namespace notifier

class CloudPrintXmppListener: public notifier::PushClientObserver {
class CloudPrintXmppListener
: public base::SupportsWeakPtr<CloudPrintXmppListener>,
public notifier::PushClientObserver {
public:
class Delegate {
public:
Expand All @@ -52,12 +55,13 @@ class CloudPrintXmppListener: public notifier::PushClientObserver {
// Invoked when local settings was updated.
virtual void OnXmppNewLocalSettings(const std::string& device_id) = 0;

// Invoked when printer was deleted from server.
// Invoked when printer was deleted from the server.
virtual void OnXmppDeleteNotification(const std::string& device_id) = 0;
};

CloudPrintXmppListener(
const std::string& robot_email,
int standard_ping_interval,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
Delegate* delegate);

Expand All @@ -66,6 +70,9 @@ class CloudPrintXmppListener: public notifier::PushClientObserver {
// Connects to the server.
void Connect(const std::string& access_token);

// Update ping interval when new local_settings was received.
void set_standard_ping_interval(int interval);

private:
// notifier::PushClientObserver methods:
virtual void OnNotificationsEnabled() OVERRIDE;
Expand All @@ -75,18 +82,41 @@ class CloudPrintXmppListener: public notifier::PushClientObserver {
const notifier::Notification& notification) OVERRIDE;
virtual void OnPingResponse() OVERRIDE;

// Is used for reconnection when number of retries is now exhausted.
void ReconnectInternal();
// Stops listening and sending pings.
void Disconnect();

// Schedules ping (unless it was already scheduled).
void SchedulePing();

// Sends ping.
void SendPing();

// Checks if ping was received.
void OnPingTimeoutReached();

// Credentials:
std::string robot_email_;
std::string access_token_;

scoped_refptr<net::URLRequestContextGetter> context_getter_;

// Internal listener.
scoped_ptr<notifier::PushClient> push_client_;

// Interval between pings in regular workflow.
int standard_ping_interval_;

// Number of timeouts posted to MessageLoop. Is used for controlling "fake"
// timeout calls.
int ping_timeouts_posted_;

// Number of responses awaiting from XMPP server. Is used for controlling
// number of failed pings.
int ping_responses_pending_;

// Is used for preventing multiple pings at the moment.
bool ping_scheduled_;

scoped_refptr<net::URLRequestContextGetter> context_getter_;

Delegate* delegate_;

DISALLOW_COPY_AND_ASSIGN(CloudPrintXmppListener);
Expand Down
7 changes: 5 additions & 2 deletions cloud_print/gcp20/prototype/printer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ const char kPrinterStatePathDefault[] = "printer_state.json";
namespace {

const uint16 kHttpPortDefault = 10101;
const uint32 kTtlDefault = 60*60;
const uint32 kTtlDefault = 60*60; // in seconds
const int kXmppPingIntervalDefault = 5*60; // in seconds

const char kServiceType[] = "_privet._tcp.local";
const char kServiceNamePrefixDefault[] = "first_gcp20_device";
Expand Down Expand Up @@ -182,6 +183,7 @@ void Printer::Stop() {
}

void Printer::OnAuthError() {
LOG(ERROR) << "Auth error occurred";
access_token_update_ = base::Time::Now();
ChangeState(OFFLINE);
// TODO(maksymb): Implement *instant* updating of access_token.
Expand Down Expand Up @@ -476,7 +478,8 @@ void Printer::TryConnect() {

void Printer::ConnectXmpp() {
xmpp_listener_.reset(
new CloudPrintXmppListener(reg_info_.xmpp_jid, GetTaskRunner(), this));
new CloudPrintXmppListener(reg_info_.xmpp_jid, kXmppPingIntervalDefault,
GetTaskRunner(), this));
xmpp_listener_->Connect(access_token_);
}

Expand Down

0 comments on commit 98fae91

Please sign in to comment.