Index: chrome/browser/invalidation_service.cc |
diff --git a/chrome/browser/invalidation_service.cc b/chrome/browser/invalidation_service.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ab8e1ee37c531f1a4dea01f185b7bd11cf34e94e |
--- /dev/null |
+++ b/chrome/browser/invalidation_service.cc |
@@ -0,0 +1,286 @@ |
+// Copyright (c) 2013 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/invalidation_service.h" |
+ |
+#include "base/base64.h" |
+#include "base/command_line.h" |
+#include "base/rand_util.h" |
+#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/signin/signin_manager.h" |
+#include "chrome/browser/signin/token_service.h" |
+#include "chrome/common/chrome_notification_types.h" |
+#include "chrome/common/chrome_switches.h" |
+#include "content/public/browser/notification_service.h" |
+#include "google_apis/gaia/gaia_constants.h" |
+#include "google_apis/gaia/google_service_auth_error.h" |
+#include "sync/notifier/invalidator.h" |
+#include "sync/notifier/invalidator_state.h" |
+#include "sync/notifier/non_blocking_invalidator.h" |
+ |
+namespace { |
+// Parses the given command line for notifier options. |
+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(switches::kSyncNotificationHostPort)) { |
+ notifier_options.xmpp_host_port = |
+ net::HostPortPair::FromString( |
+ command_line.GetSwitchValueASCII( |
+ switches::kSyncNotificationHostPort)); |
+ DVLOG(1) << "Using " << notifier_options.xmpp_host_port.ToString() |
+ << " for test sync notification server."; |
+ } |
+ |
+ notifier_options.try_ssltcp_first = |
+ command_line.HasSwitch(switches::kSyncTrySsltcpFirstForXmpp); |
+ DVLOG_IF(1, notifier_options.try_ssltcp_first) |
+ << "Trying SSL/TCP port before XMPP port for notifications."; |
+ |
+ notifier_options.invalidate_xmpp_login = |
+ command_line.HasSwitch(switches::kSyncInvalidateXmppLogin); |
+ DVLOG_IF(1, notifier_options.invalidate_xmpp_login) |
+ << "Invalidating sync XMPP login."; |
+ |
+ notifier_options.allow_insecure_connection = |
+ command_line.HasSwitch(switches::kSyncAllowInsecureXmppConnection); |
+ DVLOG_IF(1, notifier_options.allow_insecure_connection) |
+ << "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 notifier_options; |
+} |
+ |
+std::string GenerateInvalidatorClientId() { |
+ // Generate a GUID with 128 bits worth of base64-encoded randomness. |
+ // This format is similar to that of sync's cache_guid. |
+ const int kGuidBytes = 128 / 8; |
+ std::string guid; |
+ base::Base64Encode(base::RandBytesAsString(kGuidBytes), &guid); |
+ return guid; |
+} |
+ |
+} // namespace |
+ |
+InvalidationService::InvalidationService(SigninManager* signin, |
+ TokenService* token_service) |
+ : signin_manager_(signin), |
+ token_service_(token_service), |
+ invalidator_registrar_(new syncer::InvalidatorRegistrar()) { } |
+ |
+InvalidationService::~InvalidationService() { |
+ DCHECK(CalledOnValidThread()); |
+} |
+ |
+void InvalidationService::Init(Profile* profile) { |
+ DCHECK(CalledOnValidThread()); |
+ |
+ profile_ = profile; |
+ |
+ invalidator_storage_.reset( |
+ new browser_sync::InvalidatorStorage(profile_->GetPrefs())); |
+ if (invalidator_storage_->GetInvalidatorClientId().empty()) { |
+ // This also clears any existing state. We can't reuse old invalidator |
+ // state with the new ID anyway. |
+ invalidator_storage_->SetInvalidatorClientId( |
+ GenerateInvalidatorClientId()); |
+ } |
+ |
+ if (IsReadyToStart()) { |
+ Start(); |
+ } |
+ |
+ notification_registrar_.Add(this, |
+ chrome::NOTIFICATION_TOKEN_AVAILABLE, |
+ content::Source<TokenService>(token_service_)); |
+ notification_registrar_.Add(this, |
+ chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, |
+ content::NotificationService::AllSources()); |
+} |
+ |
+void InvalidationService::RegisterInvalidationHandler( |
+ syncer::InvalidationHandler* handler) { |
+ DCHECK(CalledOnValidThread()); |
+ DVLOG(2) << "Registering"; |
+ invalidator_registrar_->RegisterHandler(handler); |
+} |
+ |
+void InvalidationService::UpdateRegisteredInvalidationIds( |
+ syncer::InvalidationHandler* handler, |
+ const syncer::ObjectIdSet& ids) { |
+ DCHECK(CalledOnValidThread()); |
+ DVLOG(2) << "Registering ids: " << ids.size(); |
+ invalidator_registrar_->UpdateRegisteredIds(handler, ids); |
+ if (invalidator_) { |
+ invalidator_->UpdateRegisteredIds( |
+ this, |
+ invalidator_registrar_->GetAllRegisteredIds()); |
+ } |
+} |
+ |
+void InvalidationService::UnregisterInvalidationHandler( |
+ syncer::InvalidationHandler* handler) { |
+ DCHECK(CalledOnValidThread()); |
+ DVLOG(2) << "Unregistering"; |
+ invalidator_registrar_->UnregisterHandler(handler); |
+ // FIXME: Should unregistering the handler also unregister the IDs? |
+ // I don't see why not... |
+ if (invalidator_) { |
+ invalidator_->UpdateRegisteredIds( |
+ this, |
+ invalidator_registrar_->GetAllRegisteredIds()); |
+ } |
+} |
+ |
+void InvalidationService::AcknowledgeInvalidation( |
+ const invalidation::ObjectId& id, |
+ const syncer::AckHandle& ack_handle) { |
+ DCHECK(CalledOnValidThread()); |
+ if (invalidator_) { |
+ invalidator_->Acknowledge(id, ack_handle); |
+ } |
+} |
+ |
+syncer::InvalidatorState InvalidationService::GetInvalidatorState() const { |
+ DCHECK(CalledOnValidThread()); |
+ if (invalidator_) { |
+ DVLOG(2) << "GetInvalidatorState returning " << GetInvalidatorState(); |
+ return invalidator_->GetInvalidatorState(); |
+ } else { |
+ DVLOG(2) << "Invalidator currently stopped"; |
+ return syncer::TRANSIENT_INVALIDATION_ERROR; |
+ } |
+} |
+ |
+std::string InvalidationService::GetInvalidatorClientId() const { |
+ DCHECK(CalledOnValidThread()); |
+ if (!invalidator_storage_) { // NULL in some unit tests. |
+ return "TESTING_ONLY_ID"; |
+ } |
+ |
+ return invalidator_storage_->GetInvalidatorClientId(); |
+} |
+ |
+void InvalidationService::Observe( |
+ int type, |
+ const content::NotificationSource& source, |
+ const content::NotificationDetails& details) { |
+ DCHECK(CalledOnValidThread()); |
+ |
+ switch (type) { |
+ case chrome::NOTIFICATION_TOKEN_AVAILABLE: { |
tim (not reviewing)
2013/04/15 16:48:24
I forget, do we always send TOKEN_AVAILABLE from T
rlarocque
2013/04/22 21:47:15
I think that's always guaranteed. I was a bit sus
tim (not reviewing)
2013/04/22 22:13:56
More likely is at one time TOKEN_AVAILABLE was act
|
+ const TokenService::TokenAvailableDetails& token_details = |
+ *(content::Details<const TokenService::TokenAvailableDetails>( |
+ details).ptr()); |
+ if (token_details.service() == GaiaConstants::kSyncService) { |
+ DCHECK(IsReadyToStart()); |
+ if (!IsStarted()) { |
+ Start(); |
tim (not reviewing)
2013/04/15 16:48:24
You should check with atwilson@ and rogerta@ about
rlarocque
2013/04/22 21:47:15
I'm not sure that we want to go in that direction.
tim (not reviewing)
2013/04/22 22:13:56
As I said, just make sure you check with Drew (at
|
+ } else { |
+ UpdateToken(); |
+ } |
+ } |
+ break; |
+ } |
+ case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT: |
tim (not reviewing)
2013/04/15 16:48:24
This may get interesting when we have service acco
|
+ Stop(); |
+ break; |
+ } |
+} |
+ |
+void InvalidationService::OnInvalidatorStateChange( |
+ syncer::InvalidatorState state) { |
+ invalidator_registrar_->UpdateInvalidatorState(state); |
+} |
+ |
+void InvalidationService::OnIncomingInvalidation( |
+ const syncer::ObjectIdInvalidationMap& invalidation_map) { |
+ invalidator_registrar_->DispatchInvalidationsToHandlers(invalidation_map); |
+} |
+ |
+void InvalidationService::Shutdown() { |
+ DCHECK(CalledOnValidThread()); |
+ Stop(); |
+ invalidator_registrar_.reset(); |
+} |
+ |
+bool InvalidationService::IsReadyToStart() { |
+ if (signin_manager_->GetAuthenticatedUsername().empty()) { |
+ DVLOG(2) << "Not starting InvalidationService: user is not signed in."; |
+ return false; |
+ } |
+ |
+ if (!token_service_) { |
+ DVLOG(2) << "Not starting InvalidationService: TokenService unavailable."; |
+ return false; |
+ } |
+ |
+ if (!token_service_->HasTokenForService(GaiaConstants::kSyncService)) { |
+ DVLOG(2) << "Not starting InvalidationService: Sync token unavailable."; |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+bool InvalidationService::IsStarted() { |
+ return !!invalidator_; |
+} |
+ |
+void InvalidationService::Start() { |
+ DCHECK(CalledOnValidThread()); |
+ |
+ DCHECK(!invalidator_); |
+ |
+ invalidator_.reset(new syncer::NonBlockingInvalidator( |
+ ParseNotifierOptions(*CommandLine::ForCurrentProcess(), |
+ profile_->GetRequestContext()), |
+ invalidator_storage_->GetInvalidatorClientId(), |
+ invalidator_storage_->GetAllInvalidationStates(), |
+ invalidator_storage_->GetBootstrapData(), |
+ syncer::WeakHandle<syncer::InvalidationStateTracker>( |
+ invalidator_storage_->AsWeakPtr()), |
+ content::GetUserAgent(GURL()))); |
+ |
+ UpdateToken(); |
+ |
+ invalidator_->RegisterHandler(this); |
+ invalidator_->UpdateRegisteredIds( |
+ this, |
+ invalidator_registrar_->GetAllRegisteredIds()); |
+} |
+ |
+void InvalidationService::UpdateToken() { |
+ std::string email = signin_manager_->GetAuthenticatedUsername(); |
+ DCHECK(!email.empty()) << "Expected user to be signed in."; |
+ |
+ // FIXME: Is it right to use the sync token here? |
tim (not reviewing)
2013/04/15 16:48:24
Yes, this seems correct and equivalent to before t
rlarocque
2013/04/22 21:47:15
OK. Just to be clear, my intent with this patch i
tim (not reviewing)
2013/04/22 22:13:56
So, yes. I think we're in agreement? In the futur
|
+ DCHECK(token_service_->HasTokenForService(GaiaConstants::kSyncService)); |
+ std::string sync_token = token_service_->GetTokenForService( |
+ GaiaConstants::kSyncService); |
+ |
+ DVLOG(2) << "UpdateCredentials: " << email; |
+ invalidator_->UpdateCredentials(email, sync_token); |
+} |
+ |
+void InvalidationService::Stop() { |
+ if (invalidator_) { |
+ invalidator_->UnregisterHandler(this); |
+ invalidator_.reset(); |
+ } |
+ if (invalidator_storage_) { |
+ invalidator_storage_->Clear(); |
+ invalidator_storage_.reset(); |
+ } |
+} |