diff options
author | akalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-14 07:13:25 +0000 |
---|---|---|
committer | akalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-14 07:13:25 +0000 |
commit | e39ebd7e9922231ff8c1412834d2e9dc59ec7ab1 (patch) | |
tree | b8229b0362b5a9df1a210b89095e8b00a413b9e8 /chrome/browser/sync/notifier | |
parent | 79e549faf26611d5ac05bc4f7fefd4a71a23fcb2 (diff) | |
download | chromium_src-e39ebd7e9922231ff8c1412834d2e9dc59ec7ab1.zip chromium_src-e39ebd7e9922231ff8c1412834d2e9dc59ec7ab1.tar.gz chromium_src-e39ebd7e9922231ff8c1412834d2e9dc59ec7ab1.tar.bz2 |
Refactor sync notifier out of sync api
We now have a clearly defined interface for notifier.
Old p2p notifications are still used by tests.
Original patch by nileshagrawal@google.com.
BUG=75831
TEST=
Review URL: http://codereview.chromium.org/6683015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@78007 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/sync/notifier')
-rw-r--r-- | chrome/browser/sync/notifier/sync_notifier.h | 47 | ||||
-rw-r--r-- | chrome/browser/sync/notifier/sync_notifier_factory.cc | 99 | ||||
-rw-r--r-- | chrome/browser/sync/notifier/sync_notifier_factory.h | 25 | ||||
-rw-r--r-- | chrome/browser/sync/notifier/sync_notifier_impl.cc | 195 | ||||
-rw-r--r-- | chrome/browser/sync/notifier/sync_notifier_impl.h | 70 | ||||
-rw-r--r-- | chrome/browser/sync/notifier/sync_notifier_observer.h | 29 |
6 files changed, 465 insertions, 0 deletions
diff --git a/chrome/browser/sync/notifier/sync_notifier.h b/chrome/browser/sync/notifier/sync_notifier.h new file mode 100644 index 0000000..da15259 --- /dev/null +++ b/chrome/browser/sync/notifier/sync_notifier.h @@ -0,0 +1,47 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Interface to the sync notifier, which is an object that receives +// notifications when updates are available for a set of sync types. +// All the observers are notified when such an event happens. + +#ifndef CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_H_ +#define CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_H_ + +#include <string> + +#include "chrome/browser/sync/syncable/model_type.h" + +namespace sync_notifier { +class SyncNotifierObserver; + +class SyncNotifier { + public: + SyncNotifier() {} + virtual ~SyncNotifier() {} + + virtual void AddObserver(SyncNotifierObserver* observer) = 0; + virtual void RemoveObserver(SyncNotifierObserver* observer) = 0; + + // SetState must be called once, before any call to UpdateCredentials. + virtual void SetState(const std::string& state) = 0; + + // The observers won't be notified of any notifications until + // UpdateCredentials is called at least once. It can be called more than + // once. + virtual void UpdateCredentials( + const std::string& email, const std::string& token) = 0; + + virtual void UpdateEnabledTypes(const syncable::ModelTypeSet& types) = 0; + + // This is here only to support the old p2p notification implementation, + // which is still used by sync integration tests. + // TODO(akalin): Remove this once we move the integration tests off p2p + // notifications. + virtual void SendNotification() = 0; +}; +} // namespace sync_notifier + +#endif // CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_H_ + diff --git a/chrome/browser/sync/notifier/sync_notifier_factory.cc b/chrome/browser/sync/notifier/sync_notifier_factory.cc new file mode 100644 index 0000000..9f2886a --- /dev/null +++ b/chrome/browser/sync/notifier/sync_notifier_factory.cc @@ -0,0 +1,99 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/sync/notifier/sync_notifier_factory.h" + +#include <string> + +#include "base/command_line.h" +#include "base/string_number_conversions.h" +#include "base/string_util.h" +#include "chrome/browser/sync/notifier/sync_notifier.h" +#include "chrome/browser/sync/notifier/sync_notifier_impl.h" +#include "chrome/common/chrome_switches.h" +#include "jingle/notifier/base/notifier_options.h" +#include "jingle/notifier/communicator/const_communicator.h" +#include "net/base/host_port_pair.h" + +namespace sync_notifier { +namespace { + +// TODO(akalin): Figure out whether this should be a method of +// HostPortPair. +net::HostPortPair StringToHostPortPair(const std::string& host_port_str, + uint16 default_port) { + std::string::size_type colon_index = host_port_str.find(':'); + if (colon_index == std::string::npos) { + return net::HostPortPair(host_port_str, default_port); + } + + std::string host = host_port_str.substr(0, colon_index); + std::string port_str = host_port_str.substr(colon_index + 1); + int port = default_port; + if (!base::StringToInt(port_str, &port) || + (port <= 0) || (port > kuint16max)) { + LOG(WARNING) << "Could not parse valid port from " << port_str + << "; using port " << default_port; + return net::HostPortPair(host, default_port); + } + + return net::HostPortPair(host, port); +} + +SyncNotifier* CreateDefaultSyncNotifier(const CommandLine& command_line) { + // Contains options specific to how sync clients send and listen to + // jingle notifications. + notifier::NotifierOptions notifier_options; + + // Override the notification server host from the command-line, if provided. + if (command_line.HasSwitch(switches::kSyncNotificationHost)) { + std::string value(command_line.GetSwitchValueASCII( + switches::kSyncNotificationHost)); + if (!value.empty()) { + notifier_options.xmpp_host_port = + StringToHostPortPair(value, notifier::kDefaultXmppPort); + } + VLOG(1) << "Using " << notifier_options.xmpp_host_port.ToString() + << " for test sync notification server."; + } + + notifier_options.try_ssltcp_first = + command_line.HasSwitch(switches::kSyncTrySsltcpFirstForXmpp); + if (notifier_options.try_ssltcp_first) + VLOG(1) << "Trying SSL/TCP port before XMPP port for notifications."; + + notifier_options.invalidate_xmpp_login = + command_line.HasSwitch(switches::kSyncInvalidateXmppLogin); + if (notifier_options.invalidate_xmpp_login) { + VLOG(1) << "Invalidating sync XMPP login."; + } + + notifier_options.allow_insecure_connection = + command_line.HasSwitch(switches::kSyncAllowInsecureXmppConnection); + if (notifier_options.allow_insecure_connection) { + VLOG(1) << "Allowing insecure XMPP connections."; + } + + if (command_line.HasSwitch(switches::kSyncNotificationMethod)) { + const std::string notification_method_str( + command_line.GetSwitchValueASCII(switches::kSyncNotificationMethod)); + notifier_options.notification_method = + notifier::StringToNotificationMethod(notification_method_str); + } + + return new SyncNotifierImpl(notifier_options); +} +} // namespace + +SyncNotifierFactory::SyncNotifierFactory() { +} + +SyncNotifierFactory::~SyncNotifierFactory() { +} + +SyncNotifier* SyncNotifierFactory::CreateSyncNotifier( + const CommandLine& command_line) { + return CreateDefaultSyncNotifier(command_line); +} +} // namespace sync_notifier diff --git a/chrome/browser/sync/notifier/sync_notifier_factory.h b/chrome/browser/sync/notifier/sync_notifier_factory.h new file mode 100644 index 0000000..a9da82e --- /dev/null +++ b/chrome/browser/sync/notifier/sync_notifier_factory.h @@ -0,0 +1,25 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_FACTORY_H_ +#define CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_FACTORY_H_ + +class CommandLine; + +namespace sync_notifier { +class SyncNotifier; + +// Class to instantiate various implementations of the SyncNotifier interface. +class SyncNotifierFactory { + public: + SyncNotifierFactory(); + ~SyncNotifierFactory(); + + // Creates the appropriate sync notifier. The caller should take ownership + // of the object returned and delete it when no longer used. + SyncNotifier* CreateSyncNotifier(const CommandLine& command_line); +}; +} // namespace sync_notifier + +#endif // CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_FACTORY_H_ diff --git a/chrome/browser/sync/notifier/sync_notifier_impl.cc b/chrome/browser/sync/notifier/sync_notifier_impl.cc new file mode 100644 index 0000000..d8d7ca6 --- /dev/null +++ b/chrome/browser/sync/notifier/sync_notifier_impl.cc @@ -0,0 +1,195 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/sync/notifier/sync_notifier_impl.h" + +#include "chrome/browser/sync/notifier/server_notifier_thread.h" +#include "chrome/browser/sync/notifier/sync_notifier_observer.h" +#include "chrome/browser/sync/protocol/service_constants.h" +#include "chrome/browser/sync/sessions/session_state.h" +#include "chrome/browser/sync/sync_constants.h" +#include "chrome/browser/sync/syncable/model_type.h" +#include "jingle/notifier/listener/mediator_thread_impl.h" +#include "jingle/notifier/listener/notification_constants.h" + +// TODO(akalin): Split this class into two implementations - one for p2p and +// one for server issued notifications. +using notifier::TalkMediator; +using notifier::TalkMediatorImpl; +namespace sync_notifier { + +SyncNotifierImpl::SyncNotifierImpl( + const notifier::NotifierOptions& notifier_options) + : notifier_options_(notifier_options), + server_notifier_thread_(NULL) { } + +SyncNotifierImpl::~SyncNotifierImpl() { + scoped_ptr<TalkMediator> talk_mediator(talk_mediator_.release()); + + // Shutdown the xmpp buzz connection. + if (talk_mediator.get()) { + VLOG(1) << "P2P: Mediator logout started."; + talk_mediator->Logout(); + VLOG(1) << "P2P: Mediator logout completed."; + talk_mediator.reset(); + + // |server_notifier_thread_| is owned by |talk_mediator|. We NULL + // it out here so as to not have a dangling pointer. + server_notifier_thread_= NULL; + VLOG(1) << "P2P: Mediator destroyed."; + } +} + +void SyncNotifierImpl::AddObserver(SyncNotifierObserver* observer) { + observer_list_.AddObserver(observer); +} + +void SyncNotifierImpl::RemoveObserver(SyncNotifierObserver* observer) { + observer_list_.RemoveObserver(observer); +} + +void SyncNotifierImpl::OnNotificationStateChange(bool notifications_enabled) { + FOR_EACH_OBSERVER(SyncNotifierObserver, observer_list_, + OnNotificationStateChange(notifications_enabled)); + + // If using p2p notifications, generate a notification for all enabled types. + // Used only for tests. + if ((notifier_options_.notification_method != + notifier::NOTIFICATION_SERVER) && notifications_enabled) { + browser_sync::sessions::TypePayloadMap model_types_with_payloads = + browser_sync::sessions::MakeTypePayloadMapFromBitSet( + syncable::ModelTypeBitSetFromSet(enabled_types_), std::string()); + FOR_EACH_OBSERVER(SyncNotifierObserver, observer_list_, + OnIncomingNotification(model_types_with_payloads)); + } +} + +void SyncNotifierImpl::OnIncomingNotification( + const IncomingNotificationData& notification_data) { + browser_sync::sessions::TypePayloadMap model_types_with_payloads; + + // Check if the service url is a sync URL. An empty service URL is + // treated as a legacy sync notification. If we're listening to + // server-issued notifications, no need to check the service_url. + if (notifier_options_.notification_method == + notifier::NOTIFICATION_SERVER) { + VLOG(1) << "Sync received server notification from " << + notification_data.service_url << ": " << + notification_data.service_specific_data; + syncable::ModelTypeBitSet model_types; + const std::string& model_type_list = notification_data.service_url; + const std::string& notification_payload = + notification_data.service_specific_data; + + if (!syncable::ModelTypeBitSetFromString(model_type_list, &model_types)) { + LOG(DFATAL) << "Could not extract model types from server data."; + model_types.set(); + } + + model_types_with_payloads = + browser_sync::sessions::MakeTypePayloadMapFromBitSet(model_types, + notification_payload); + } else if (notification_data.service_url.empty() || + (notification_data.service_url == + browser_sync::kSyncLegacyServiceUrl) || + (notification_data.service_url == + browser_sync::kSyncServiceUrl)) { + VLOG(1) << "Sync received P2P notification."; + + // Catch for sync integration tests (uses p2p). Just set all enabled + // datatypes. + model_types_with_payloads = + browser_sync::sessions::MakeTypePayloadMapFromBitSet( + syncable::ModelTypeBitSetFromSet(enabled_types_), std::string()); + } else { + LOG(WARNING) << "Notification fron unexpected source: " + << notification_data.service_url; + } + + FOR_EACH_OBSERVER(SyncNotifierObserver, observer_list_, + OnIncomingNotification(model_types_with_payloads)); +} + +void SyncNotifierImpl::WriteState(const std::string& state) { + FOR_EACH_OBSERVER(SyncNotifierObserver, observer_list_, + StoreState(state)); +} + +void SyncNotifierImpl::UpdateCredentials( + const std::string& email, const std::string& token) { + // Reset talk_mediator_ before creating ServerNotifierThread/MediatorThread, + // to avoid any problems with having two of those threads at the same time. + talk_mediator_.reset(); + + if (notifier_options_.notification_method == + notifier::NOTIFICATION_SERVER) { + // |talk_mediator_| takes ownership of |sync_notifier_thread_| + // but it is guaranteed that |sync_notifier_thread_| is destroyed only + // when |talk_mediator_| is (see the comments in talk_mediator.h). + server_notifier_thread_ = new sync_notifier::ServerNotifierThread( + notifier_options_, state_, this); + talk_mediator_.reset( + new TalkMediatorImpl(server_notifier_thread_, + notifier_options_.invalidate_xmpp_login, + notifier_options_.allow_insecure_connection)); + + // Since we may be initialized more than once, make sure that any + // newly created server notifier thread has the latest enabled types. + server_notifier_thread_->UpdateEnabledTypes(enabled_types_); + } else { + notifier::MediatorThread* mediator_thread = + new notifier::MediatorThreadImpl(notifier_options_); + talk_mediator_.reset( + new TalkMediatorImpl(mediator_thread, + notifier_options_.invalidate_xmpp_login, + notifier_options_.allow_insecure_connection)); + talk_mediator_->AddSubscribedServiceUrl(browser_sync::kSyncServiceUrl); + server_notifier_thread_ = NULL; + } + talk_mediator_->SetDelegate(this); + talk_mediator_->SetAuthToken(email, token, SYNC_SERVICE_NAME); + talk_mediator_->Login(); +} + +void SyncNotifierImpl::SetState(const std::string& state) { + state_ = state; +} + +void SyncNotifierImpl::UpdateEnabledTypes(const syncable::ModelTypeSet& types) { + enabled_types_ = types; + if (server_notifier_thread_ != NULL) { + server_notifier_thread_->UpdateEnabledTypes(types); + } +} + +void SyncNotifierImpl::SendNotification() { + // Do nothing if we are using server based notifications. + if (notifier_options_.notification_method == + notifier::NOTIFICATION_SERVER) { + return; + } + + if (!talk_mediator_.get()) { + NOTREACHED() << "Cannot send notification: talk_mediator_ is NULL"; + return; + } + + VLOG(1) << "Sending XMPP notification..."; + OutgoingNotificationData notification_data; + notification_data.service_id = browser_sync::kSyncServiceId; + notification_data.service_url = browser_sync::kSyncServiceUrl; + notification_data.send_content = true; + notification_data.priority = browser_sync::kSyncPriority; + notification_data.write_to_cache_only = true; + notification_data.service_specific_data = + browser_sync::kSyncServiceSpecificData; + notification_data.require_subscription = true; + bool success = talk_mediator_->SendNotification(notification_data); + if (success) { + VLOG(1) << "Sent XMPP notification"; + } else { + VLOG(1) << "Could not send XMPP notification"; + } +} +} // namespace sync_notifier diff --git a/chrome/browser/sync/notifier/sync_notifier_impl.h b/chrome/browser/sync/notifier/sync_notifier_impl.h new file mode 100644 index 0000000..ccf8d9c --- /dev/null +++ b/chrome/browser/sync/notifier/sync_notifier_impl.h @@ -0,0 +1,70 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Talk Mediator based implementation of the sync notifier interface. +// Initializes the talk mediator and registers itself as the delegate. + +#ifndef CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_IMPL_H_ +#define CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_IMPL_H_ + +#include <string> + +#include "base/observer_list.h" +#include "chrome/browser/sync/notifier/state_writer.h" +#include "chrome/browser/sync/notifier/sync_notifier.h" +#include "chrome/browser/sync/syncable/model_type.h" +#include "jingle/notifier/base/notifier_options.h" +#include "jingle/notifier/listener/talk_mediator.h" +#include "jingle/notifier/listener/talk_mediator_impl.h" + +namespace sync_notifier { +class ServerNotifierThread; + +class SyncNotifierImpl + : public SyncNotifier, + public sync_notifier::StateWriter, + public notifier::TalkMediator::Delegate { + public: + explicit SyncNotifierImpl(const notifier::NotifierOptions& notifier_options); + + virtual ~SyncNotifierImpl(); + + // TalkMediator::Delegate implementation. + virtual void OnNotificationStateChange(bool notifications_enabled); + + virtual void OnIncomingNotification( + const IncomingNotificationData& notification_data); + + virtual void OnOutgoingNotification() {} + + // sync_notifier::StateWriter implementation. + virtual void WriteState(const std::string& state); + + // SyncNotifier implementation + virtual void UpdateCredentials( + const std::string& email, const std::string& token); + + virtual void SetState(const std::string& state); + + virtual void AddObserver(SyncNotifierObserver* observer); + virtual void RemoveObserver(SyncNotifierObserver* observer); + + virtual void UpdateEnabledTypes(const syncable::ModelTypeSet& types); + virtual void SendNotification(); + private: + // Login to the talk mediator with the given credentials. + void TalkMediatorLogin( + const std::string& email, const std::string& token); + + // Notification (xmpp) handler. + scoped_ptr<notifier::TalkMediator> talk_mediator_; + syncable::ModelTypeSet enabled_types_; + std::string state_; + + notifier::NotifierOptions notifier_options_; + ServerNotifierThread* server_notifier_thread_; + ObserverList<SyncNotifierObserver> observer_list_; +}; +} +#endif // CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_IMPL_H_ diff --git a/chrome/browser/sync/notifier/sync_notifier_observer.h b/chrome/browser/sync/notifier/sync_notifier_observer.h new file mode 100644 index 0000000..2978d17 --- /dev/null +++ b/chrome/browser/sync/notifier/sync_notifier_observer.h @@ -0,0 +1,29 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + + +#ifndef CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_OBSERVER_H_ +#define CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_OBSERVER_H_ + +#include <string> + +#include "chrome/browser/sync/sessions/session_state.h" + +namespace sync_notifier { + +class SyncNotifierObserver { + public: + SyncNotifierObserver() {} + virtual ~SyncNotifierObserver() {} + + virtual void OnIncomingNotification( + const browser_sync::sessions::TypePayloadMap& type_payloads) = 0; + virtual void OnNotificationStateChange(bool notifications_enabled) = 0; + + // TODO(nileshagrawal): Find a way to hide state handling inside the + // sync notifier implementation. + virtual void StoreState(const std::string& state) = 0; +}; +} // namespace sync_notifier +#endif // CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_OBSERVER_H_ |