OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "chrome/browser/sync/notifier/p2p_notifier.h" | 5 #include "chrome/browser/sync/notifier/p2p_notifier.h" |
6 | 6 |
7 #include <algorithm> | |
8 | |
9 #include "base/logging.h" | |
7 #include "base/message_loop_proxy.h" | 10 #include "base/message_loop_proxy.h" |
11 #include "base/json/json_reader.h" | |
12 #include "base/json/json_writer.h" | |
13 #include "base/values.h" | |
8 #include "chrome/browser/sync/notifier/sync_notifier_observer.h" | 14 #include "chrome/browser/sync/notifier/sync_notifier_observer.h" |
9 #include "chrome/browser/sync/protocol/service_constants.h" | 15 #include "chrome/browser/sync/protocol/service_constants.h" |
10 #include "chrome/browser/sync/syncable/model_type_payload_map.h" | 16 #include "chrome/browser/sync/syncable/model_type_payload_map.h" |
11 #include "jingle/notifier/listener/mediator_thread_impl.h" | |
12 #include "jingle/notifier/listener/talk_mediator_impl.h" | |
13 | 17 |
14 namespace sync_notifier { | 18 namespace sync_notifier { |
15 | 19 |
16 namespace { | 20 namespace { |
21 | |
17 const char kSyncNotificationChannel[] = "http://www.google.com/chrome/sync"; | 22 const char kSyncNotificationChannel[] = "http://www.google.com/chrome/sync"; |
18 const char kSyncNotificationData[] = "sync-ping-p2p"; | 23 |
24 const char kNotifySelf[] = "notifySelf"; | |
25 const char kNotifyOthers[] = "notifyOthers"; | |
26 const char kNotifyAll[] = "notifyAll"; | |
27 | |
28 const char kSenderIdKey[] = "senderId"; | |
29 const char kNotificationTypeKey[] = "notificationType"; | |
30 const char kChangedTypesKey[] = "changedTypes"; | |
31 | |
19 } // namespace | 32 } // namespace |
20 | 33 |
21 P2PNotifier::P2PNotifier( | 34 std::string P2PNotificationTargetToString(P2PNotificationTarget target) { |
22 const notifier::NotifierOptions& notifier_options) | 35 switch (target) { |
23 : talk_mediator_( | 36 case NOTIFY_SELF: |
24 new notifier::TalkMediatorImpl( | 37 return kNotifySelf; |
25 new notifier::MediatorThreadImpl(notifier_options), | 38 case NOTIFY_OTHERS: |
26 notifier_options)), | 39 return kNotifyOthers; |
40 case NOTIFY_ALL: | |
41 return kNotifyAll; | |
42 default: | |
43 NOTREACHED(); | |
44 return ""; | |
45 } | |
46 } | |
47 | |
48 P2PNotificationTarget P2PNotificationTargetFromString( | |
49 const std::string& target_str) { | |
50 if (target_str == kNotifySelf) { | |
51 return NOTIFY_SELF; | |
52 } | |
53 if (target_str == kNotifyOthers) { | |
54 return NOTIFY_OTHERS; | |
55 } | |
56 if (target_str == kNotifyAll) { | |
57 return NOTIFY_ALL; | |
58 } | |
59 LOG(WARNING) << "Could not parse " << target_str; | |
60 return NOTIFY_SELF; | |
61 } | |
62 | |
63 P2PNotificationData::P2PNotificationData() : target_(NOTIFY_SELF) {} | |
64 | |
65 P2PNotificationData::P2PNotificationData( | |
66 const std::string& sender_id, | |
67 P2PNotificationTarget target, | |
68 const syncable::ModelTypeSet& changed_types) | |
69 : sender_id_(sender_id), | |
70 target_(target), | |
71 changed_types_(changed_types) {} | |
72 | |
73 P2PNotificationData::~P2PNotificationData() {} | |
74 | |
75 bool P2PNotificationData::IsTargeted(const std::string& id) const { | |
76 switch (target_) { | |
77 case NOTIFY_SELF: | |
78 return sender_id_ == id; | |
79 case NOTIFY_OTHERS: | |
80 return sender_id_ != id; | |
81 case NOTIFY_ALL: | |
82 return true; | |
83 default: | |
84 NOTREACHED(); | |
85 return false; | |
86 } | |
87 } | |
88 | |
89 const syncable::ModelTypeSet& P2PNotificationData::GetChangedTypes() const { | |
90 return changed_types_; | |
91 } | |
92 | |
93 bool P2PNotificationData::Equals(const P2PNotificationData& other) const { | |
94 return | |
95 (sender_id_ == other.sender_id_) && | |
96 (target_ == other.target_) && | |
97 (changed_types_ == other.changed_types_); | |
98 } | |
99 | |
100 std::string P2PNotificationData::ToString() const { | |
101 scoped_ptr<DictionaryValue> dict(new DictionaryValue()); | |
102 dict->SetString(kSenderIdKey, sender_id_); | |
103 dict->SetString(kNotificationTypeKey, | |
104 P2PNotificationTargetToString(target_)); | |
105 dict->Set(kChangedTypesKey, syncable::ModelTypeSetToValue(changed_types_)); | |
106 std::string json; | |
107 base::JSONWriter::Write(dict.get(), false /* pretty_print */, &json); | |
108 return json; | |
109 } | |
110 | |
111 bool P2PNotificationData::FromString(const std::string& str) { | |
112 scoped_ptr<Value> data_value( | |
113 base::JSONReader::Read(str, false /* allow_trailing_comma */)); | |
114 DictionaryValue* data_dict = NULL; | |
115 if (!data_value.get()) { | |
116 LOG(WARNING) << "Could not parse " << str; | |
117 return false; | |
118 } | |
119 if (!data_value->GetAsDictionary(&data_dict)) { | |
120 LOG(WARNING) << "Could not parse " << str << " as a dictionary"; | |
121 return false; | |
122 } | |
123 if (!data_dict->GetString(kSenderIdKey, &sender_id_)) { | |
124 LOG(WARNING) << "Could not find string value for " << kSenderIdKey; | |
125 } | |
126 std::string target_str; | |
127 if (!data_dict->GetString(kNotificationTypeKey, &target_str)) { | |
128 LOG(WARNING) << "Could not find string value for " | |
129 << kNotificationTypeKey; | |
130 } | |
131 target_ = P2PNotificationTargetFromString(target_str); | |
132 ListValue* changed_types_list = NULL; | |
133 if (!data_dict->GetList(kChangedTypesKey, &changed_types_list)) { | |
134 LOG(WARNING) << "Could not find list value for " | |
135 << kChangedTypesKey; | |
136 return false; | |
137 } | |
138 changed_types_ = syncable::ModelTypeSetFromValue(*changed_types_list); | |
139 return true; | |
140 } | |
141 | |
142 P2PNotifier::P2PNotifier(notifier::TalkMediator* talk_mediator) | |
143 : talk_mediator_(talk_mediator), | |
27 logged_in_(false), | 144 logged_in_(false), |
28 notifications_enabled_(false), | 145 notifications_enabled_(false), |
29 parent_message_loop_proxy_( | 146 parent_message_loop_proxy_( |
30 base::MessageLoopProxy::current()) { | 147 base::MessageLoopProxy::current()) { |
31 talk_mediator_->SetDelegate(this); | 148 talk_mediator_->SetDelegate(this); |
32 } | 149 } |
33 | 150 |
34 P2PNotifier::~P2PNotifier() { | 151 P2PNotifier::~P2PNotifier() { |
35 DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); | 152 DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); |
36 } | 153 } |
(...skipping 12 matching lines...) Expand all Loading... | |
49 observer_list_.RemoveObserver(observer); | 166 observer_list_.RemoveObserver(observer); |
50 | 167 |
51 // Logout after the last observer is removed. | 168 // Logout after the last observer is removed. |
52 if (observer_list_.size() == 0) { | 169 if (observer_list_.size() == 0) { |
53 talk_mediator_->Logout(); | 170 talk_mediator_->Logout(); |
54 } | 171 } |
55 } | 172 } |
56 | 173 |
57 void P2PNotifier::SetUniqueId(const std::string& unique_id) { | 174 void P2PNotifier::SetUniqueId(const std::string& unique_id) { |
58 DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); | 175 DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); |
176 unique_id_ = unique_id; | |
59 } | 177 } |
60 | 178 |
61 void P2PNotifier::SetState(const std::string& state) { | 179 void P2PNotifier::SetState(const std::string& state) { |
62 DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); | 180 DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); |
63 } | 181 } |
64 | 182 |
65 void P2PNotifier::UpdateCredentials( | 183 void P2PNotifier::UpdateCredentials( |
66 const std::string& email, const std::string& token) { | 184 const std::string& email, const std::string& token) { |
67 DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); | 185 DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); |
68 // If already logged in, the new credentials will take effect on the | 186 // If already logged in, the new credentials will take effect on the |
(...skipping 10 matching lines...) Expand all Loading... | |
79 // There may be some subtle issues around case sensitivity of the | 197 // There may be some subtle issues around case sensitivity of the |
80 // from field, but it doesn't matter too much since this is only | 198 // from field, but it doesn't matter too much since this is only |
81 // used in p2p mode (which is only used in testing). | 199 // used in p2p mode (which is only used in testing). |
82 subscription.from = email; | 200 subscription.from = email; |
83 talk_mediator_->AddSubscription(subscription); | 201 talk_mediator_->AddSubscription(subscription); |
84 | 202 |
85 logged_in_ = true; | 203 logged_in_ = true; |
86 } | 204 } |
87 } | 205 } |
88 | 206 |
89 void P2PNotifier::UpdateEnabledTypes(const syncable::ModelTypeSet& types) { | 207 void P2PNotifier::UpdateEnabledTypes( |
208 const syncable::ModelTypeSet& enabled_types) { | |
90 DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); | 209 DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); |
91 enabled_types_ = types; | 210 syncable::ModelTypeSet new_enabled_types; |
92 MaybeEmitNotification(); | 211 std::set_difference(enabled_types.begin(), enabled_types.end(), |
212 enabled_types_.begin(), enabled_types_.end(), | |
213 std::inserter(new_enabled_types, | |
214 new_enabled_types.end())); | |
215 enabled_types_ = enabled_types; | |
216 const P2PNotificationData notification_data( | |
217 unique_id_, NOTIFY_SELF, new_enabled_types); | |
218 SendNotificationData(notification_data); | |
93 } | 219 } |
94 | 220 |
95 void P2PNotifier::SendNotification() { | 221 void P2PNotifier::SendNotification( |
222 const syncable::ModelTypeSet& changed_types) { | |
96 DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); | 223 DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); |
97 VLOG(1) << "Sending XMPP notification..."; | 224 const P2PNotificationData notification_data( |
98 notifier::Notification notification; | 225 unique_id_, NOTIFY_OTHERS, changed_types); |
99 notification.channel = kSyncNotificationChannel; | 226 SendNotificationData(notification_data); |
100 notification.data = kSyncNotificationData; | |
101 talk_mediator_->SendNotification(notification); | |
102 } | 227 } |
103 | 228 |
104 void P2PNotifier::OnNotificationStateChange(bool notifications_enabled) { | 229 void P2PNotifier::OnNotificationStateChange(bool notifications_enabled) { |
105 DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); | 230 DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); |
231 bool disabled_to_enabled = notifications_enabled && !notifications_enabled_; | |
106 notifications_enabled_ = notifications_enabled; | 232 notifications_enabled_ = notifications_enabled; |
107 FOR_EACH_OBSERVER(SyncNotifierObserver, observer_list_, | 233 FOR_EACH_OBSERVER(SyncNotifierObserver, observer_list_, |
108 OnNotificationStateChange(notifications_enabled_)); | 234 OnNotificationStateChange(notifications_enabled_)); |
109 MaybeEmitNotification(); | 235 if (disabled_to_enabled) { |
236 const P2PNotificationData notification_data( | |
237 unique_id_, NOTIFY_SELF, enabled_types_); | |
238 SendNotificationData(notification_data); | |
239 } | |
110 } | 240 } |
111 | 241 |
112 void P2PNotifier::OnIncomingNotification( | 242 void P2PNotifier::OnIncomingNotification( |
113 const notifier::Notification& notification) { | 243 const notifier::Notification& notification) { |
114 DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); | 244 DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); |
115 VLOG(1) << "Sync received P2P notification."; | 245 VLOG(1) << "Received notification " << notification.ToString(); |
116 if (notification.channel != kSyncNotificationChannel) { | |
117 LOG(WARNING) << "Notification from unexpected source: " | |
118 << notification.channel; | |
119 } | |
120 MaybeEmitNotification(); | |
121 } | |
122 | |
123 void P2PNotifier::OnOutgoingNotification() {} | |
124 | |
125 void P2PNotifier::MaybeEmitNotification() { | |
126 if (!logged_in_) { | 246 if (!logged_in_) { |
127 VLOG(1) << "Not logged in yet -- not emitting notification"; | 247 VLOG(1) << "Not logged in yet -- not emitting notification"; |
128 return; | 248 return; |
129 } | 249 } |
130 if (!notifications_enabled_) { | 250 if (!notifications_enabled_) { |
131 VLOG(1) << "Notifications not enabled -- not emitting notification"; | 251 VLOG(1) << "Notifications not enabled -- not emitting notification"; |
132 return; | 252 return; |
133 } | 253 } |
134 if (enabled_types_.empty()) { | 254 if (notification.channel != kSyncNotificationChannel) { |
135 VLOG(1) << "No enabled types -- not emitting notification"; | 255 LOG(WARNING) << "Notification from unexpected source " |
256 << notification.channel; | |
257 } | |
258 P2PNotificationData notification_data; | |
259 if (!notification_data.FromString(notification.data)) { | |
260 LOG(WARNING) << "Could not parse notification data from " | |
261 << notification.data; | |
262 notification_data = | |
263 P2PNotificationData(unique_id_, NOTIFY_ALL, enabled_types_); | |
264 } | |
265 if (!notification_data.IsTargeted(unique_id_)) { | |
266 VLOG(1) << "Not a target of the notification -- " | |
267 << "not emitting notification"; | |
136 return; | 268 return; |
137 } | 269 } |
138 syncable::ModelTypePayloadMap type_payloads = | 270 if (notification_data.GetChangedTypes().empty()) { |
271 VLOG(1) << "No changed types -- not emitting notification"; | |
272 return; | |
273 } | |
Nicolas Zea
2011/08/26 21:19:14
Should this check to see if the changed types are
akalin
2011/08/26 22:42:27
The InvalidationNotifier doesn't, so I don't think
| |
274 const syncable::ModelTypePayloadMap& type_payloads = | |
139 syncable::ModelTypePayloadMapFromBitSet( | 275 syncable::ModelTypePayloadMapFromBitSet( |
Nicolas Zea
2011/08/26 21:19:14
We really need to standardize bitset vs set, but t
akalin
2011/08/26 22:42:27
Yeah. Although I think it's better to make a spec
| |
140 syncable::ModelTypeBitSetFromSet(enabled_types_), std::string()); | 276 syncable::ModelTypeBitSetFromSet( |
277 notification_data.GetChangedTypes()), std::string()); | |
141 FOR_EACH_OBSERVER(SyncNotifierObserver, observer_list_, | 278 FOR_EACH_OBSERVER(SyncNotifierObserver, observer_list_, |
142 OnIncomingNotification(type_payloads)); | 279 OnIncomingNotification(type_payloads)); |
143 } | 280 } |
144 | 281 |
282 void P2PNotifier::OnOutgoingNotification() {} | |
283 | |
284 void P2PNotifier::SendNotificationDataForTest( | |
285 const P2PNotificationData& notification_data) { | |
286 SendNotificationData(notification_data); | |
287 } | |
288 | |
289 void P2PNotifier::SendNotificationData( | |
290 const P2PNotificationData& notification_data) { | |
291 DCHECK(parent_message_loop_proxy_->BelongsToCurrentThread()); | |
292 notifier::Notification notification; | |
293 notification.channel = kSyncNotificationChannel; | |
294 notification.data = notification_data.ToString(); | |
295 VLOG(1) << "Sending XMPP notification: " << notification.ToString(); | |
296 talk_mediator_->SendNotification(notification); | |
297 } | |
298 | |
145 } // namespace sync_notifier | 299 } // namespace sync_notifier |
OLD | NEW |