Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(109)

Unified Diff: chrome/browser/extensions/syncable_extension_settings_storage.cc

Issue 7775008: Enable sync for the settings from the Extension Settings API. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Reordering Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/syncable_extension_settings_storage.cc
diff --git a/chrome/browser/extensions/syncable_extension_settings_storage.cc b/chrome/browser/extensions/syncable_extension_settings_storage.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0b561ee894cb7c6b84b6c7d01e8d987369f14828
--- /dev/null
+++ b/chrome/browser/extensions/syncable_extension_settings_storage.cc
@@ -0,0 +1,425 @@
+// 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/extensions/syncable_extension_settings_storage.h"
+
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/task.h"
+#include "chrome/browser/extensions/extension_settings_sync_helper.h"
+#include "chrome/browser/sync/api/sync_data.h"
+#include "chrome/browser/sync/protocol/extension_setting_specifics.pb.h"
+
+SyncableExtensionSettingsStorage::SyncDeps::SyncDeps(
+ SyncChangeProcessor* processor) : processor_(processor) {
+ DCHECK(processor != NULL);
+}
+
+SyncableExtensionSettingsStorage::SyncDeps::~SyncDeps() {
+}
+
+SyncableExtensionSettingsStorage::SyncableExtensionSettingsStorage(
+ std::string extension_id, ExtensionSettingsStorage* delegate)
+ : extension_id_(extension_id), delegate_(delegate), sync_deps_(NULL) {}
+
+SyncableExtensionSettingsStorage::~SyncableExtensionSettingsStorage() {}
+
+void SyncableExtensionSettingsStorage::Get(
+ const std::string& key, ExtensionSettingsStorage::Callback* callback) {
+ delegate_->Get(key, callback);
+}
+
+void SyncableExtensionSettingsStorage::Get(
+ const ListValue& keys, ExtensionSettingsStorage::Callback* callback) {
+ delegate_->Get(keys, callback);
+}
+
+void SyncableExtensionSettingsStorage::Get(
+ ExtensionSettingsStorage::Callback* callback) {
+ delegate_->Get(callback);
+}
+
+namespace {
+
+class SendAddsOrUpdatesToSyncCallback
+ : public ExtensionSettingsStorage::Callback {
+ public:
+ SendAddsOrUpdatesToSyncCallback(
+ Callback* delegate,
+ const std::string& extension_id,
+ base::WeakPtr<SyncableExtensionSettingsStorage::SyncDeps> sync_deps)
+ : delegate_(delegate),
+ extension_id_(extension_id),
+ sync_deps_(sync_deps) {}
+
+ void OnSuccess(DictionaryValue* settings) OVERRIDE {
+ if (!sync_deps_) {
+ delegate_->OnSuccess(settings);
+ return;
+ }
+
+ SyncChangeList sync_changes;
+ for (DictionaryValue::key_iterator it = settings->begin_keys();
+ it != settings->end_keys(); ++it) {
+ Value* value;
+ settings->GetWithoutPathExpansion(*it, &value);
+ if (sync_deps_->keys()->count(*it)) {
+ // Key is synced, send ACTION_UPDATE to sync.
+ sync_changes.push_back(ExtensionSettingsSyncHelper::CreateUpdate(
+ extension_id_, *it, *value));
+ } else {
+ // Key is not synced, send ACTION_ADD to sync.
+ sync_changes.push_back(ExtensionSettingsSyncHelper::CreateAdd(
+ extension_id_, *it, *value));
+ }
+ }
+
+ if (sync_changes.empty()) {
+ delegate_->OnSuccess(settings);
+ return;
+ }
+
+ SyncError error =
+ sync_deps_->processor()->ProcessSyncChanges(FROM_HERE, sync_changes);
+ if (error.IsSet()) {
+ LOG(WARNING) << "Failed to send changes to sync: " << error.message();
+ } else {
+ // Sync was successful, record those keys as synced.
+ sync_deps_->keys()->insert(settings->begin_keys(), settings->end_keys());
+ }
+
+ delegate_->OnSuccess(settings);
+ }
+
+ void OnFailure(const std::string& error) {
+ LOG(WARNING) << "Settings operation failed, not sending to sync: " << error;
+ delegate_->OnFailure(error);
+ }
+
+ private:
+ scoped_ptr<Callback> delegate_;
+ std::string extension_id_;
+ base::WeakPtr<SyncableExtensionSettingsStorage::SyncDeps> sync_deps_;
+};
+
+} // namespace
+
+void SyncableExtensionSettingsStorage::Set(
+ const std::string& key,
+ const Value& value,
+ ExtensionSettingsStorage::Callback* callback) {
+ if (sync_deps_ != NULL) {
+ callback = new SendAddsOrUpdatesToSyncCallback(
+ callback, extension_id_, sync_deps_->AsWeakPtr());
+ }
+ delegate_->Set(key, value, callback);
+}
+
+void SyncableExtensionSettingsStorage::Set(
+ const DictionaryValue& values,
+ ExtensionSettingsStorage::Callback* callback) {
+ if (sync_deps_ != NULL) {
+ callback = new SendAddsOrUpdatesToSyncCallback(
+ callback, extension_id_, sync_deps_->AsWeakPtr());
+ }
+ delegate_->Set(values, callback);
+}
+
+namespace {
+
+class SendDeletesToSyncCallback : public ExtensionSettingsStorage::Callback {
+ public:
+ SendDeletesToSyncCallback(
+ // Ownership is taken.
+ Callback* delegate,
+ const std::string& extension_id,
+ // Ownership is taken.
+ std::set<std::string>* keys_to_remove,
+ base::WeakPtr<SyncableExtensionSettingsStorage::SyncDeps> sync_deps)
+ : delegate_(delegate),
+ extension_id_(extension_id),
+ keys_to_remove_(keys_to_remove),
+ sync_deps_(sync_deps) {
+ DCHECK(!keys_to_remove->empty());
+ }
+
+ void OnSuccess(DictionaryValue* settings) OVERRIDE {
+ DCHECK(settings == NULL);
+ if (!sync_deps_) {
+ delegate_->OnSuccess(settings);
+ return;
+ }
+
+ SyncChangeList sync_changes;
+ for (std::set<std::string>::iterator it = keys_to_remove_->begin();
+ it != keys_to_remove_->end(); ++it) {
+ // Only remove from sync if it's actually synced.
+ if (sync_deps_->keys()->count(*it)) {
+ sync_changes.push_back(
+ ExtensionSettingsSyncHelper::CreateDelete(extension_id_, *it));
+ }
+ }
+
+ if (sync_changes.empty()) {
+ delegate_->OnSuccess(settings);
+ return;
+ }
+
+ SyncError error =
+ sync_deps_->processor()->ProcessSyncChanges(FROM_HERE, sync_changes);
+ if (error.IsSet()) {
+ LOG(WARNING) << "Failed to send changes to sync: " << error.message();
+ } else {
+ // Sync was successful, record those keys as deleted from sync.
+ for (std::set<std::string>::iterator it = keys_to_remove_->begin();
+ it != keys_to_remove_->end(); ++it) {
+ sync_deps_->keys()->erase(*it);
+ }
+ }
+
+ delegate_->OnSuccess(settings);
+ }
+
+ void OnFailure(const std::string& error) {
+ LOG(WARNING) << "Settings operation failed, not sending to sync: " << error;
+ delegate_->OnFailure(error);
+ }
+
+ private:
+ scoped_ptr<Callback> delegate_;
+ std::string extension_id_;
+ scoped_ptr<std::set<std::string> > keys_to_remove_;
+ base::WeakPtr<SyncableExtensionSettingsStorage::SyncDeps> sync_deps_;
+};
+
+} // namespace
+
+void SyncableExtensionSettingsStorage::Remove(
+ const std::string& key, ExtensionSettingsStorage::Callback* callback) {
+ if (sync_deps_ != NULL) {
+ std::set<std::string>* keys_to_remove = new std::set<std::string>();
+ keys_to_remove->insert(key);
+ callback = new SendDeletesToSyncCallback(
+ callback,
+ extension_id_,
+ keys_to_remove,
+ sync_deps_->AsWeakPtr());
+ }
+ delegate_->Remove(key, callback);
+}
+
+void SyncableExtensionSettingsStorage::Remove(
+ const ListValue& keys, ExtensionSettingsStorage::Callback* callback) {
+ if (sync_deps_ != NULL) {
+ std::set<std::string>* keys_to_remove = new std::set<std::string>();
+ std::string key_to_remove;
+ for (ListValue::const_iterator it = keys.begin(); it != keys.end(); ++it) {
+ if ((*it)->GetAsString(&key_to_remove)) {
+ keys_to_remove->insert(key_to_remove);
+ }
+ }
+ callback = new SendDeletesToSyncCallback(
+ callback,
+ extension_id_,
+ keys_to_remove,
+ sync_deps_->AsWeakPtr());
+ }
+ delegate_->Remove(keys, callback);
+}
+
+void SyncableExtensionSettingsStorage::Clear(
+ ExtensionSettingsStorage::Callback* callback) {
+ if (sync_deps_ != NULL) {
+ callback = new SendDeletesToSyncCallback(
+ callback,
+ extension_id_,
+ // Remove all the synced keys.
+ new std::set<std::string>(*sync_deps_->keys()),
+ sync_deps_->AsWeakPtr());
+ }
+ delegate_->Clear(callback);
+}
+
+void SyncableExtensionSettingsStorage::DeleteSoon() {
+ delegate_->DeleteSoon();
+ delete this;
+}
+
+// Sync-related methods.
+
+namespace {
+
+class SendAllLocalSettingsToSyncCallback
+ : public ExtensionSettingsStorage::Callback {
+ public:
+ SendAllLocalSettingsToSyncCallback(
+ const std::string& extension_id,
+ base::WeakPtr<SyncableExtensionSettingsStorage::SyncDeps> sync_deps)
+ : extension_id_(extension_id), sync_deps_(sync_deps) {}
+
+ virtual void OnSuccess(DictionaryValue* settings) OVERRIDE {
+ scoped_ptr<DictionaryValue> settings_ownership(settings);
+ if (!sync_deps_) {
+ return;
+ }
+
+ SyncChangeList sync_changes;
+ for (DictionaryValue::key_iterator it = settings->begin_keys();
+ it != settings->end_keys(); ++it) {
+ Value* value;
+ settings->GetWithoutPathExpansion(*it, &value);
+ sync_changes.push_back(ExtensionSettingsSyncHelper::CreateAdd(
+ extension_id_, *it, *value));
+ }
+
+ if (sync_changes.empty()) {
+ return;
+ }
+
+ SyncError error =
+ sync_deps_->processor()->ProcessSyncChanges(FROM_HERE, sync_changes);
+ if (error.IsSet()) {
+ LOG(WARNING) << "Failed to send changes to sync: " << error.message();
+ } else {
+ // Sync was successful, record those keys as synced.
+ sync_deps_->keys()->insert(settings->begin_keys(), settings->end_keys());
+ }
+ }
+
+ virtual void OnFailure(const std::string& error) OVERRIDE {
+ LOG(WARNING) << "Settings operation failed, not sending to sync: " << error;
+ }
+
+ private:
+ std::string extension_id_;
+ base::WeakPtr<SyncableExtensionSettingsStorage::SyncDeps> sync_deps_;
+};
+
+class OverwriteLocalSettingsFromSyncCallback
+ : public ExtensionSettingsStorage::Callback {
+ public:
+ OverwriteLocalSettingsFromSyncCallback(
+ base::WeakPtr<SyncableExtensionSettingsStorage> storage,
+ // Ownership taken.
+ DictionaryValue* sync_state)
+ : storage_(storage), sync_state_(sync_state) {}
+
+ virtual void OnSuccess(DictionaryValue* local_state) {
+ scoped_ptr<DictionaryValue> local_state_ownership(local_state);
+ if (!storage_) {
+ return;
+ }
+
+ // Pretend they're sync changes to process, because they are.
+ ExtensionSettingSyncDataList sync_changes;
+ for (DictionaryValue::key_iterator it = local_state->begin_keys();
+ it != local_state->end_keys(); ++it) {
+ Value* sync_value;
+ if (sync_state_->RemoveWithoutPathExpansion(*it, &sync_value)) {
+ Value* local_value;
+ local_state->GetWithoutPathExpansion(*it, &local_value);
+ if (!local_value->Equals(sync_value)) {
+ // Sync value is different, update locally with new value.
+ sync_changes.push_back(ExtensionSettingSyncData(
+ SyncChange::ACTION_UPDATE, "", *it, sync_value));
+ }
+ } else {
+ // No sync value, delete locally.
+ sync_changes.push_back(ExtensionSettingSyncData(
+ SyncChange::ACTION_DELETE, "", *it, new DictionaryValue()));
+ }
+ }
+
+ for (DictionaryValue::key_iterator it = sync_state_->begin_keys();
+ it != sync_state_->end_keys(); ++it) {
+ Value* sync_value;
+ // Missing local value for synced setting, add locally.
+ // If it's safe to RemoveWithoutPathExpansion the DeepCopy would be
+ // unnecessary.
+ sync_state_->GetWithoutPathExpansion(*it, &sync_value);
+ sync_changes.push_back(ExtensionSettingSyncData(
+ SyncChange::ACTION_ADD, "", *it, sync_value->DeepCopy()));
+ }
+
+ if (!sync_changes.empty()) {
+ storage_->ProcessSyncChanges(sync_changes);
+ }
+ }
+
+ virtual void OnFailure(const std::string& error) {
+ LOG(WARNING) <<
+ "Settings operation failed, local state not in sync: " << error;
+ }
+
+ private:
+ base::WeakPtr<SyncableExtensionSettingsStorage> storage_;
+ scoped_ptr<DictionaryValue> sync_state_;
+};
+
+} // namespace
+
+void SyncableExtensionSettingsStorage::StartSyncing(
+ const DictionaryValue& sync_state, SyncChangeProcessor* sync_processor) {
+ DCHECK(sync_deps_ == NULL);
+ sync_deps_ = new SyncDeps(sync_processor);
+ sync_deps_->keys()->insert(sync_state.begin_keys(), sync_state.end_keys());
+
+ // Send local state to sync if there is no sync data yet, otherwise overwrite
+ // local state with sync state (via a callback).
+ if (sync_state.empty()) {
+ Get(new SendAllLocalSettingsToSyncCallback(
+ extension_id_, sync_deps_->AsWeakPtr()));
+ } else {
+ Get(new OverwriteLocalSettingsFromSyncCallback(
+ this->AsWeakPtr(), sync_state.DeepCopy()));
+ }
+}
+
+void SyncableExtensionSettingsStorage::StopSyncing() {
+ DCHECK(sync_deps_ != NULL);
+ delete sync_deps_;
+ sync_deps_ = NULL;
+}
+
+namespace {
+
+// Callback from storage methods which does nothing.
+// TODO(kalman): Replace with actual implementations when notifications of sync
+// changes need to be sent to extensions.
+class NoopCallback : public ExtensionSettingsStorage::Callback {
+ public:
+ virtual ~NoopCallback() {}
+ virtual void OnSuccess(DictionaryValue* s) OVERRIDE { delete s; }
+ virtual void OnFailure(const std::string& message) OVERRIDE {}
+};
+
+} // namespace
+
+void SyncableExtensionSettingsStorage::ProcessSyncChanges(
+ const ExtensionSettingSyncDataList& sync_changes) {
+ DCHECK(sync_deps_ != NULL);
+ DCHECK(!sync_changes.empty()) << "No sync changes for " << extension_id_;
+ for (ExtensionSettingSyncDataList::const_iterator it = sync_changes.begin();
+ it != sync_changes.end(); ++it) {
+ switch (it->change_type()) {
+ case SyncChange::ACTION_ADD:
+ case SyncChange::ACTION_UPDATE:
+ sync_deps_->keys()->insert(it->key());
+ delegate_->Set(
+ it->key(),
+ *it->value(),
+ new NoopCallback());
+ break;
+ case SyncChange::ACTION_DELETE:
+ sync_deps_->keys()->erase(it->key());
+ delegate_->Remove(
+ it->key(),
+ new NoopCallback());
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698