| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "sync/notifier/p2p_invalidator.h" | 5 #include "sync/notifier/p2p_invalidator.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/json/json_reader.h" | 9 #include "base/json/json_reader.h" |
| 10 #include "base/json/json_writer.h" | 10 #include "base/json/json_writer.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/values.h" | 12 #include "base/values.h" |
| 13 #include "jingle/notifier/listener/push_client.h" | 13 #include "jingle/notifier/listener/push_client.h" |
| 14 #include "sync/internal_api/public/base/model_type_state_map.h" | |
| 15 #include "sync/notifier/invalidation_handler.h" | 14 #include "sync/notifier/invalidation_handler.h" |
| 16 #include "sync/notifier/invalidation_util.h" | 15 #include "sync/notifier/invalidation_util.h" |
| 17 | 16 |
| 18 namespace syncer { | 17 namespace syncer { |
| 19 | 18 |
| 20 const char kSyncP2PNotificationChannel[] = "http://www.google.com/chrome/sync"; | 19 const char kSyncP2PNotificationChannel[] = "http://www.google.com/chrome/sync"; |
| 21 | 20 |
| 22 namespace { | 21 namespace { |
| 23 | 22 |
| 24 const char kNotifySelf[] = "notifySelf"; | 23 const char kNotifySelf[] = "notifySelf"; |
| 25 const char kNotifyOthers[] = "notifyOthers"; | 24 const char kNotifyOthers[] = "notifyOthers"; |
| 26 const char kNotifyAll[] = "notifyAll"; | 25 const char kNotifyAll[] = "notifyAll"; |
| 27 | 26 |
| 28 const char kSenderIdKey[] = "senderId"; | 27 const char kSenderIdKey[] = "senderId"; |
| 29 const char kNotificationTypeKey[] = "notificationType"; | 28 const char kNotificationTypeKey[] = "notificationType"; |
| 30 const char kIdStateMapKey[] = "idStateMap"; | 29 const char kIdInvalidationMapKey[] = "idInvalidationMap"; |
| 31 const char kSourceKey[] = "source"; | 30 const char kSourceKey[] = "source"; |
| 32 | 31 |
| 33 } // namespace | 32 } // namespace |
| 34 | 33 |
| 35 std::string P2PNotificationTargetToString(P2PNotificationTarget target) { | 34 std::string P2PNotificationTargetToString(P2PNotificationTarget target) { |
| 36 switch (target) { | 35 switch (target) { |
| 37 case NOTIFY_SELF: | 36 case NOTIFY_SELF: |
| 38 return kNotifySelf; | 37 return kNotifySelf; |
| 39 case NOTIFY_OTHERS: | 38 case NOTIFY_OTHERS: |
| 40 return kNotifyOthers; | 39 return kNotifyOthers; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 67 } | 66 } |
| 68 return REMOTE_INVALIDATION; | 67 return REMOTE_INVALIDATION; |
| 69 } | 68 } |
| 70 | 69 |
| 71 P2PNotificationData::P2PNotificationData() | 70 P2PNotificationData::P2PNotificationData() |
| 72 : target_(NOTIFY_SELF), source_(REMOTE_INVALIDATION) {} | 71 : target_(NOTIFY_SELF), source_(REMOTE_INVALIDATION) {} |
| 73 | 72 |
| 74 P2PNotificationData::P2PNotificationData( | 73 P2PNotificationData::P2PNotificationData( |
| 75 const std::string& sender_id, | 74 const std::string& sender_id, |
| 76 P2PNotificationTarget target, | 75 P2PNotificationTarget target, |
| 77 const ObjectIdStateMap& id_state_map, | 76 const ObjectIdInvalidationMap& invalidation_map, |
| 78 IncomingInvalidationSource source) | 77 IncomingInvalidationSource source) |
| 79 : sender_id_(sender_id), | 78 : sender_id_(sender_id), |
| 80 target_(target), | 79 target_(target), |
| 81 id_state_map_(id_state_map), | 80 invalidation_map_(invalidation_map), |
| 82 source_(source) {} | 81 source_(source) {} |
| 83 | 82 |
| 84 P2PNotificationData::~P2PNotificationData() {} | 83 P2PNotificationData::~P2PNotificationData() {} |
| 85 | 84 |
| 86 bool P2PNotificationData::IsTargeted(const std::string& id) const { | 85 bool P2PNotificationData::IsTargeted(const std::string& id) const { |
| 87 switch (target_) { | 86 switch (target_) { |
| 88 case NOTIFY_SELF: | 87 case NOTIFY_SELF: |
| 89 return sender_id_ == id; | 88 return sender_id_ == id; |
| 90 case NOTIFY_OTHERS: | 89 case NOTIFY_OTHERS: |
| 91 return sender_id_ != id; | 90 return sender_id_ != id; |
| 92 case NOTIFY_ALL: | 91 case NOTIFY_ALL: |
| 93 return true; | 92 return true; |
| 94 default: | 93 default: |
| 95 NOTREACHED(); | 94 NOTREACHED(); |
| 96 return false; | 95 return false; |
| 97 } | 96 } |
| 98 } | 97 } |
| 99 | 98 |
| 100 const ObjectIdStateMap& P2PNotificationData::GetIdStateMap() const { | 99 const ObjectIdInvalidationMap& |
| 101 return id_state_map_; | 100 P2PNotificationData::GetIdInvalidationMap() const { |
| 101 return invalidation_map_; |
| 102 } | 102 } |
| 103 | 103 |
| 104 IncomingInvalidationSource P2PNotificationData::GetSource() const { | 104 IncomingInvalidationSource P2PNotificationData::GetSource() const { |
| 105 return source_; | 105 return source_; |
| 106 } | 106 } |
| 107 | 107 |
| 108 bool P2PNotificationData::Equals(const P2PNotificationData& other) const { | 108 bool P2PNotificationData::Equals(const P2PNotificationData& other) const { |
| 109 return | 109 return |
| 110 (sender_id_ == other.sender_id_) && | 110 (sender_id_ == other.sender_id_) && |
| 111 (target_ == other.target_) && | 111 (target_ == other.target_) && |
| 112 ObjectIdStateMapEquals(id_state_map_, other.id_state_map_) && | 112 ObjectIdInvalidationMapEquals(invalidation_map_, |
| 113 other.invalidation_map_) && |
| 113 (source_ == other.source_); | 114 (source_ == other.source_); |
| 114 } | 115 } |
| 115 | 116 |
| 116 std::string P2PNotificationData::ToString() const { | 117 std::string P2PNotificationData::ToString() const { |
| 117 scoped_ptr<DictionaryValue> dict(new DictionaryValue()); | 118 scoped_ptr<DictionaryValue> dict(new DictionaryValue()); |
| 118 dict->SetString(kSenderIdKey, sender_id_); | 119 dict->SetString(kSenderIdKey, sender_id_); |
| 119 dict->SetString(kNotificationTypeKey, | 120 dict->SetString(kNotificationTypeKey, |
| 120 P2PNotificationTargetToString(target_)); | 121 P2PNotificationTargetToString(target_)); |
| 121 dict->Set(kIdStateMapKey, ObjectIdStateMapToValue(id_state_map_).release()); | 122 dict->Set(kIdInvalidationMapKey, |
| 123 ObjectIdInvalidationMapToValue(invalidation_map_).release()); |
| 122 dict->SetInteger(kSourceKey, source_); | 124 dict->SetInteger(kSourceKey, source_); |
| 123 std::string json; | 125 std::string json; |
| 124 base::JSONWriter::Write(dict.get(), &json); | 126 base::JSONWriter::Write(dict.get(), &json); |
| 125 return json; | 127 return json; |
| 126 } | 128 } |
| 127 | 129 |
| 128 bool P2PNotificationData::ResetFromString(const std::string& str) { | 130 bool P2PNotificationData::ResetFromString(const std::string& str) { |
| 129 scoped_ptr<Value> data_value(base::JSONReader::Read(str)); | 131 scoped_ptr<Value> data_value(base::JSONReader::Read(str)); |
| 130 const base::DictionaryValue* data_dict = NULL; | 132 const base::DictionaryValue* data_dict = NULL; |
| 131 if (!data_value.get() || !data_value->GetAsDictionary(&data_dict)) { | 133 if (!data_value.get() || !data_value->GetAsDictionary(&data_dict)) { |
| 132 LOG(WARNING) << "Could not parse " << str << " as a dictionary"; | 134 LOG(WARNING) << "Could not parse " << str << " as a dictionary"; |
| 133 return false; | 135 return false; |
| 134 } | 136 } |
| 135 if (!data_dict->GetString(kSenderIdKey, &sender_id_)) { | 137 if (!data_dict->GetString(kSenderIdKey, &sender_id_)) { |
| 136 LOG(WARNING) << "Could not find string value for " << kSenderIdKey; | 138 LOG(WARNING) << "Could not find string value for " << kSenderIdKey; |
| 137 } | 139 } |
| 138 std::string target_str; | 140 std::string target_str; |
| 139 if (!data_dict->GetString(kNotificationTypeKey, &target_str)) { | 141 if (!data_dict->GetString(kNotificationTypeKey, &target_str)) { |
| 140 LOG(WARNING) << "Could not find string value for " | 142 LOG(WARNING) << "Could not find string value for " |
| 141 << kNotificationTypeKey; | 143 << kNotificationTypeKey; |
| 142 } | 144 } |
| 143 target_ = P2PNotificationTargetFromString(target_str); | 145 target_ = P2PNotificationTargetFromString(target_str); |
| 144 const base::ListValue* id_state_map_list = NULL; | 146 const base::ListValue* invalidation_map_list = NULL; |
| 145 if (!data_dict->GetList(kIdStateMapKey, &id_state_map_list) || | 147 if (!data_dict->GetList(kIdInvalidationMapKey, &invalidation_map_list) || |
| 146 !ObjectIdStateMapFromValue(*id_state_map_list, &id_state_map_)) { | 148 !ObjectIdInvalidationMapFromValue(*invalidation_map_list, |
| 147 LOG(WARNING) << "Could not parse " << kIdStateMapKey; | 149 &invalidation_map_)) { |
| 150 LOG(WARNING) << "Could not parse " << kIdInvalidationMapKey; |
| 148 } | 151 } |
| 149 int source_num = 0; | 152 int source_num = 0; |
| 150 if (!data_dict->GetInteger(kSourceKey, &source_num)) { | 153 if (!data_dict->GetInteger(kSourceKey, &source_num)) { |
| 151 LOG(WARNING) << "Could not find integer value for " << kSourceKey; | 154 LOG(WARNING) << "Could not find integer value for " << kSourceKey; |
| 152 } | 155 } |
| 153 source_ = P2PNotificationSourceFromInteger(source_num); | 156 source_ = P2PNotificationSourceFromInteger(source_num); |
| 154 return true; | 157 return true; |
| 155 } | 158 } |
| 156 | 159 |
| 157 P2PInvalidator::P2PInvalidator(scoped_ptr<notifier::PushClient> push_client, | 160 P2PInvalidator::P2PInvalidator(scoped_ptr<notifier::PushClient> push_client, |
| (...skipping 22 matching lines...) Expand all Loading... |
| 180 // TODO(akalin): Handle arbitrary object IDs (http://crbug.com/140411). | 183 // TODO(akalin): Handle arbitrary object IDs (http://crbug.com/140411). |
| 181 DCHECK(thread_checker_.CalledOnValidThread()); | 184 DCHECK(thread_checker_.CalledOnValidThread()); |
| 182 ObjectIdSet new_ids; | 185 ObjectIdSet new_ids; |
| 183 const ObjectIdSet& old_ids = registrar_.GetRegisteredIds(handler); | 186 const ObjectIdSet& old_ids = registrar_.GetRegisteredIds(handler); |
| 184 std::set_difference(ids.begin(), ids.end(), | 187 std::set_difference(ids.begin(), ids.end(), |
| 185 old_ids.begin(), old_ids.end(), | 188 old_ids.begin(), old_ids.end(), |
| 186 std::inserter(new_ids, new_ids.end()), | 189 std::inserter(new_ids, new_ids.end()), |
| 187 ObjectIdLessThan()); | 190 ObjectIdLessThan()); |
| 188 registrar_.UpdateRegisteredIds(handler, ids); | 191 registrar_.UpdateRegisteredIds(handler, ids); |
| 189 const P2PNotificationData notification_data( | 192 const P2PNotificationData notification_data( |
| 190 unique_id_, NOTIFY_SELF, ObjectIdSetToStateMap(new_ids, ""), | 193 unique_id_, NOTIFY_SELF, ObjectIdSetToInvalidationMap(new_ids, ""), |
| 191 REMOTE_INVALIDATION); | 194 REMOTE_INVALIDATION); |
| 192 SendNotificationData(notification_data); | 195 SendNotificationData(notification_data); |
| 193 } | 196 } |
| 194 | 197 |
| 195 void P2PInvalidator::UnregisterHandler(InvalidationHandler* handler) { | 198 void P2PInvalidator::UnregisterHandler(InvalidationHandler* handler) { |
| 196 DCHECK(thread_checker_.CalledOnValidThread()); | 199 DCHECK(thread_checker_.CalledOnValidThread()); |
| 197 registrar_.UnregisterHandler(handler); | 200 registrar_.UnregisterHandler(handler); |
| 198 } | 201 } |
| 199 | 202 |
| 200 InvalidatorState P2PInvalidator::GetInvalidatorState() const { | 203 InvalidatorState P2PInvalidator::GetInvalidatorState() const { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 222 // used in p2p mode (which is only used in testing). | 225 // used in p2p mode (which is only used in testing). |
| 223 subscription.from = email; | 226 subscription.from = email; |
| 224 push_client_->UpdateSubscriptions( | 227 push_client_->UpdateSubscriptions( |
| 225 notifier::SubscriptionList(1, subscription)); | 228 notifier::SubscriptionList(1, subscription)); |
| 226 // If already logged in, the new credentials will take effect on the | 229 // If already logged in, the new credentials will take effect on the |
| 227 // next reconnection. | 230 // next reconnection. |
| 228 push_client_->UpdateCredentials(email, token); | 231 push_client_->UpdateCredentials(email, token); |
| 229 logged_in_ = true; | 232 logged_in_ = true; |
| 230 } | 233 } |
| 231 | 234 |
| 232 void P2PInvalidator::SendInvalidation(const ObjectIdStateMap& id_state_map) { | 235 void P2PInvalidator::SendInvalidation( |
| 236 const ObjectIdInvalidationMap& invalidation_map) { |
| 233 DCHECK(thread_checker_.CalledOnValidThread()); | 237 DCHECK(thread_checker_.CalledOnValidThread()); |
| 234 const P2PNotificationData notification_data( | 238 const P2PNotificationData notification_data( |
| 235 unique_id_, send_notification_target_, id_state_map, | 239 unique_id_, send_notification_target_, invalidation_map, |
| 236 REMOTE_INVALIDATION); | 240 REMOTE_INVALIDATION); |
| 237 SendNotificationData(notification_data); | 241 SendNotificationData(notification_data); |
| 238 } | 242 } |
| 239 | 243 |
| 240 void P2PInvalidator::OnNotificationsEnabled() { | 244 void P2PInvalidator::OnNotificationsEnabled() { |
| 241 DCHECK(thread_checker_.CalledOnValidThread()); | 245 DCHECK(thread_checker_.CalledOnValidThread()); |
| 242 bool just_turned_on = (notifications_enabled_ == false); | 246 bool just_turned_on = (notifications_enabled_ == false); |
| 243 notifications_enabled_ = true; | 247 notifications_enabled_ = true; |
| 244 registrar_.UpdateInvalidatorState(INVALIDATIONS_ENABLED); | 248 registrar_.UpdateInvalidatorState(INVALIDATIONS_ENABLED); |
| 245 if (just_turned_on) { | 249 if (just_turned_on) { |
| 246 const P2PNotificationData notification_data( | 250 const P2PNotificationData notification_data( |
| 247 unique_id_, NOTIFY_SELF, | 251 unique_id_, NOTIFY_SELF, |
| 248 ObjectIdSetToStateMap(registrar_.GetAllRegisteredIds(), ""), | 252 ObjectIdSetToInvalidationMap(registrar_.GetAllRegisteredIds(), ""), |
| 249 REMOTE_INVALIDATION); | 253 REMOTE_INVALIDATION); |
| 250 SendNotificationData(notification_data); | 254 SendNotificationData(notification_data); |
| 251 } | 255 } |
| 252 } | 256 } |
| 253 | 257 |
| 254 void P2PInvalidator::OnNotificationsDisabled( | 258 void P2PInvalidator::OnNotificationsDisabled( |
| 255 notifier::NotificationsDisabledReason reason) { | 259 notifier::NotificationsDisabledReason reason) { |
| 256 DCHECK(thread_checker_.CalledOnValidThread()); | 260 DCHECK(thread_checker_.CalledOnValidThread()); |
| 257 registrar_.UpdateInvalidatorState(FromNotifierReason(reason)); | 261 registrar_.UpdateInvalidatorState(FromNotifierReason(reason)); |
| 258 } | 262 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 273 LOG(WARNING) << "Notification from unexpected source " | 277 LOG(WARNING) << "Notification from unexpected source " |
| 274 << notification.channel; | 278 << notification.channel; |
| 275 } | 279 } |
| 276 P2PNotificationData notification_data; | 280 P2PNotificationData notification_data; |
| 277 if (!notification_data.ResetFromString(notification.data)) { | 281 if (!notification_data.ResetFromString(notification.data)) { |
| 278 LOG(WARNING) << "Could not parse notification data from " | 282 LOG(WARNING) << "Could not parse notification data from " |
| 279 << notification.data; | 283 << notification.data; |
| 280 notification_data = | 284 notification_data = |
| 281 P2PNotificationData( | 285 P2PNotificationData( |
| 282 unique_id_, NOTIFY_ALL, | 286 unique_id_, NOTIFY_ALL, |
| 283 ObjectIdSetToStateMap(registrar_.GetAllRegisteredIds(), ""), | 287 ObjectIdSetToInvalidationMap(registrar_.GetAllRegisteredIds(), ""), |
| 284 REMOTE_INVALIDATION); | 288 REMOTE_INVALIDATION); |
| 285 } | 289 } |
| 286 if (!notification_data.IsTargeted(unique_id_)) { | 290 if (!notification_data.IsTargeted(unique_id_)) { |
| 287 DVLOG(1) << "Not a target of the notification -- " | 291 DVLOG(1) << "Not a target of the notification -- " |
| 288 << "not emitting notification"; | 292 << "not emitting notification"; |
| 289 return; | 293 return; |
| 290 } | 294 } |
| 291 registrar_.DispatchInvalidationsToHandlers( | 295 registrar_.DispatchInvalidationsToHandlers( |
| 292 notification_data.GetIdStateMap(), | 296 notification_data.GetIdInvalidationMap(), |
| 293 REMOTE_INVALIDATION); | 297 REMOTE_INVALIDATION); |
| 294 } | 298 } |
| 295 | 299 |
| 296 void P2PInvalidator::SendNotificationDataForTest( | 300 void P2PInvalidator::SendNotificationDataForTest( |
| 297 const P2PNotificationData& notification_data) { | 301 const P2PNotificationData& notification_data) { |
| 298 DCHECK(thread_checker_.CalledOnValidThread()); | 302 DCHECK(thread_checker_.CalledOnValidThread()); |
| 299 SendNotificationData(notification_data); | 303 SendNotificationData(notification_data); |
| 300 } | 304 } |
| 301 | 305 |
| 302 void P2PInvalidator::SendNotificationData( | 306 void P2PInvalidator::SendNotificationData( |
| 303 const P2PNotificationData& notification_data) { | 307 const P2PNotificationData& notification_data) { |
| 304 DCHECK(thread_checker_.CalledOnValidThread()); | 308 DCHECK(thread_checker_.CalledOnValidThread()); |
| 305 if (notification_data.GetIdStateMap().empty()) { | 309 if (notification_data.GetIdInvalidationMap().empty()) { |
| 306 DVLOG(1) << "Not sending XMPP notification with empty state map: " | 310 DVLOG(1) << "Not sending XMPP notification with empty state map: " |
| 307 << notification_data.ToString(); | 311 << notification_data.ToString(); |
| 308 return; | 312 return; |
| 309 } | 313 } |
| 310 notifier::Notification notification; | 314 notifier::Notification notification; |
| 311 notification.channel = kSyncP2PNotificationChannel; | 315 notification.channel = kSyncP2PNotificationChannel; |
| 312 notification.data = notification_data.ToString(); | 316 notification.data = notification_data.ToString(); |
| 313 DVLOG(1) << "Sending XMPP notification: " << notification.ToString(); | 317 DVLOG(1) << "Sending XMPP notification: " << notification.ToString(); |
| 314 push_client_->SendNotification(notification); | 318 push_client_->SendNotification(notification); |
| 315 } | 319 } |
| 316 | 320 |
| 317 } // namespace syncer | 321 } // namespace syncer |
| OLD | NEW |