• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/sync/notifier/p2p_notifier.h"
6 
7 #include "base/message_loop_proxy.h"
8 #include "chrome/browser/sync/notifier/sync_notifier_observer.h"
9 #include "chrome/browser/sync/protocol/service_constants.h"
10 #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 
14 namespace sync_notifier {
15 
16 namespace {
17 const char kSyncNotificationChannel[] = "http://www.google.com/chrome/sync";
18 const char kSyncNotificationData[] = "sync-ping-p2p";
19 }  // namespace
20 
P2PNotifier(const notifier::NotifierOptions & notifier_options)21 P2PNotifier::P2PNotifier(
22     const notifier::NotifierOptions& notifier_options)
23     : talk_mediator_(
24         new notifier::TalkMediatorImpl(
25             new notifier::MediatorThreadImpl(notifier_options),
26             notifier_options)),
27       logged_in_(false),
28       notifications_enabled_(false),
29       construction_message_loop_proxy_(
30           base::MessageLoopProxy::CreateForCurrentThread()) {
31   talk_mediator_->SetDelegate(this);
32 }
33 
~P2PNotifier()34 P2PNotifier::~P2PNotifier() {
35   DCHECK(construction_message_loop_proxy_->BelongsToCurrentThread());
36 }
37 
AddObserver(SyncNotifierObserver * observer)38 void P2PNotifier::AddObserver(SyncNotifierObserver* observer) {
39   CheckOrSetValidThread();
40   observer_list_.AddObserver(observer);
41 }
42 
43 // Note: Since we need to shutdown TalkMediator on the method_thread, we are
44 // calling Logout on TalkMediator when the last observer is removed.
45 // Users will need to call UpdateCredentials again to use the same object.
46 // TODO(akalin): Think of a better solution to fix this.
RemoveObserver(SyncNotifierObserver * observer)47 void P2PNotifier::RemoveObserver(SyncNotifierObserver* observer) {
48   CheckOrSetValidThread();
49   observer_list_.RemoveObserver(observer);
50 
51   // Logout after the last observer is removed.
52   if (observer_list_.size() == 0) {
53    talk_mediator_->Logout();
54   }
55 }
56 
SetState(const std::string & state)57 void P2PNotifier::SetState(const std::string& state) {
58   CheckOrSetValidThread();
59 }
60 
UpdateCredentials(const std::string & email,const std::string & token)61 void P2PNotifier::UpdateCredentials(
62     const std::string& email, const std::string& token) {
63   CheckOrSetValidThread();
64   // If already logged in, the new credentials will take effect on the
65   // next reconnection.
66   talk_mediator_->SetAuthToken(email, token, SYNC_SERVICE_NAME);
67   if (!logged_in_) {
68     if (!talk_mediator_->Login()) {
69       LOG(DFATAL) << "Could not login for " << email;
70       return;
71     }
72 
73     notifier::Subscription subscription;
74     subscription.channel = kSyncNotificationChannel;
75     // There may be some subtle issues around case sensitivity of the
76     // from field, but it doesn't matter too much since this is only
77     // used in p2p mode (which is only used in testing).
78     subscription.from = email;
79     talk_mediator_->AddSubscription(subscription);
80 
81     logged_in_ = true;
82   }
83 }
84 
UpdateEnabledTypes(const syncable::ModelTypeSet & types)85 void P2PNotifier::UpdateEnabledTypes(const syncable::ModelTypeSet& types) {
86   CheckOrSetValidThread();
87   enabled_types_ = types;
88   MaybeEmitNotification();
89 }
90 
SendNotification()91 void P2PNotifier::SendNotification() {
92   CheckOrSetValidThread();
93   VLOG(1) << "Sending XMPP notification...";
94   notifier::Notification notification;
95   notification.channel = kSyncNotificationChannel;
96   notification.data = kSyncNotificationData;
97   talk_mediator_->SendNotification(notification);
98 }
99 
OnNotificationStateChange(bool notifications_enabled)100 void P2PNotifier::OnNotificationStateChange(bool notifications_enabled) {
101   CheckOrSetValidThread();
102   notifications_enabled_ = notifications_enabled;
103   FOR_EACH_OBSERVER(SyncNotifierObserver, observer_list_,
104       OnNotificationStateChange(notifications_enabled_));
105   MaybeEmitNotification();
106 }
107 
OnIncomingNotification(const notifier::Notification & notification)108 void P2PNotifier::OnIncomingNotification(
109     const notifier::Notification& notification) {
110   CheckOrSetValidThread();
111   VLOG(1) << "Sync received P2P notification.";
112   if (notification.channel != kSyncNotificationChannel) {
113     LOG(WARNING) << "Notification from unexpected source: "
114                  << notification.channel;
115   }
116   MaybeEmitNotification();
117 }
118 
OnOutgoingNotification()119 void P2PNotifier::OnOutgoingNotification() {}
120 
MaybeEmitNotification()121 void P2PNotifier::MaybeEmitNotification() {
122   if (!logged_in_) {
123     VLOG(1) << "Not logged in yet -- not emitting notification";
124     return;
125   }
126   if (!notifications_enabled_) {
127     VLOG(1) << "Notifications not enabled -- not emitting notification";
128     return;
129   }
130   if (enabled_types_.empty()) {
131     VLOG(1) << "No enabled types -- not emitting notification";
132     return;
133   }
134   syncable::ModelTypePayloadMap type_payloads =
135       syncable::ModelTypePayloadMapFromBitSet(
136           syncable::ModelTypeBitSetFromSet(enabled_types_), std::string());
137   FOR_EACH_OBSERVER(SyncNotifierObserver, observer_list_,
138                     OnIncomingNotification(type_payloads));
139 }
140 
CheckOrSetValidThread()141 void P2PNotifier::CheckOrSetValidThread() {
142   if (method_message_loop_proxy_) {
143     DCHECK(method_message_loop_proxy_->BelongsToCurrentThread());
144   } else {
145     method_message_loop_proxy_ =
146         base::MessageLoopProxy::CreateForCurrentThread();
147   }
148 }
149 
150 }  // namespace sync_notifier
151