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

Side by Side 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: Review #2 against correct branch Created 9 years, 3 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/extensions/syncable_extension_settings_storage.h"
6
7 #include "base/memory/scoped_ptr.h"
8 #include "chrome/browser/extensions/extension_settings_sync_util.h"
9 #include "chrome/browser/sync/api/sync_data.h"
10 #include "chrome/browser/sync/protocol/extension_setting_specifics.pb.h"
11 #include "content/browser/browser_thread.h"
12
13 // Inserts all the keys from a dictionary into a set of strings.
14 static void InsertAll(std::set<std::string>* dst, const DictionaryValue& src) {
15 for (DictionaryValue::key_iterator it = src.begin_keys();
16 it != src.end_keys(); ++it) {
17 dst->insert(*it);
18 }
19 }
20
21 SyncableExtensionSettingsStorage::SyncableExtensionSettingsStorage(
22 std::string extension_id, ExtensionSettingsStorage* delegate)
23 : extension_id_(extension_id), delegate_(delegate), sync_processor_(NULL) {
24 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
25 }
26
27 SyncableExtensionSettingsStorage::~SyncableExtensionSettingsStorage() {}
28
29 ExtensionSettingsStorage::Result SyncableExtensionSettingsStorage::Get(
30 const std::string& key) {
31 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
32 return delegate_->Get(key);
33 }
34
35 ExtensionSettingsStorage::Result SyncableExtensionSettingsStorage::Get(
36 const std::vector<std::string>& keys) {
37 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
38 return delegate_->Get(keys);
39 }
40
41 ExtensionSettingsStorage::Result SyncableExtensionSettingsStorage::Get() {
42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
43 return delegate_->Get();
44 }
45
46 ExtensionSettingsStorage::Result SyncableExtensionSettingsStorage::Set(
47 const std::string& key, const Value& value) {
48 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
49 Result result = delegate_->Set(key, value);
50 if (result.HasError()) {
51 return result;
52 }
53 if (sync_processor_) {
54 SendAddsOrUpdatesToSync(*result.GetSettings());
55 }
56 return result;
57 }
58
59 ExtensionSettingsStorage::Result SyncableExtensionSettingsStorage::Set(
60 const DictionaryValue& values) {
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
62 Result result = delegate_->Set(values);
63 if (result.HasError()) {
64 return result;
65 }
66 if (sync_processor_) {
67 SendAddsOrUpdatesToSync(*result.GetSettings());
68 }
69 return result;
70 }
71
72 ExtensionSettingsStorage::Result SyncableExtensionSettingsStorage::Remove(
73 const std::string& key) {
74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
75 Result result = delegate_->Remove(key);
76 if (result.HasError()) {
77 return result;
78 }
79 if (sync_processor_) {
80 std::vector<std::string> keys;
81 keys.push_back(key);
82 SendDeletesToSync(keys);
83 }
84 return result;
85 }
86
87 ExtensionSettingsStorage::Result SyncableExtensionSettingsStorage::Remove(
88 const std::vector<std::string>& keys) {
89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
90 Result result = delegate_->Remove(keys);
91 if (result.HasError()) {
92 return result;
93 }
94 if (sync_processor_) {
95 SendDeletesToSync(keys);
96 }
97 return result;
98 }
99
100 ExtensionSettingsStorage::Result SyncableExtensionSettingsStorage::Clear() {
101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
102 Result result = delegate_->Clear();
103 if (result.HasError()) {
104 return result;
105 }
106 if (sync_processor_) {
107 std::vector<std::string> keys;
108 keys.insert(keys.end(), synced_keys_.begin(), synced_keys_.end());
109 SendDeletesToSync(keys);
110 }
111 return result;
112 }
113
114 // Sync-related methods.
115
116 void SyncableExtensionSettingsStorage::StartSyncing(
117 const DictionaryValue& sync_state, SyncChangeProcessor* sync_processor) {
118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
119 DCHECK(!sync_processor_);
120 DCHECK(synced_keys_.empty());
121 sync_processor_ = sync_processor;
122 InsertAll(&synced_keys_, sync_state);
123
124 Result maybe_settings = delegate_->Get();
125 if (maybe_settings.HasError()) {
126 LOG(WARNING) << "Failed to get local settings to send to sync: " <<
127 maybe_settings.GetError();
128 return;
129 }
130 DictionaryValue* settings = maybe_settings.GetSettings();
131
132 if (sync_state.empty()) {
133 SendLocalSettingsToSync(*settings);
134 } else {
135 OverwriteLocalSettingsWithSync(sync_state, *settings);
136 }
137 }
138
139 void SyncableExtensionSettingsStorage::SendLocalSettingsToSync(
140 const DictionaryValue& settings) {
141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
142 SyncChangeList changes;
143 for (DictionaryValue::key_iterator it = settings.begin_keys();
144 it != settings.end_keys(); ++it) {
145 Value* value;
146 settings.GetWithoutPathExpansion(*it, &value);
147 changes.push_back(
148 extension_settings_sync_util::CreateAdd(extension_id_, *it, *value));
149 }
150
151 if (changes.empty()) {
152 return;
153 }
154
155 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
156 if (error.IsSet()) {
157 LOG(WARNING) << "Failed to send changes to sync: " << error.message();
158 return;
159 }
160
161 InsertAll(&synced_keys_, settings);
162 }
163
164 void SyncableExtensionSettingsStorage::OverwriteLocalSettingsWithSync(
165 const DictionaryValue& sync_state, const DictionaryValue& settings) {
166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
167 // Treat this as a list of changes to sync and use ProcessSyncChanges.
168 // This gives notifications etc for free.
169 scoped_ptr<DictionaryValue> new_sync_state(sync_state.DeepCopy());
170
171 ExtensionSettingSyncDataList changes;
172 for (DictionaryValue::key_iterator it = settings.begin_keys();
173 it != settings.end_keys(); ++it) {
174 Value* sync_value = NULL;
175 if (new_sync_state->RemoveWithoutPathExpansion(*it, &sync_value)) {
176 Value* local_value = NULL;
177 settings.GetWithoutPathExpansion(*it, &local_value);
178 if (!local_value->Equals(sync_value)) {
179 // Sync value is different, update local setting with new value.
180 changes.push_back(
181 ExtensionSettingSyncData(
182 SyncChange::ACTION_UPDATE, extension_id_, *it, sync_value));
183 }
184 } else {
185 // Not synced, delete local setting.
186 changes.push_back(
187 ExtensionSettingSyncData(
188 SyncChange::ACTION_DELETE,
189 extension_id_,
190 *it,
191 new DictionaryValue()));
192 }
193 }
194
195 // Add all new settings to local settings.
196 while (!new_sync_state->empty()) {
197 std::string key = *new_sync_state->begin_keys();
198 Value* value;
199 new_sync_state->RemoveWithoutPathExpansion(key, &value);
200 changes.push_back(
201 ExtensionSettingSyncData(
202 SyncChange::ACTION_ADD, extension_id_, key, value));
203 }
204
205 if (!changes.empty()) {
206 ProcessSyncChanges(changes);
207 }
208 }
209
210 void SyncableExtensionSettingsStorage::StopSyncing() {
211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
212 DCHECK(sync_processor_);
213 sync_processor_ = NULL;
214 synced_keys_.clear();
215 }
216
217 void SyncableExtensionSettingsStorage::ProcessSyncChanges(
218 const ExtensionSettingSyncDataList& sync_changes) {
219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
220 DCHECK(sync_processor_);
221 DCHECK(!sync_changes.empty()) << "No sync changes for " << extension_id_;
222
223 for (ExtensionSettingSyncDataList::const_iterator it = sync_changes.begin();
224 it != sync_changes.end(); ++it) {
225 DCHECK_EQ(extension_id_, it->extension_id());
226 switch (it->change_type()) {
227 case SyncChange::ACTION_ADD:
228 case SyncChange::ACTION_UPDATE: {
229 synced_keys_.insert(it->key());
230 Result result = delegate_->Set(it->key(), it->value());
231 if (result.HasError()) {
232 LOG(WARNING) << "Error pushing sync change to local settings: " <<
233 result.GetError();
234 }
235 break;
236 }
237
238 case SyncChange::ACTION_DELETE: {
239 synced_keys_.erase(it->key());
240 Result result = delegate_->Remove(it->key());
241 if (result.HasError()) {
242 LOG(WARNING) << "Error removing sync change from local settings: " <<
243 result.GetError();
244 }
245 break;
246 }
247
248 default:
249 NOTREACHED();
250 }
251 }
252 }
253
254 void SyncableExtensionSettingsStorage::SendAddsOrUpdatesToSync(
255 const DictionaryValue& settings) {
256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
257 DCHECK(sync_processor_);
258
259 SyncChangeList changes;
260 for (DictionaryValue::key_iterator it = settings.begin_keys();
261 it != settings.end_keys(); ++it) {
262 Value* value = NULL;
263 settings.GetWithoutPathExpansion(*it, &value);
264 DCHECK(value);
265 if (synced_keys_.count(*it)) {
266 // Key is synced, send ACTION_UPDATE to sync.
267 changes.push_back(
268 extension_settings_sync_util::CreateUpdate(
269 extension_id_, *it, *value));
270 } else {
271 // Key is not synced, send ACTION_ADD to sync.
272 changes.push_back(
273 extension_settings_sync_util::CreateAdd(extension_id_, *it, *value));
274 }
275 }
276
277 if (changes.empty()) {
278 return;
279 }
280
281 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
282 if (error.IsSet()) {
283 LOG(WARNING) << "Failed to send changes to sync: " << error.message();
284 return;
285 }
286
287 InsertAll(&synced_keys_, settings);
288 }
289
290 void SyncableExtensionSettingsStorage::SendDeletesToSync(
291 const std::vector<std::string>& keys) {
292 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
293 DCHECK(sync_processor_);
294
295 SyncChangeList changes;
296 for (std::vector<std::string>::const_iterator it = keys.begin();
297 it != keys.end(); ++it) {
298 // Only remove from sync if it's actually synced.
299 if (synced_keys_.count(*it)) {
300 changes.push_back(
301 extension_settings_sync_util::CreateDelete(extension_id_, *it));
302 }
303 }
304
305 if (changes.empty()) {
306 return;
307 }
308
309 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
310 if (error.IsSet()) {
311 LOG(WARNING) << "Failed to send changes to sync: " << error.message();
312 return;
313 }
314
315 for (std::vector<std::string>::const_iterator it = keys.begin();
316 it != keys.end(); ++it) {
317 synced_keys_.erase(*it);
318 }
319 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698