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