1a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// found in the LICENSE file. 4a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 5a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "cloud_print/gcp20/prototype/cloud_print_xmpp_listener.h" 6a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 73240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "base/bind.h" 8a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/logging.h" 93240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "base/message_loop/message_loop.h" 103240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "base/rand_util.h" 11a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/single_thread_task_runner.h" 12a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "cloud_print/gcp20/prototype/cloud_print_url_request_context_getter.h" 13a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "jingle/notifier/base/notifier_options.h" 14a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "jingle/notifier/listener/push_client.h" 15a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 16a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)namespace { 17a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 183240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochconst int kUrgentPingInterval = 60; // in seconds 193240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochconst int kPingTimeout = 30; // in seconds 203240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochconst double kRandomDelayPercentage = 0.2; 213240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 22a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)const char kCloudPrintPushNotificationsSource[] = "cloudprint.google.com"; 23a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 24a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Splits message into two parts (e.g. '<device_id>/delete' will be splitted 25a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// into '<device_id>' and '/delete'). 26a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void TokenizeXmppMessage(const std::string& message, std::string* device_id, 27a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) std::string* path) { 28a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) std::string::size_type pos = message.find('/'); 29a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (pos != std::string::npos) { 30a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *device_id = message.substr(0, pos); 31a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *path = message.substr(pos); 32a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } else { 33a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *device_id = message; 34a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) path->clear(); 35a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 36a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 37a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 38a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} // namespace 39a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 40a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)CloudPrintXmppListener::CloudPrintXmppListener( 41a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) const std::string& robot_email, 423240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch int standard_ping_interval, 43a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) scoped_refptr<base::SingleThreadTaskRunner> task_runner, 44a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) Delegate* delegate) 45a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) : robot_email_(robot_email), 463240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch standard_ping_interval_(standard_ping_interval), 473240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch ping_timeouts_posted_(0), 483240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch ping_responses_pending_(0), 493240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch ping_scheduled_(false), 50a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) context_getter_(new CloudPrintURLRequestContextGetter(task_runner)), 51a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) delegate_(delegate) { 52a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 53a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 54a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)CloudPrintXmppListener::~CloudPrintXmppListener() { 553240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (push_client_) { 563240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch push_client_->RemoveObserver(this); 573240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch push_client_.reset(); 583240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } 59a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 60a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 61a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void CloudPrintXmppListener::Connect(const std::string& access_token) { 62a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) access_token_ = access_token; 633240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch ping_responses_pending_ = 0; 643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) ping_scheduled_ = false; 65a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 66a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) notifier::NotifierOptions options; 67a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) options.request_context_getter = context_getter_; 68a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) options.auth_mechanism = "X-OAUTH2"; 69a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) options.try_ssltcp_first = true; 70a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) push_client_ = notifier::PushClient::CreateDefault(options); 71a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 72a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) notifier::Subscription subscription; 73a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) subscription.channel = kCloudPrintPushNotificationsSource; 74a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) subscription.from = kCloudPrintPushNotificationsSource; 75a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 76a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) notifier::SubscriptionList list; 77a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) list.push_back(subscription); 78a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 79a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) push_client_->UpdateSubscriptions(list); 80a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) push_client_->AddObserver(this); 81a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) push_client_->UpdateCredentials(robot_email_, access_token_); 82a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 83a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void CloudPrintXmppListener::set_ping_interval(int interval) { 853240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch standard_ping_interval_ = interval; 863240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch} 873240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 88a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void CloudPrintXmppListener::OnNotificationsEnabled() { 89a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) delegate_->OnXmppConnected(); 903240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch SchedulePing(); 91a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 92a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 93a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void CloudPrintXmppListener::OnNotificationsDisabled( 94a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) notifier::NotificationsDisabledReason reason) { 95a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) switch (reason) { 96a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case notifier::NOTIFICATION_CREDENTIALS_REJECTED: 97a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) delegate_->OnXmppAuthError(); 98a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) break; 99a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case notifier::TRANSIENT_NOTIFICATION_ERROR: 1003240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch Disconnect(); 101a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) break; 102a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) default: 103a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) NOTREACHED() << "XMPP failed with unexpected reason code: " << reason; 104a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 105a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 106a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 107a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void CloudPrintXmppListener::OnIncomingNotification( 108a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) const notifier::Notification& notification) { 109a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) std::string device_id; 110a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) std::string path; 111a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) TokenizeXmppMessage(notification.data, &device_id, &path); 112a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 113a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (path.empty() || path == "/") { 114a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) delegate_->OnXmppNewPrintJob(device_id); 115a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } else if (path == "/update_settings") { 116a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) delegate_->OnXmppNewLocalSettings(device_id); 117a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } else if (path == "/delete") { 118a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) delegate_->OnXmppDeleteNotification(device_id); 119a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } else { 120a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) LOG(ERROR) << "Cannot parse XMPP notification: " << notification.data; 121a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 122a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 123a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 124a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void CloudPrintXmppListener::OnPingResponse() { 1253240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch ping_responses_pending_ = 0; 1263240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch SchedulePing(); 1273240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch} 1283240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 1293240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochvoid CloudPrintXmppListener::Disconnect() { 1303240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch push_client_.reset(); 1313240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch delegate_->OnXmppNetworkError(); 1323240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch} 1333240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 1343240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochvoid CloudPrintXmppListener::SchedulePing() { 1353240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (ping_scheduled_) 1363240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch return; 1373240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 1383240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch DCHECK_LE(kPingTimeout, kUrgentPingInterval); 1393240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch int delay = (ping_responses_pending_ > 0) 1403240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch ? kUrgentPingInterval - kPingTimeout 1413240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch : standard_ping_interval_; 1423240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 1433240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch delay += base::RandInt(0, delay*kRandomDelayPercentage); 1443240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 1453240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch base::MessageLoop::current()->PostDelayedTask( 1463240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch FROM_HERE, 1473240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch base::Bind(&CloudPrintXmppListener::SendPing, AsWeakPtr()), 1483240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch base::TimeDelta::FromSeconds(delay)); 1493240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 1503240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch ping_scheduled_ = true; 1513240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch} 1523240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 1533240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochvoid CloudPrintXmppListener::SendPing() { 1543240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch ping_scheduled_ = false; 1553240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 1563240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch DCHECK(push_client_); 1573240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch push_client_->SendPing(); 1583240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch ++ping_responses_pending_; 1593240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 1603240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch base::MessageLoop::current()->PostDelayedTask( 1613240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch FROM_HERE, 1623240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch base::Bind(&CloudPrintXmppListener::OnPingTimeoutReached, AsWeakPtr()), 1633240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch base::TimeDelta::FromSeconds(kPingTimeout)); 1643240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch ++ping_timeouts_posted_; 1653240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch} 1663240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 1673240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochvoid CloudPrintXmppListener::OnPingTimeoutReached() { 1683240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch DCHECK_GT(ping_timeouts_posted_, 0); 1693240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch --ping_timeouts_posted_; 1703240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (ping_timeouts_posted_ > 0) 1713240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch return; // Fake (old) timeout. 1723240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 1733240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch switch (ping_responses_pending_) { 1743240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch case 0: 1753240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch break; 1763240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch case 1: 1773240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch SchedulePing(); 1783240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch break; 1793240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch case 2: 1803240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch Disconnect(); 1813240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch break; 1823240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch default: 1833240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch NOTREACHED(); 1843240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } 185a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 186a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 187