| 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" | 14 #include "sync/internal_api/public/base/model_type_state_map.h" |
| 15 #include "sync/notifier/invalidation_handler.h" | 15 #include "sync/notifier/invalidation_handler.h" |
| 16 #include "sync/notifier/invalidation_util.h" | 16 #include "sync/notifier/invalidation_util.h" |
| 17 | 17 |
| 18 namespace syncer { | 18 namespace syncer { |
| 19 | 19 |
| 20 const char* kSyncP2PNotificationChannel = "http://www.google.com/chrome/sync"; | 20 const char kSyncP2PNotificationChannel[] = "http://www.google.com/chrome/sync"; |
| 21 | 21 |
| 22 namespace { | 22 namespace { |
| 23 | 23 |
| 24 const char kNotifySelf[] = "notifySelf"; | 24 const char kNotifySelf[] = "notifySelf"; |
| 25 const char kNotifyOthers[] = "notifyOthers"; | 25 const char kNotifyOthers[] = "notifyOthers"; |
| 26 const char kNotifyAll[] = "notifyAll"; | 26 const char kNotifyAll[] = "notifyAll"; |
| 27 | 27 |
| 28 const char kSenderIdKey[] = "senderId"; | 28 const char kSenderIdKey[] = "senderId"; |
| 29 const char kNotificationTypeKey[] = "notificationType"; | 29 const char kNotificationTypeKey[] = "notificationType"; |
| 30 const char kChangedTypesKey[] = "changedTypes"; | 30 const char kIdStateMapKey[] = "idStateMap"; |
| 31 const char kSourceKey[] = "source"; |
| 31 | 32 |
| 32 } // namespace | 33 } // namespace |
| 33 | 34 |
| 34 std::string P2PNotificationTargetToString(P2PNotificationTarget target) { | 35 std::string P2PNotificationTargetToString(P2PNotificationTarget target) { |
| 35 switch (target) { | 36 switch (target) { |
| 36 case NOTIFY_SELF: | 37 case NOTIFY_SELF: |
| 37 return kNotifySelf; | 38 return kNotifySelf; |
| 38 case NOTIFY_OTHERS: | 39 case NOTIFY_OTHERS: |
| 39 return kNotifyOthers; | 40 return kNotifyOthers; |
| 40 case NOTIFY_ALL: | 41 case NOTIFY_ALL: |
| (...skipping 12 matching lines...) Expand all Loading... |
| 53 if (target_str == kNotifyOthers) { | 54 if (target_str == kNotifyOthers) { |
| 54 return NOTIFY_OTHERS; | 55 return NOTIFY_OTHERS; |
| 55 } | 56 } |
| 56 if (target_str == kNotifyAll) { | 57 if (target_str == kNotifyAll) { |
| 57 return NOTIFY_ALL; | 58 return NOTIFY_ALL; |
| 58 } | 59 } |
| 59 LOG(WARNING) << "Could not parse " << target_str; | 60 LOG(WARNING) << "Could not parse " << target_str; |
| 60 return NOTIFY_SELF; | 61 return NOTIFY_SELF; |
| 61 } | 62 } |
| 62 | 63 |
| 63 P2PNotificationData::P2PNotificationData() : target_(NOTIFY_SELF) {} | 64 IncomingNotificationSource P2PNotificationSourceFromInteger(int source_num) { |
| 65 if (source_num == LOCAL_NOTIFICATION) { |
| 66 return LOCAL_NOTIFICATION; |
| 67 } |
| 68 return REMOTE_NOTIFICATION; |
| 69 } |
| 70 |
| 71 P2PNotificationData::P2PNotificationData() |
| 72 : target_(NOTIFY_SELF), source_(REMOTE_NOTIFICATION) {} |
| 64 | 73 |
| 65 P2PNotificationData::P2PNotificationData( | 74 P2PNotificationData::P2PNotificationData( |
| 66 const std::string& sender_id, | 75 const std::string& sender_id, |
| 67 P2PNotificationTarget target, | 76 P2PNotificationTarget target, |
| 68 ModelTypeSet changed_types) | 77 const ObjectIdStateMap& id_state_map, |
| 78 IncomingNotificationSource source) |
| 69 : sender_id_(sender_id), | 79 : sender_id_(sender_id), |
| 70 target_(target), | 80 target_(target), |
| 71 changed_types_(changed_types) {} | 81 id_state_map_(id_state_map), |
| 82 source_(source) {} |
| 72 | 83 |
| 73 P2PNotificationData::~P2PNotificationData() {} | 84 P2PNotificationData::~P2PNotificationData() {} |
| 74 | 85 |
| 75 bool P2PNotificationData::IsTargeted(const std::string& id) const { | 86 bool P2PNotificationData::IsTargeted(const std::string& id) const { |
| 76 switch (target_) { | 87 switch (target_) { |
| 77 case NOTIFY_SELF: | 88 case NOTIFY_SELF: |
| 78 return sender_id_ == id; | 89 return sender_id_ == id; |
| 79 case NOTIFY_OTHERS: | 90 case NOTIFY_OTHERS: |
| 80 return sender_id_ != id; | 91 return sender_id_ != id; |
| 81 case NOTIFY_ALL: | 92 case NOTIFY_ALL: |
| 82 return true; | 93 return true; |
| 83 default: | 94 default: |
| 84 NOTREACHED(); | 95 NOTREACHED(); |
| 85 return false; | 96 return false; |
| 86 } | 97 } |
| 87 } | 98 } |
| 88 | 99 |
| 89 ModelTypeSet P2PNotificationData::GetChangedTypes() const { | 100 const ObjectIdStateMap& P2PNotificationData::GetIdStateMap() const { |
| 90 return changed_types_; | 101 return id_state_map_; |
| 102 } |
| 103 |
| 104 IncomingNotificationSource P2PNotificationData::GetSource() const { |
| 105 return source_; |
| 91 } | 106 } |
| 92 | 107 |
| 93 bool P2PNotificationData::Equals(const P2PNotificationData& other) const { | 108 bool P2PNotificationData::Equals(const P2PNotificationData& other) const { |
| 94 return | 109 return |
| 95 (sender_id_ == other.sender_id_) && | 110 (sender_id_ == other.sender_id_) && |
| 96 (target_ == other.target_) && | 111 (target_ == other.target_) && |
| 97 changed_types_.Equals(other.changed_types_); | 112 ObjectIdStateMapEquals(id_state_map_, other.id_state_map_) && |
| 113 (source_ == other.source_); |
| 98 } | 114 } |
| 99 | 115 |
| 100 std::string P2PNotificationData::ToString() const { | 116 std::string P2PNotificationData::ToString() const { |
| 101 scoped_ptr<DictionaryValue> dict(new DictionaryValue()); | 117 scoped_ptr<DictionaryValue> dict(new DictionaryValue()); |
| 102 dict->SetString(kSenderIdKey, sender_id_); | 118 dict->SetString(kSenderIdKey, sender_id_); |
| 103 dict->SetString(kNotificationTypeKey, | 119 dict->SetString(kNotificationTypeKey, |
| 104 P2PNotificationTargetToString(target_)); | 120 P2PNotificationTargetToString(target_)); |
| 105 dict->Set(kChangedTypesKey, ModelTypeSetToValue(changed_types_)); | 121 dict->Set(kIdStateMapKey, ObjectIdStateMapToValue(id_state_map_).release()); |
| 122 dict->SetInteger(kSourceKey, source_); |
| 106 std::string json; | 123 std::string json; |
| 107 base::JSONWriter::Write(dict.get(), &json); | 124 base::JSONWriter::Write(dict.get(), &json); |
| 108 return json; | 125 return json; |
| 109 } | 126 } |
| 110 | 127 |
| 111 bool P2PNotificationData::ResetFromString(const std::string& str) { | 128 bool P2PNotificationData::ResetFromString(const std::string& str) { |
| 112 scoped_ptr<Value> data_value(base::JSONReader::Read(str)); | 129 scoped_ptr<Value> data_value(base::JSONReader::Read(str)); |
| 113 if (!data_value.get()) { | 130 const base::DictionaryValue* data_dict = NULL; |
| 114 LOG(WARNING) << "Could not parse " << str; | 131 if (!data_value.get() || !data_value->GetAsDictionary(&data_dict)) { |
| 115 return false; | |
| 116 } | |
| 117 if (!data_value->IsType(Value::TYPE_DICTIONARY)) { | |
| 118 LOG(WARNING) << "Could not parse " << str << " as a dictionary"; | 132 LOG(WARNING) << "Could not parse " << str << " as a dictionary"; |
| 119 return false; | 133 return false; |
| 120 } | 134 } |
| 121 // TODO(akalin): Use Values::AsDictionary() when it becomes | |
| 122 // available. | |
| 123 DictionaryValue* data_dict = | |
| 124 static_cast<DictionaryValue*>(data_value.get()); | |
| 125 if (!data_dict->GetString(kSenderIdKey, &sender_id_)) { | 135 if (!data_dict->GetString(kSenderIdKey, &sender_id_)) { |
| 126 LOG(WARNING) << "Could not find string value for " << kSenderIdKey; | 136 LOG(WARNING) << "Could not find string value for " << kSenderIdKey; |
| 127 } | 137 } |
| 128 std::string target_str; | 138 std::string target_str; |
| 129 if (!data_dict->GetString(kNotificationTypeKey, &target_str)) { | 139 if (!data_dict->GetString(kNotificationTypeKey, &target_str)) { |
| 130 LOG(WARNING) << "Could not find string value for " | 140 LOG(WARNING) << "Could not find string value for " |
| 131 << kNotificationTypeKey; | 141 << kNotificationTypeKey; |
| 132 } | 142 } |
| 133 target_ = P2PNotificationTargetFromString(target_str); | 143 target_ = P2PNotificationTargetFromString(target_str); |
| 134 ListValue* changed_types_list = NULL; | 144 const base::ListValue* id_state_map_list = NULL; |
| 135 if (!data_dict->GetList(kChangedTypesKey, &changed_types_list)) { | 145 if (!data_dict->GetList(kIdStateMapKey, &id_state_map_list) || |
| 136 LOG(WARNING) << "Could not find list value for " | 146 !ObjectIdStateMapFromValue(*id_state_map_list, &id_state_map_)) { |
| 137 << kChangedTypesKey; | 147 LOG(WARNING) << "Could not parse " << kIdStateMapKey; |
| 138 return false; | |
| 139 } | 148 } |
| 140 changed_types_ = ModelTypeSetFromValue(*changed_types_list); | 149 int source_num = 0; |
| 150 if (!data_dict->GetInteger(kSourceKey, &source_num)) { |
| 151 LOG(WARNING) << "Could not find integer value for " << kSourceKey; |
| 152 } |
| 153 source_ = P2PNotificationSourceFromInteger(source_num); |
| 141 return true; | 154 return true; |
| 142 } | 155 } |
| 143 | 156 |
| 144 P2PInvalidator::P2PInvalidator(scoped_ptr<notifier::PushClient> push_client, | 157 P2PInvalidator::P2PInvalidator(scoped_ptr<notifier::PushClient> push_client, |
| 145 P2PNotificationTarget send_notification_target) | 158 P2PNotificationTarget send_notification_target) |
| 146 : push_client_(push_client.Pass()), | 159 : push_client_(push_client.Pass()), |
| 147 logged_in_(false), | 160 logged_in_(false), |
| 148 notifications_enabled_(false), | 161 notifications_enabled_(false), |
| 149 send_notification_target_(send_notification_target) { | 162 send_notification_target_(send_notification_target) { |
| 150 DCHECK(send_notification_target_ == NOTIFY_OTHERS || | 163 DCHECK(send_notification_target_ == NOTIFY_OTHERS || |
| 151 send_notification_target_ == NOTIFY_ALL); | 164 send_notification_target_ == NOTIFY_ALL); |
| 152 push_client_->AddObserver(this); | 165 push_client_->AddObserver(this); |
| 153 } | 166 } |
| 154 | 167 |
| 155 P2PInvalidator::~P2PInvalidator() { | 168 P2PInvalidator::~P2PInvalidator() { |
| 156 DCHECK(thread_checker_.CalledOnValidThread()); | 169 DCHECK(thread_checker_.CalledOnValidThread()); |
| 157 push_client_->RemoveObserver(this); | 170 push_client_->RemoveObserver(this); |
| 158 } | 171 } |
| 159 | 172 |
| 160 void P2PInvalidator::RegisterHandler(InvalidationHandler* handler) { | 173 void P2PInvalidator::RegisterHandler(InvalidationHandler* handler) { |
| 161 DCHECK(thread_checker_.CalledOnValidThread()); | 174 DCHECK(thread_checker_.CalledOnValidThread()); |
| 162 registrar_.RegisterHandler(handler); | 175 registrar_.RegisterHandler(handler); |
| 163 } | 176 } |
| 164 | 177 |
| 165 void P2PInvalidator::UpdateRegisteredIds(InvalidationHandler* handler, | 178 void P2PInvalidator::UpdateRegisteredIds(InvalidationHandler* handler, |
| 166 const ObjectIdSet& ids) { | 179 const ObjectIdSet& ids) { |
| 167 // TODO(akalin): Handle arbitrary object IDs (http://crbug.com/140411). | 180 // TODO(akalin): Handle arbitrary object IDs (http://crbug.com/140411). |
| 168 DCHECK(thread_checker_.CalledOnValidThread()); | 181 DCHECK(thread_checker_.CalledOnValidThread()); |
| 182 ObjectIdSet new_ids; |
| 183 const ObjectIdSet& old_ids = registrar_.GetRegisteredIds(handler); |
| 184 std::set_difference(ids.begin(), ids.end(), |
| 185 old_ids.begin(), old_ids.end(), |
| 186 std::inserter(new_ids, new_ids.end()), |
| 187 ObjectIdLessThan()); |
| 169 registrar_.UpdateRegisteredIds(handler, ids); | 188 registrar_.UpdateRegisteredIds(handler, ids); |
| 170 const ModelTypeSet enabled_types = | |
| 171 ObjectIdSetToModelTypeSet(registrar_.GetAllRegisteredIds()); | |
| 172 const ModelTypeSet new_enabled_types = | |
| 173 Difference(enabled_types, enabled_types_); | |
| 174 const P2PNotificationData notification_data( | 189 const P2PNotificationData notification_data( |
| 175 unique_id_, NOTIFY_SELF, new_enabled_types); | 190 unique_id_, NOTIFY_SELF, ObjectIdSetToStateMap(new_ids, ""), |
| 191 REMOTE_NOTIFICATION); |
| 176 SendNotificationData(notification_data); | 192 SendNotificationData(notification_data); |
| 177 enabled_types_ = enabled_types; | |
| 178 } | 193 } |
| 179 | 194 |
| 180 void P2PInvalidator::UnregisterHandler(InvalidationHandler* handler) { | 195 void P2PInvalidator::UnregisterHandler(InvalidationHandler* handler) { |
| 181 DCHECK(thread_checker_.CalledOnValidThread()); | 196 DCHECK(thread_checker_.CalledOnValidThread()); |
| 182 registrar_.UnregisterHandler(handler); | 197 registrar_.UnregisterHandler(handler); |
| 183 } | 198 } |
| 184 | 199 |
| 185 void P2PInvalidator::SetUniqueId(const std::string& unique_id) { | 200 void P2PInvalidator::SetUniqueId(const std::string& unique_id) { |
| 186 DCHECK(thread_checker_.CalledOnValidThread()); | 201 DCHECK(thread_checker_.CalledOnValidThread()); |
| 187 unique_id_ = unique_id; | 202 unique_id_ = unique_id; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 202 // used in p2p mode (which is only used in testing). | 217 // used in p2p mode (which is only used in testing). |
| 203 subscription.from = email; | 218 subscription.from = email; |
| 204 push_client_->UpdateSubscriptions( | 219 push_client_->UpdateSubscriptions( |
| 205 notifier::SubscriptionList(1, subscription)); | 220 notifier::SubscriptionList(1, subscription)); |
| 206 // If already logged in, the new credentials will take effect on the | 221 // If already logged in, the new credentials will take effect on the |
| 207 // next reconnection. | 222 // next reconnection. |
| 208 push_client_->UpdateCredentials(email, token); | 223 push_client_->UpdateCredentials(email, token); |
| 209 logged_in_ = true; | 224 logged_in_ = true; |
| 210 } | 225 } |
| 211 | 226 |
| 212 void P2PInvalidator::SendNotification(ModelTypeSet changed_types) { | 227 void P2PInvalidator::SendNotification(const ObjectIdStateMap& id_state_map) { |
| 213 DCHECK(thread_checker_.CalledOnValidThread()); | 228 DCHECK(thread_checker_.CalledOnValidThread()); |
| 214 const P2PNotificationData notification_data( | 229 const P2PNotificationData notification_data( |
| 215 unique_id_, send_notification_target_, changed_types); | 230 unique_id_, send_notification_target_, id_state_map, |
| 231 REMOTE_NOTIFICATION); |
| 216 SendNotificationData(notification_data); | 232 SendNotificationData(notification_data); |
| 217 } | 233 } |
| 218 | 234 |
| 219 void P2PInvalidator::OnNotificationsEnabled() { | 235 void P2PInvalidator::OnNotificationsEnabled() { |
| 220 DCHECK(thread_checker_.CalledOnValidThread()); | 236 DCHECK(thread_checker_.CalledOnValidThread()); |
| 221 bool just_turned_on = (notifications_enabled_ == false); | 237 bool just_turned_on = (notifications_enabled_ == false); |
| 222 notifications_enabled_ = true; | 238 notifications_enabled_ = true; |
| 223 registrar_.EmitOnNotificationsEnabled(); | 239 registrar_.EmitOnNotificationsEnabled(); |
| 224 if (just_turned_on) { | 240 if (just_turned_on) { |
| 225 const P2PNotificationData notification_data( | 241 const P2PNotificationData notification_data( |
| 226 unique_id_, NOTIFY_SELF, enabled_types_); | 242 unique_id_, NOTIFY_SELF, |
| 243 ObjectIdSetToStateMap(registrar_.GetAllRegisteredIds(), ""), |
| 244 REMOTE_NOTIFICATION); |
| 227 SendNotificationData(notification_data); | 245 SendNotificationData(notification_data); |
| 228 } | 246 } |
| 229 } | 247 } |
| 230 | 248 |
| 231 void P2PInvalidator::OnNotificationsDisabled( | 249 void P2PInvalidator::OnNotificationsDisabled( |
| 232 notifier::NotificationsDisabledReason reason) { | 250 notifier::NotificationsDisabledReason reason) { |
| 233 DCHECK(thread_checker_.CalledOnValidThread()); | 251 DCHECK(thread_checker_.CalledOnValidThread()); |
| 234 registrar_.EmitOnNotificationsDisabled(FromNotifierReason(reason)); | 252 registrar_.EmitOnNotificationsDisabled(FromNotifierReason(reason)); |
| 235 } | 253 } |
| 236 | 254 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 248 } | 266 } |
| 249 if (notification.channel != kSyncP2PNotificationChannel) { | 267 if (notification.channel != kSyncP2PNotificationChannel) { |
| 250 LOG(WARNING) << "Notification from unexpected source " | 268 LOG(WARNING) << "Notification from unexpected source " |
| 251 << notification.channel; | 269 << notification.channel; |
| 252 } | 270 } |
| 253 P2PNotificationData notification_data; | 271 P2PNotificationData notification_data; |
| 254 if (!notification_data.ResetFromString(notification.data)) { | 272 if (!notification_data.ResetFromString(notification.data)) { |
| 255 LOG(WARNING) << "Could not parse notification data from " | 273 LOG(WARNING) << "Could not parse notification data from " |
| 256 << notification.data; | 274 << notification.data; |
| 257 notification_data = | 275 notification_data = |
| 258 P2PNotificationData(unique_id_, NOTIFY_ALL, enabled_types_); | 276 P2PNotificationData( |
| 277 unique_id_, NOTIFY_ALL, |
| 278 ObjectIdSetToStateMap(registrar_.GetAllRegisteredIds(), ""), |
| 279 REMOTE_NOTIFICATION); |
| 259 } | 280 } |
| 260 if (!notification_data.IsTargeted(unique_id_)) { | 281 if (!notification_data.IsTargeted(unique_id_)) { |
| 261 DVLOG(1) << "Not a target of the notification -- " | 282 DVLOG(1) << "Not a target of the notification -- " |
| 262 << "not emitting notification"; | 283 << "not emitting notification"; |
| 263 return; | 284 return; |
| 264 } | 285 } |
| 265 const ModelTypeSet types_to_notify = | |
| 266 Intersection(enabled_types_, notification_data.GetChangedTypes()); | |
| 267 if (types_to_notify.Empty()) { | |
| 268 DVLOG(1) << "No enabled and changed types -- not emitting notification"; | |
| 269 return; | |
| 270 } | |
| 271 const ModelTypeStateMap& type_state_map = ModelTypeSetToStateMap( | |
| 272 notification_data.GetChangedTypes(), std::string()); | |
| 273 registrar_.DispatchInvalidationsToHandlers( | 286 registrar_.DispatchInvalidationsToHandlers( |
| 274 ModelTypeStateMapToObjectIdStateMap(type_state_map), | 287 notification_data.GetIdStateMap(), |
| 275 REMOTE_NOTIFICATION); | 288 REMOTE_NOTIFICATION); |
| 276 } | 289 } |
| 277 | 290 |
| 278 void P2PInvalidator::SendNotificationDataForTest( | 291 void P2PInvalidator::SendNotificationDataForTest( |
| 279 const P2PNotificationData& notification_data) { | 292 const P2PNotificationData& notification_data) { |
| 280 DCHECK(thread_checker_.CalledOnValidThread()); | 293 DCHECK(thread_checker_.CalledOnValidThread()); |
| 281 SendNotificationData(notification_data); | 294 SendNotificationData(notification_data); |
| 282 } | 295 } |
| 283 | 296 |
| 284 void P2PInvalidator::SendNotificationData( | 297 void P2PInvalidator::SendNotificationData( |
| 285 const P2PNotificationData& notification_data) { | 298 const P2PNotificationData& notification_data) { |
| 286 DCHECK(thread_checker_.CalledOnValidThread()); | 299 DCHECK(thread_checker_.CalledOnValidThread()); |
| 287 if (notification_data.GetChangedTypes().Empty()) { | 300 if (notification_data.GetIdStateMap().empty()) { |
| 288 DVLOG(1) << "Not sending XMPP notification with no changed types: " | 301 DVLOG(1) << "Not sending XMPP notification with empty state map: " |
| 289 << notification_data.ToString(); | 302 << notification_data.ToString(); |
| 290 return; | 303 return; |
| 291 } | 304 } |
| 292 notifier::Notification notification; | 305 notifier::Notification notification; |
| 293 notification.channel = kSyncP2PNotificationChannel; | 306 notification.channel = kSyncP2PNotificationChannel; |
| 294 notification.data = notification_data.ToString(); | 307 notification.data = notification_data.ToString(); |
| 295 DVLOG(1) << "Sending XMPP notification: " << notification.ToString(); | 308 DVLOG(1) << "Sending XMPP notification: " << notification.ToString(); |
| 296 push_client_->SendNotification(notification); | 309 push_client_->SendNotification(notification); |
| 297 } | 310 } |
| 298 | 311 |
| 299 } // namespace syncer | 312 } // namespace syncer |
| OLD | NEW |