16acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Copyright (c) 2011 The Chromium Authors. All rights reserved.
26acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Use of this source code is governed by a BSD-style license that can be
36acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// found in the LICENSE file.
46acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
56acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include "chrome/browser/sync/notifier/p2p_notifier.h"
66acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
76acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include "base/message_loop_proxy.h"
86acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include "chrome/browser/sync/notifier/sync_notifier_observer.h"
96acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include "chrome/browser/sync/protocol/service_constants.h"
106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include "chrome/browser/sync/syncable/model_type_payload_map.h"
116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include "jingle/notifier/listener/mediator_thread_impl.h"
126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include "jingle/notifier/listener/talk_mediator_impl.h"
136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennnamespace sync_notifier {
156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennnamespace {
176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennconst char kSyncNotificationChannel[] = "http://www.google.com/chrome/sync";
186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennconst char kSyncNotificationData[] = "sync-ping-p2p";
196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}  // namespace
206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennP2PNotifier::P2PNotifier(
226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    const notifier::NotifierOptions& notifier_options)
236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    : talk_mediator_(
246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        new notifier::TalkMediatorImpl(
256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            new notifier::MediatorThreadImpl(notifier_options),
266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            notifier_options)),
276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      logged_in_(false),
286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      notifications_enabled_(false),
296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      construction_message_loop_proxy_(
306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn          base::MessageLoopProxy::CreateForCurrentThread()) {
316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  talk_mediator_->SetDelegate(this);
326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennP2PNotifier::~P2PNotifier() {
356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  DCHECK(construction_message_loop_proxy_->BelongsToCurrentThread());
366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennvoid P2PNotifier::AddObserver(SyncNotifierObserver* observer) {
396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  CheckOrSetValidThread();
406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  observer_list_.AddObserver(observer);
416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Note: Since we need to shutdown TalkMediator on the method_thread, we are
446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// calling Logout on TalkMediator when the last observer is removed.
456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Users will need to call UpdateCredentials again to use the same object.
466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// TODO(akalin): Think of a better solution to fix this.
476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennvoid P2PNotifier::RemoveObserver(SyncNotifierObserver* observer) {
486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  CheckOrSetValidThread();
496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  observer_list_.RemoveObserver(observer);
506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  // Logout after the last observer is removed.
526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  if (observer_list_.size() == 0) {
536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   talk_mediator_->Logout();
546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  }
556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennvoid P2PNotifier::SetState(const std::string& state) {
586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  CheckOrSetValidThread();
596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennvoid P2PNotifier::UpdateCredentials(
626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    const std::string& email, const std::string& token) {
636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  CheckOrSetValidThread();
646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  // If already logged in, the new credentials will take effect on the
656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  // next reconnection.
666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  talk_mediator_->SetAuthToken(email, token, SYNC_SERVICE_NAME);
676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  if (!logged_in_) {
686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if (!talk_mediator_->Login()) {
696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      LOG(DFATAL) << "Could not login for " << email;
706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      return;
716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    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
85void P2PNotifier::UpdateEnabledTypes(const syncable::ModelTypeSet& types) {
86  CheckOrSetValidThread();
87  enabled_types_ = types;
88  MaybeEmitNotification();
89}
90
91void 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
100void 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
108void 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
119void P2PNotifier::OnOutgoingNotification() {}
120
121void 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
141void 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