Home | History | Annotate | Download | only in notifier
      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 
     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 
     34 P2PNotifier::~P2PNotifier() {
     35   DCHECK(construction_message_loop_proxy_->BelongsToCurrentThread());
     36 }
     37 
     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.
     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 
     57 void P2PNotifier::SetState(const std::string& state) {
     58   CheckOrSetValidThread();
     59 }
     60 
     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 
     85 void P2PNotifier::UpdateEnabledTypes(const syncable::ModelTypeSet& types) {
     86   CheckOrSetValidThread();
     87   enabled_types_ = types;
     88   MaybeEmitNotification();
     89 }
     90 
     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 
    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 
    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 
    119 void P2PNotifier::OnOutgoingNotification() {}
    120 
    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 
    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