blob: c583d440faabfa77ff4f48ea9e82e917d6b43282 [file] [log] [blame]
[email protected]24c9ee52014-06-02 22:17:501// Copyright 2014 The Chromium Authors. All rights reserved.
[email protected]08dd8312011-03-19 20:09:312// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]44828772014-06-06 02:56:525#include "components/invalidation/p2p_invalidator.h"
[email protected]08dd8312011-03-19 20:09:316
[email protected]2f15fd0e2011-08-27 05:29:097#include <algorithm>
[email protected]c014f2b32013-09-03 23:29:128#include <iterator>
[email protected]2f15fd0e2011-08-27 05:29:099
[email protected]2f15fd0e2011-08-27 05:29:0910#include "base/json/json_reader.h"
11#include "base/json/json_writer.h"
[email protected]c1c32c82012-03-15 09:35:4212#include "base/logging.h"
[email protected]2f15fd0e2011-08-27 05:29:0913#include "base/values.h"
[email protected]001bbfdc2014-07-17 19:28:4614#include "components/invalidation/invalidation_handler.h"
[email protected]51766bf2014-07-24 01:13:4715#include "components/invalidation/invalidation_util.h"
[email protected]44828772014-06-06 02:56:5216#include "components/invalidation/notifier_reason_util.h"
[email protected]001bbfdc2014-07-17 19:28:4617#include "components/invalidation/object_id_invalidation_map.h"
[email protected]6618e73f2012-05-23 05:20:4018#include "jingle/notifier/listener/push_client.h"
[email protected]08dd8312011-03-19 20:09:3119
[email protected]65f173552012-06-28 22:43:5820namespace syncer {
[email protected]08dd8312011-03-19 20:09:3121
[email protected]33596da2012-08-31 23:39:2522const char kSyncP2PNotificationChannel[] = "http://www.google.com/chrome/sync";
[email protected]2f15fd0e2011-08-27 05:29:0923
[email protected]d6fdf682011-08-27 06:53:2124namespace {
[email protected]2f15fd0e2011-08-27 05:29:0925
26const char kNotifySelf[] = "notifySelf";
27const char kNotifyOthers[] = "notifyOthers";
28const char kNotifyAll[] = "notifyAll";
29
30const char kSenderIdKey[] = "senderId";
31const char kNotificationTypeKey[] = "notificationType";
[email protected]163d0632013-10-04 03:51:0132const char kInvalidationsKey[] = "invalidations";
[email protected]2f15fd0e2011-08-27 05:29:0933
[email protected]08dd8312011-03-19 20:09:3134} // namespace
35
[email protected]2f15fd0e2011-08-27 05:29:0936std::string P2PNotificationTargetToString(P2PNotificationTarget target) {
37 switch (target) {
38 case NOTIFY_SELF:
39 return kNotifySelf;
40 case NOTIFY_OTHERS:
41 return kNotifyOthers;
42 case NOTIFY_ALL:
43 return kNotifyAll;
44 default:
45 NOTREACHED();
[email protected]007b3f82013-04-09 08:46:4546 return std::string();
[email protected]2f15fd0e2011-08-27 05:29:0947 }
48}
49
50P2PNotificationTarget P2PNotificationTargetFromString(
51 const std::string& target_str) {
52 if (target_str == kNotifySelf) {
53 return NOTIFY_SELF;
54 }
55 if (target_str == kNotifyOthers) {
56 return NOTIFY_OTHERS;
57 }
58 if (target_str == kNotifyAll) {
59 return NOTIFY_ALL;
60 }
61 LOG(WARNING) << "Could not parse " << target_str;
62 return NOTIFY_SELF;
63}
64
[email protected]33596da2012-08-31 23:39:2565P2PNotificationData::P2PNotificationData()
[email protected]0d0b59d2013-02-02 00:24:4766 : target_(NOTIFY_SELF) {}
[email protected]2f15fd0e2011-08-27 05:29:0967
68P2PNotificationData::P2PNotificationData(
69 const std::string& sender_id,
70 P2PNotificationTarget target,
[email protected]0d0b59d2013-02-02 00:24:4771 const ObjectIdInvalidationMap& invalidation_map)
[email protected]2f15fd0e2011-08-27 05:29:0972 : sender_id_(sender_id),
73 target_(target),
[email protected]0d0b59d2013-02-02 00:24:4774 invalidation_map_(invalidation_map) {}
[email protected]2f15fd0e2011-08-27 05:29:0975
76P2PNotificationData::~P2PNotificationData() {}
77
78bool P2PNotificationData::IsTargeted(const std::string& id) const {
79 switch (target_) {
80 case NOTIFY_SELF:
81 return sender_id_ == id;
82 case NOTIFY_OTHERS:
83 return sender_id_ != id;
84 case NOTIFY_ALL:
85 return true;
86 default:
87 NOTREACHED();
88 return false;
89 }
90}
91
[email protected]3e31fa42012-10-04 03:53:0992const ObjectIdInvalidationMap&
93P2PNotificationData::GetIdInvalidationMap() const {
94 return invalidation_map_;
[email protected]33596da2012-08-31 23:39:2595}
96
[email protected]2f15fd0e2011-08-27 05:29:0997bool P2PNotificationData::Equals(const P2PNotificationData& other) const {
98 return
99 (sender_id_ == other.sender_id_) &&
100 (target_ == other.target_) &&
[email protected]163d0632013-10-04 03:51:01101 (invalidation_map_ == other.invalidation_map_);
[email protected]2f15fd0e2011-08-27 05:29:09102}
103
104std::string P2PNotificationData::ToString() const {
[email protected]0c6c1e42013-06-21 19:42:19105 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
[email protected]2f15fd0e2011-08-27 05:29:09106 dict->SetString(kSenderIdKey, sender_id_);
107 dict->SetString(kNotificationTypeKey,
108 P2PNotificationTargetToString(target_));
[email protected]163d0632013-10-04 03:51:01109 dict->Set(kInvalidationsKey, invalidation_map_.ToValue().release());
[email protected]2f15fd0e2011-08-27 05:29:09110 std::string json;
[email protected]4abb4602012-03-16 01:59:55111 base::JSONWriter::Write(dict.get(), &json);
[email protected]2f15fd0e2011-08-27 05:29:09112 return json;
113}
114
115bool P2PNotificationData::ResetFromString(const std::string& str) {
[email protected]0c6c1e42013-06-21 19:42:19116 scoped_ptr<base::Value> data_value(base::JSONReader::Read(str));
[email protected]33596da2012-08-31 23:39:25117 const base::DictionaryValue* data_dict = NULL;
118 if (!data_value.get() || !data_value->GetAsDictionary(&data_dict)) {
[email protected]2f15fd0e2011-08-27 05:29:09119 LOG(WARNING) << "Could not parse " << str << " as a dictionary";
120 return false;
121 }
[email protected]2f15fd0e2011-08-27 05:29:09122 if (!data_dict->GetString(kSenderIdKey, &sender_id_)) {
123 LOG(WARNING) << "Could not find string value for " << kSenderIdKey;
124 }
125 std::string target_str;
126 if (!data_dict->GetString(kNotificationTypeKey, &target_str)) {
127 LOG(WARNING) << "Could not find string value for "
128 << kNotificationTypeKey;
129 }
130 target_ = P2PNotificationTargetFromString(target_str);
[email protected]3e31fa42012-10-04 03:53:09131 const base::ListValue* invalidation_map_list = NULL;
[email protected]163d0632013-10-04 03:51:01132 if (!data_dict->GetList(kInvalidationsKey, &invalidation_map_list) ||
133 !invalidation_map_.ResetFromValue(*invalidation_map_list)) {
134 LOG(WARNING) << "Could not parse " << kInvalidationsKey;
[email protected]2f15fd0e2011-08-27 05:29:09135 }
[email protected]2f15fd0e2011-08-27 05:29:09136 return true;
137}
138
[email protected]a329cb82012-08-28 03:17:58139P2PInvalidator::P2PInvalidator(scoped_ptr<notifier::PushClient> push_client,
[email protected]d5511232013-03-28 01:34:54140 const std::string& invalidator_client_id,
[email protected]a329cb82012-08-28 03:17:58141 P2PNotificationTarget send_notification_target)
[email protected]6618e73f2012-05-23 05:20:40142 : push_client_(push_client.Pass()),
[email protected]d5511232013-03-28 01:34:54143 invalidator_client_id_(invalidator_client_id),
[email protected]08dd8312011-03-19 20:09:31144 logged_in_(false),
[email protected]09fb6e82011-04-07 00:08:14145 notifications_enabled_(false),
[email protected]6618e73f2012-05-23 05:20:40146 send_notification_target_(send_notification_target) {
[email protected]c7b7610da2011-09-30 01:49:16147 DCHECK(send_notification_target_ == NOTIFY_OTHERS ||
148 send_notification_target_ == NOTIFY_ALL);
[email protected]6618e73f2012-05-23 05:20:40149 push_client_->AddObserver(this);
[email protected]08dd8312011-03-19 20:09:31150}
151
[email protected]a329cb82012-08-28 03:17:58152P2PInvalidator::~P2PInvalidator() {
[email protected]327e52b2012-06-25 21:11:36153 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]6618e73f2012-05-23 05:20:40154 push_client_->RemoveObserver(this);
[email protected]09fb6e82011-04-07 00:08:14155}
[email protected]08dd8312011-03-19 20:09:31156
[email protected]a329cb82012-08-28 03:17:58157void P2PInvalidator::RegisterHandler(InvalidationHandler* handler) {
[email protected]85b25eb2012-08-10 19:32:08158 DCHECK(thread_checker_.CalledOnValidThread());
159 registrar_.RegisterHandler(handler);
160}
161
[email protected]a329cb82012-08-28 03:17:58162void P2PInvalidator::UpdateRegisteredIds(InvalidationHandler* handler,
[email protected]163d0632013-10-04 03:51:01163 const ObjectIdSet& ids) {
[email protected]85b25eb2012-08-10 19:32:08164 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]33596da2012-08-31 23:39:25165 ObjectIdSet new_ids;
166 const ObjectIdSet& old_ids = registrar_.GetRegisteredIds(handler);
167 std::set_difference(ids.begin(), ids.end(),
168 old_ids.begin(), old_ids.end(),
169 std::inserter(new_ids, new_ids.end()),
170 ObjectIdLessThan());
[email protected]85b25eb2012-08-10 19:32:08171 registrar_.UpdateRegisteredIds(handler, ids);
[email protected]d914f022012-07-27 02:02:00172 const P2PNotificationData notification_data(
[email protected]007b3f82013-04-09 08:46:45173 invalidator_client_id_,
[email protected]163d0632013-10-04 03:51:01174 send_notification_target_,
175 ObjectIdInvalidationMap::InvalidateAll(ids));
[email protected]d914f022012-07-27 02:02:00176 SendNotificationData(notification_data);
[email protected]08dd8312011-03-19 20:09:31177}
178
[email protected]a329cb82012-08-28 03:17:58179void P2PInvalidator::UnregisterHandler(InvalidationHandler* handler) {
[email protected]85b25eb2012-08-10 19:32:08180 DCHECK(thread_checker_.CalledOnValidThread());
181 registrar_.UnregisterHandler(handler);
182}
183
[email protected]08a6f9992012-09-07 19:19:16184InvalidatorState P2PInvalidator::GetInvalidatorState() const {
185 DCHECK(thread_checker_.CalledOnValidThread());
186 return registrar_.GetInvalidatorState();
187}
188
[email protected]a329cb82012-08-28 03:17:58189void P2PInvalidator::UpdateCredentials(
[email protected]08dd8312011-03-19 20:09:31190 const std::string& email, const std::string& token) {
[email protected]327e52b2012-06-25 21:11:36191 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]fc4386862012-05-17 02:11:48192 notifier::Subscription subscription;
193 subscription.channel = kSyncP2PNotificationChannel;
194 // There may be some subtle issues around case sensitivity of the
195 // from field, but it doesn't matter too much since this is only
196 // used in p2p mode (which is only used in testing).
197 subscription.from = email;
[email protected]6618e73f2012-05-23 05:20:40198 push_client_->UpdateSubscriptions(
[email protected]fc4386862012-05-17 02:11:48199 notifier::SubscriptionList(1, subscription));
[email protected]08dd8312011-03-19 20:09:31200 // If already logged in, the new credentials will take effect on the
201 // next reconnection.
[email protected]6618e73f2012-05-23 05:20:40202 push_client_->UpdateCredentials(email, token);
[email protected]fc4386862012-05-17 02:11:48203 logged_in_ = true;
[email protected]08dd8312011-03-19 20:09:31204}
205
[email protected]5cb5b182014-03-18 00:32:39206void P2PInvalidator::RequestDetailedStatus(
[email protected]40848a92014-03-24 22:41:02207 base::Callback<void(const base::DictionaryValue&)> callback) const {
[email protected]5cb5b182014-03-18 00:32:39208 DCHECK(thread_checker_.CalledOnValidThread());
209 // TODO(mferreria): Make the P2P Invalidator work.
210 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
211 callback.Run(*value);
212}
213
[email protected]163d0632013-10-04 03:51:01214void P2PInvalidator::SendInvalidation(const ObjectIdSet& ids) {
[email protected]327e52b2012-06-25 21:11:36215 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]163d0632013-10-04 03:51:01216 ObjectIdInvalidationMap invalidation_map =
217 ObjectIdInvalidationMap::InvalidateAll(ids);
[email protected]2f15fd0e2011-08-27 05:29:09218 const P2PNotificationData notification_data(
[email protected]d5511232013-03-28 01:34:54219 invalidator_client_id_, send_notification_target_, invalidation_map);
[email protected]2f15fd0e2011-08-27 05:29:09220 SendNotificationData(notification_data);
[email protected]08dd8312011-03-19 20:09:31221}
222
[email protected]a329cb82012-08-28 03:17:58223void P2PInvalidator::OnNotificationsEnabled() {
[email protected]327e52b2012-06-25 21:11:36224 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]2d3d1d12012-06-18 20:50:28225 bool just_turned_on = (notifications_enabled_ == false);
226 notifications_enabled_ = true;
[email protected]08a6f9992012-09-07 19:19:16227 registrar_.UpdateInvalidatorState(INVALIDATIONS_ENABLED);
[email protected]2d3d1d12012-06-18 20:50:28228 if (just_turned_on) {
[email protected]2f15fd0e2011-08-27 05:29:09229 const P2PNotificationData notification_data(
[email protected]007b3f82013-04-09 08:46:45230 invalidator_client_id_,
231 NOTIFY_SELF,
[email protected]163d0632013-10-04 03:51:01232 ObjectIdInvalidationMap::InvalidateAll(
233 registrar_.GetAllRegisteredIds()));
[email protected]2f15fd0e2011-08-27 05:29:09234 SendNotificationData(notification_data);
235 }
[email protected]08dd8312011-03-19 20:09:31236}
237
[email protected]a329cb82012-08-28 03:17:58238void P2PInvalidator::OnNotificationsDisabled(
[email protected]2d3d1d12012-06-18 20:50:28239 notifier::NotificationsDisabledReason reason) {
[email protected]327e52b2012-06-25 21:11:36240 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]08a6f9992012-09-07 19:19:16241 registrar_.UpdateInvalidatorState(FromNotifierReason(reason));
[email protected]2d3d1d12012-06-18 20:50:28242}
243
[email protected]a329cb82012-08-28 03:17:58244void P2PInvalidator::OnIncomingNotification(
[email protected]08dd8312011-03-19 20:09:31245 const notifier::Notification& notification) {
[email protected]327e52b2012-06-25 21:11:36246 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]060588c2011-11-29 21:38:41247 DVLOG(1) << "Received notification " << notification.ToString();
[email protected]08dd8312011-03-19 20:09:31248 if (!logged_in_) {
[email protected]060588c2011-11-29 21:38:41249 DVLOG(1) << "Not logged in yet -- not emitting notification";
[email protected]08dd8312011-03-19 20:09:31250 return;
251 }
252 if (!notifications_enabled_) {
[email protected]2d3d1d12012-06-18 20:50:28253 DVLOG(1) << "Notifications not on -- not emitting notification";
[email protected]08dd8312011-03-19 20:09:31254 return;
255 }
[email protected]d6fdf682011-08-27 06:53:21256 if (notification.channel != kSyncP2PNotificationChannel) {
[email protected]2f15fd0e2011-08-27 05:29:09257 LOG(WARNING) << "Notification from unexpected source "
258 << notification.channel;
259 }
260 P2PNotificationData notification_data;
261 if (!notification_data.ResetFromString(notification.data)) {
262 LOG(WARNING) << "Could not parse notification data from "
263 << notification.data;
[email protected]007b3f82013-04-09 08:46:45264 notification_data = P2PNotificationData(
265 invalidator_client_id_,
266 NOTIFY_ALL,
[email protected]163d0632013-10-04 03:51:01267 ObjectIdInvalidationMap::InvalidateAll(
268 registrar_.GetAllRegisteredIds()));
[email protected]2f15fd0e2011-08-27 05:29:09269 }
[email protected]d5511232013-03-28 01:34:54270 if (!notification_data.IsTargeted(invalidator_client_id_)) {
[email protected]060588c2011-11-29 21:38:41271 DVLOG(1) << "Not a target of the notification -- "
272 << "not emitting notification";
[email protected]08dd8312011-03-19 20:09:31273 return;
274 }
[email protected]85b25eb2012-08-10 19:32:08275 registrar_.DispatchInvalidationsToHandlers(
[email protected]0d0b59d2013-02-02 00:24:47276 notification_data.GetIdInvalidationMap());
[email protected]08dd8312011-03-19 20:09:31277}
278
[email protected]a329cb82012-08-28 03:17:58279void P2PInvalidator::SendNotificationDataForTest(
[email protected]2f15fd0e2011-08-27 05:29:09280 const P2PNotificationData& notification_data) {
[email protected]327e52b2012-06-25 21:11:36281 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]2f15fd0e2011-08-27 05:29:09282 SendNotificationData(notification_data);
283}
284
[email protected]a329cb82012-08-28 03:17:58285void P2PInvalidator::SendNotificationData(
[email protected]2f15fd0e2011-08-27 05:29:09286 const P2PNotificationData& notification_data) {
[email protected]327e52b2012-06-25 21:11:36287 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]163d0632013-10-04 03:51:01288 if (notification_data.GetIdInvalidationMap().Empty()) {
[email protected]33596da2012-08-31 23:39:25289 DVLOG(1) << "Not sending XMPP notification with empty state map: "
[email protected]177bcf22012-07-26 03:13:46290 << notification_data.ToString();
291 return;
292 }
[email protected]2f15fd0e2011-08-27 05:29:09293 notifier::Notification notification;
[email protected]d6fdf682011-08-27 06:53:21294 notification.channel = kSyncP2PNotificationChannel;
[email protected]2f15fd0e2011-08-27 05:29:09295 notification.data = notification_data.ToString();
[email protected]060588c2011-11-29 21:38:41296 DVLOG(1) << "Sending XMPP notification: " << notification.ToString();
[email protected]6618e73f2012-05-23 05:20:40297 push_client_->SendNotification(notification);
[email protected]2f15fd0e2011-08-27 05:29:09298}
299
[email protected]65f173552012-06-28 22:43:58300} // namespace syncer