diff options
author | akalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-03 04:28:11 +0000 |
---|---|---|
committer | akalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-03 04:28:11 +0000 |
commit | 523508cebbed52ab8645694d3889547cb13b3e7e (patch) | |
tree | 2208471b583e7c6dc153481e1b2d4bb72896384a /sync/tools | |
parent | 8af3f2c6032b00e7a4d1a81b37f5b6751fd6f9a9 (diff) | |
download | chromium_src-523508cebbed52ab8645694d3889547cb13b3e7e.zip chromium_src-523508cebbed52ab8645694d3889547cb13b3e7e.tar.gz chromium_src-523508cebbed52ab8645694d3889547cb13b3e7e.tar.bz2 |
[Sync] Add sync_client tool
sync_client is a command-line sync client. Currently, it just downloads
the sync data for the given user and listens for new changes.
Fix logging in server_connection_manager.cc.
Clean up sync_listen_notifications a bit.
BUG=135536
TEST=
Review URL: https://chromiumcodereview.appspot.com/10704071
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@145254 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sync/tools')
-rw-r--r-- | sync/tools/DEPS | 5 | ||||
-rw-r--r-- | sync/tools/sync_client.cc | 378 | ||||
-rw-r--r-- | sync/tools/sync_listen_notifications.cc | 86 |
3 files changed, 426 insertions, 43 deletions
diff --git a/sync/tools/DEPS b/sync/tools/DEPS index f4429c8..322ec26 100644 --- a/sync/tools/DEPS +++ b/sync/tools/DEPS @@ -1,6 +1,9 @@ include_rules = [ "+jingle/notifier/base", "+net", + "+sync/internal_api/public", + "+sync/js", "+sync/notifier", - "+sync/internal_api/public/base", + # TODO(akalin): Remove this when we use the system encryptor. + "+sync/test/fake_encryptor.h", ] diff --git a/sync/tools/sync_client.cc b/sync/tools/sync_client.cc new file mode 100644 index 0000000..8d98646 --- /dev/null +++ b/sync/tools/sync_client.cc @@ -0,0 +1,378 @@ +// Copyright (c) 2012 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 <cstddef> +#include <cstdio> +#include <string> + +#include "base/at_exit.h" +#include "base/base64.h" +#include "base/command_line.h" +#include "base/compiler_specific.h" +#include "base/debug/stack_trace.h" +#include "base/json/json_writer.h" +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/message_loop.h" +#include "base/scoped_temp_dir.h" +#include "base/task_runner.h" +#include "base/threading/thread.h" +#include "jingle/notifier/base/notification_method.h" +#include "jingle/notifier/base/notifier_options.h" +#include "net/base/host_port_pair.h" +#include "net/base/host_resolver.h" +#include "net/base/network_change_notifier.h" +#include "net/url_request/url_request_test_util.h" +#include "sync/internal_api/public/base/model_type.h" +#include "sync/internal_api/public/base_node.h" +#include "sync/internal_api/public/engine/passive_model_worker.h" +#include "sync/internal_api/public/http_bridge.h" +#include "sync/internal_api/public/read_node.h" +#include "sync/internal_api/public/sync_manager.h" +#include "sync/internal_api/public/util/report_unrecoverable_error_function.h" +#include "sync/internal_api/public/util/unrecoverable_error_handler.h" +#include "sync/internal_api/public/util/weak_handle.h" +#include "sync/js/js_event_details.h" +#include "sync/js/js_event_handler.h" +#include "sync/notifier/invalidation_state_tracker.h" +#include "sync/notifier/sync_notifier_factory.h" +#include "sync/test/fake_encryptor.h" + +#if defined(OS_MACOSX) +#include "base/mac/scoped_nsautorelease_pool.h" +#endif + +// This is a simple utility that initializes a sync client and +// prints out any events. + +// TODO(akalin): Refactor to combine shared code with +// sync_listen_notifications. +namespace { + +const char kEmailSwitch[] = "email"; +const char kTokenSwitch[] = "token"; +const char kXmppHostPortSwitch[] = "xmpp-host-port"; +const char kXmppTrySslTcpFirstSwitch[] = "xmpp-try-ssltcp-first"; +const char kXmppAllowInsecureConnectionSwitch[] = + "xmpp-allow-insecure-connection"; +const char kNotificationMethodSwitch[] = "notification-method"; + +class NullInvalidationStateTracker + : public base::SupportsWeakPtr<NullInvalidationStateTracker>, + public syncer::InvalidationStateTracker { + public: + NullInvalidationStateTracker() {} + virtual ~NullInvalidationStateTracker() {} + + virtual syncer::InvalidationVersionMap + GetAllMaxVersions() const OVERRIDE { + return syncer::InvalidationVersionMap(); + } + + virtual void SetMaxVersion( + const invalidation::ObjectId& id, + int64 max_invalidation_version) OVERRIDE { + VLOG(1) << "Setting max invalidation version for " + << syncer::ObjectIdToString(id) << " to " + << max_invalidation_version; + } + + virtual std::string GetInvalidationState() const OVERRIDE { + return std::string(); + } + + virtual void SetInvalidationState(const std::string& state) OVERRIDE { + std::string base64_state; + CHECK(base::Base64Encode(state, &base64_state)); + VLOG(1) << "Setting invalidation state to: " << base64_state; + } +}; + +// Needed to use a real host resolver. +class MyTestURLRequestContext : public TestURLRequestContext { + public: + MyTestURLRequestContext() : TestURLRequestContext(true) { + context_storage_.set_host_resolver( + net::CreateSystemHostResolver( + net::HostResolver::kDefaultParallelism, + net::HostResolver::kDefaultRetryAttempts, + NULL)); + Init(); + } + + virtual ~MyTestURLRequestContext() {} +}; + +class MyTestURLRequestContextGetter : public TestURLRequestContextGetter { + public: + explicit MyTestURLRequestContextGetter( + const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy) + : TestURLRequestContextGetter(io_message_loop_proxy) {} + + virtual TestURLRequestContext* GetURLRequestContext() OVERRIDE { + // Construct |context_| lazily so it gets constructed on the right + // thread (the IO thread). + if (!context_.get()) + context_.reset(new MyTestURLRequestContext()); + return context_.get(); + } + + private: + virtual ~MyTestURLRequestContextGetter() {} + + scoped_ptr<MyTestURLRequestContext> context_; +}; + +// TODO(akalin): Use system encryptor once it's moved to sync/. +class NullEncryptor : public syncer::Encryptor { + public: + virtual ~NullEncryptor() {} + + virtual bool EncryptString(const std::string& plaintext, + std::string* ciphertext) OVERRIDE { + *ciphertext = plaintext; + return true; + } + + virtual bool DecryptString(const std::string& ciphertext, + std::string* plaintext) OVERRIDE { + *plaintext = ciphertext; + return true; + } +}; + +std::string ValueToString(const Value& value) { + std::string str; + base::JSONWriter::Write(&value, &str); + return str; +} + +class LoggingChangeDelegate : public syncer::SyncManager::ChangeDelegate { + public: + virtual ~LoggingChangeDelegate() {} + + virtual void OnChangesApplied( + syncable::ModelType model_type, + const syncer::BaseTransaction* trans, + const syncer::ImmutableChangeRecordList& changes) OVERRIDE { + LOG(INFO) << "Changes applied for " + << syncable::ModelTypeToString(model_type); + size_t i = 1; + size_t change_count = changes.Get().size(); + for (syncer::ChangeRecordList::const_iterator it = + changes.Get().begin(); it != changes.Get().end(); ++it) { + scoped_ptr<base::DictionaryValue> change_value(it->ToValue()); + LOG(INFO) << "Change (" << i << "/" << change_count << "): " + << ValueToString(*change_value); + if (it->action != syncer::ChangeRecord::ACTION_DELETE) { + syncer::ReadNode node(trans); + CHECK_EQ(node.InitByIdLookup(it->id), syncer::BaseNode::INIT_OK); + scoped_ptr<base::DictionaryValue> details(node.GetDetailsAsValue()); + VLOG(1) << "Details: " << ValueToString(*details); + } + ++i; + } + } + + virtual void OnChangesComplete(syncable::ModelType model_type) OVERRIDE { + LOG(INFO) << "Changes complete for " + << syncable::ModelTypeToString(model_type); + } +}; + +class LoggingUnrecoverableErrorHandler + : public syncer::UnrecoverableErrorHandler { + public: + virtual ~LoggingUnrecoverableErrorHandler() {} + + virtual void OnUnrecoverableError(const tracked_objects::Location& from_here, + const std::string& message) OVERRIDE { + if (LOG_IS_ON(ERROR)) { + logging::LogMessage(from_here.file_name(), from_here.line_number(), + logging::LOG_ERROR).stream() + << message; + } + } +}; + +class LoggingJsEventHandler + : public syncer::JsEventHandler, + public base::SupportsWeakPtr<LoggingJsEventHandler> { + public: + virtual ~LoggingJsEventHandler() {} + + virtual void HandleJsEvent( + const std::string& name, + const syncer::JsEventDetails& details) OVERRIDE { + VLOG(1) << name << ": " << details.ToString(); + } +}; + +void LogUnrecoverableErrorContext() { + base::debug::StackTrace stack_trace; + stack_trace.PrintBacktrace(); +} + +notifier::NotifierOptions ParseNotifierOptions( + const CommandLine& command_line, + const scoped_refptr<net::URLRequestContextGetter>& + request_context_getter) { + notifier::NotifierOptions notifier_options; + notifier_options.request_context_getter = request_context_getter; + + if (command_line.HasSwitch(kXmppHostPortSwitch)) { + notifier_options.xmpp_host_port = + net::HostPortPair::FromString( + command_line.GetSwitchValueASCII(kXmppHostPortSwitch)); + LOG(INFO) << "Using " << notifier_options.xmpp_host_port.ToString() + << " for test sync notification server."; + } + + notifier_options.try_ssltcp_first = + command_line.HasSwitch(kXmppTrySslTcpFirstSwitch); + LOG_IF(INFO, notifier_options.try_ssltcp_first) + << "Trying SSL/TCP port before XMPP port for notifications."; + + notifier_options.allow_insecure_connection = + command_line.HasSwitch(kXmppAllowInsecureConnectionSwitch); + LOG_IF(INFO, notifier_options.allow_insecure_connection) + << "Allowing insecure XMPP connections."; + + if (command_line.HasSwitch(kNotificationMethodSwitch)) { + notifier_options.notification_method = + notifier::StringToNotificationMethod( + command_line.GetSwitchValueASCII(kNotificationMethodSwitch)); + } + + return notifier_options; +} + +} // namespace + +int main(int argc, char* argv[]) { +#if defined(OS_MACOSX) + base::mac::ScopedNSAutoreleasePool pool; +#endif + base::AtExitManager exit_manager; + CommandLine::Init(argc, argv); + logging::InitLogging( + NULL, + logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG, + logging::LOCK_LOG_FILE, + logging::DELETE_OLD_LOG_FILE, + logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS); + + MessageLoop sync_loop; + base::Thread io_thread("IO thread"); + base::Thread::Options options; + options.message_loop_type = MessageLoop::TYPE_IO; + io_thread.StartWithOptions(options); + + // Parse command line. + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + syncer::SyncCredentials credentials; + credentials.email = command_line.GetSwitchValueASCII(kEmailSwitch); + credentials.sync_token = command_line.GetSwitchValueASCII(kTokenSwitch); + // TODO(akalin): Write a wrapper script that gets a token for an + // email and password and passes that in to this utility. + if (credentials.email.empty() || credentials.sync_token.empty()) { + std::printf("Usage: %s --%s=foo@bar.com --%s=token\n" + "[--%s=host:port] [--%s] [--%s]\n" + "[--%s=(server|p2p)]\n\n" + "Run chrome and set a breakpoint on\n" + "syncer::SyncManager::SyncInternal::UpdateCredentials() " + "after logging into\n" + "sync to get the token to pass into this utility.\n", + argv[0], + kEmailSwitch, kTokenSwitch, kXmppHostPortSwitch, + kXmppTrySslTcpFirstSwitch, + kXmppAllowInsecureConnectionSwitch, + kNotificationMethodSwitch); + return -1; + } + + // Set up objects that monitor the network. + scoped_ptr<net::NetworkChangeNotifier> network_change_notifier( + net::NetworkChangeNotifier::Create()); + + // Set up sync notifier factory. + const scoped_refptr<MyTestURLRequestContextGetter> context_getter = + new MyTestURLRequestContextGetter(io_thread.message_loop_proxy()); + const notifier::NotifierOptions& notifier_options = + ParseNotifierOptions(command_line, context_getter); + const char kClientInfo[] = "sync_listen_notifications"; + NullInvalidationStateTracker null_invalidation_state_tracker; + syncer::SyncNotifierFactory sync_notifier_factory( + notifier_options, kClientInfo, + null_invalidation_state_tracker.AsWeakPtr()); + + // Set up database directory for the syncer. + ScopedTempDir database_dir; + CHECK(database_dir.CreateUniqueTempDir()); + + // Set up model type parameters. + const syncable::ModelTypeSet model_types = syncable::ModelTypeSet::All(); + syncer::ModelSafeRoutingInfo routing_info; + for (syncable::ModelTypeSet::Iterator it = model_types.First(); + it.Good(); it.Inc()) { + routing_info[it.Get()] = syncer::GROUP_PASSIVE; + } + scoped_refptr<syncer::PassiveModelWorker> passive_model_safe_worker = + new syncer::PassiveModelWorker(&sync_loop); + std::vector<syncer::ModelSafeWorker*> workers; + workers.push_back(passive_model_safe_worker.get()); + + // Set up sync manager. + syncer::SyncManager sync_manager("sync_client manager"); + LoggingJsEventHandler js_event_handler; + const char kSyncServerAndPath[] = "clients4.google.com/chrome-sync/dev"; + int kSyncServerPort = 443; + bool kUseSsl = true; + // Used only by RefreshNigori(), so it's okay to leave this as NULL. + const scoped_refptr<base::TaskRunner> blocking_task_runner = NULL; + const char kUserAgent[] = "sync_client"; + // TODO(akalin): Replace this with just the context getter once + // HttpPostProviderFactory is removed. + scoped_ptr<syncer::HttpPostProviderFactory> post_factory( + new syncer::HttpBridgeFactory(context_getter, kUserAgent)); + // Used only when committing bookmarks, so it's okay to leave this + // as NULL. + syncer::ExtensionsActivityMonitor* extensions_activity_monitor = NULL; + LoggingChangeDelegate change_delegate; + const char kRestoredKeyForBootstrapping[] = ""; + const syncer::SyncManager::TestingMode kTestingMode = + syncer::SyncManager::NON_TEST; + NullEncryptor null_encryptor; + LoggingUnrecoverableErrorHandler unrecoverable_error_handler; + sync_manager.Init(database_dir.path(), + syncer::WeakHandle<syncer::JsEventHandler>( + js_event_handler.AsWeakPtr()), + kSyncServerAndPath, + kSyncServerPort, + kUseSsl, + blocking_task_runner, + post_factory.release(), + routing_info, + workers, + extensions_activity_monitor, + &change_delegate, + credentials, + sync_notifier_factory.CreateSyncNotifier(), + kRestoredKeyForBootstrapping, + kTestingMode, + &null_encryptor, + &unrecoverable_error_handler, + &LogUnrecoverableErrorContext); + // TODO(akalin): We have pass in model parameters multiple times. + // Organize handling of model types. + sync_manager.UpdateEnabledTypes(model_types); + sync_manager.StartSyncingNormally(routing_info); + + sync_loop.Run(); + + io_thread.Stop(); + return 0; +} diff --git a/sync/tools/sync_listen_notifications.cc b/sync/tools/sync_listen_notifications.cc index 5378f41..29d6edc 100644 --- a/sync/tools/sync_listen_notifications.cc +++ b/sync/tools/sync_listen_notifications.cc @@ -38,6 +38,13 @@ namespace { +const char kEmailSwitch[] = "email"; +const char kTokenSwitch[] = "token"; +const char kHostPortSwitch[] = "host-port"; +const char kTrySslTcpFirstSwitch[] = "try-ssltcp-first"; +const char kAllowInsecureConnectionSwitch[] = "allow-insecure-connection"; +const char kNotificationMethodSwitch[] = "notification-method"; + // Class to print received notifications events. class NotificationPrinter : public syncer::SyncNotifierObserver { public: @@ -96,51 +103,12 @@ class NullInvalidationStateTracker } virtual void SetInvalidationState(const std::string& state) OVERRIDE { - LOG(INFO) << "Setting invalidation state to: " << state; + std::string base64_state; + CHECK(base::Base64Encode(state, &base64_state)); + LOG(INFO) << "Setting invalidation state to: " << base64_state; } }; -const char kEmailSwitch[] = "email"; -const char kTokenSwitch[] = "token"; -const char kHostPortSwitch[] = "host-port"; -const char kTrySslTcpFirstSwitch[] = "try-ssltcp-first"; -const char kAllowInsecureConnectionSwitch[] = "allow-insecure-connection"; -const char kNotificationMethodSwitch[] = "notification-method"; - -notifier::NotifierOptions ParseNotifierOptions( - const CommandLine& command_line, - const scoped_refptr<net::URLRequestContextGetter>& - request_context_getter) { - notifier::NotifierOptions notifier_options; - notifier_options.request_context_getter = request_context_getter; - - if (command_line.HasSwitch(kHostPortSwitch)) { - notifier_options.xmpp_host_port = - net::HostPortPair::FromString( - command_line.GetSwitchValueASCII(kHostPortSwitch)); - LOG(INFO) << "Using " << notifier_options.xmpp_host_port.ToString() - << " for test sync notification server."; - } - - notifier_options.try_ssltcp_first = - command_line.HasSwitch(kTrySslTcpFirstSwitch); - LOG_IF(INFO, notifier_options.try_ssltcp_first) - << "Trying SSL/TCP port before XMPP port for notifications."; - - notifier_options.allow_insecure_connection = - command_line.HasSwitch(kAllowInsecureConnectionSwitch); - LOG_IF(INFO, notifier_options.allow_insecure_connection) - << "Allowing insecure XMPP connections."; - - if (command_line.HasSwitch(kNotificationMethodSwitch)) { - notifier_options.notification_method = - notifier::StringToNotificationMethod( - command_line.GetSwitchValueASCII(kNotificationMethodSwitch)); - } - - return notifier_options; -} - // Needed to use a real host resolver. class MyTestURLRequestContext : public TestURLRequestContext { public: @@ -176,6 +144,40 @@ class MyTestURLRequestContextGetter : public TestURLRequestContextGetter { scoped_ptr<MyTestURLRequestContext> context_; }; +notifier::NotifierOptions ParseNotifierOptions( + const CommandLine& command_line, + const scoped_refptr<net::URLRequestContextGetter>& + request_context_getter) { + notifier::NotifierOptions notifier_options; + notifier_options.request_context_getter = request_context_getter; + + if (command_line.HasSwitch(kHostPortSwitch)) { + notifier_options.xmpp_host_port = + net::HostPortPair::FromString( + command_line.GetSwitchValueASCII(kHostPortSwitch)); + LOG(INFO) << "Using " << notifier_options.xmpp_host_port.ToString() + << " for test sync notification server."; + } + + notifier_options.try_ssltcp_first = + command_line.HasSwitch(kTrySslTcpFirstSwitch); + LOG_IF(INFO, notifier_options.try_ssltcp_first) + << "Trying SSL/TCP port before XMPP port for notifications."; + + notifier_options.allow_insecure_connection = + command_line.HasSwitch(kAllowInsecureConnectionSwitch); + LOG_IF(INFO, notifier_options.allow_insecure_connection) + << "Allowing insecure XMPP connections."; + + if (command_line.HasSwitch(kNotificationMethodSwitch)) { + notifier_options.notification_method = + notifier::StringToNotificationMethod( + command_line.GetSwitchValueASCII(kNotificationMethodSwitch)); + } + + return notifier_options; +} + } // namespace int main(int argc, char* argv[]) { |