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

Side by Side Diff: chrome/browser/extensions/syncable_extension_settings_storage.cc

Issue 7977018: Enable sync for the settings from the Extension Settings API. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix race condition in ExtensionSettingsUIWrapper::Core 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 namespace {
14
15 // Inserts all the keys from a dictionary into a set of strings.
16 void InsertAll(const DictionaryValue& src, std::set<std::string>* dst) {
17 for (DictionaryValue::key_iterator it = src.begin_keys();
18 it != src.end_keys(); ++it) {
19 dst->insert(*it);
20 }
21 }
22
23 } // namespace
24
25 SyncableExtensionSettingsStorage::SyncableExtensionSettingsStorage(
26 std::string extension_id, ExtensionSettingsStorage* delegate)
27 : extension_id_(extension_id), delegate_(delegate), sync_processor_(NULL) {
28 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
29 }
30
31 SyncableExtensionSettingsStorage::~SyncableExtensionSettingsStorage() {
32 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
33 }
34
35 ExtensionSettingsStorage::Result SyncableExtensionSettingsStorage::Get(
36 const std::string& key) {
37 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
38 return delegate_->Get(key);
39 }
40
41 ExtensionSettingsStorage::Result SyncableExtensionSettingsStorage::Get(
42 const std::vector<std::string>& keys) {
43 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
44 return delegate_->Get(keys);
45 }
46
47 ExtensionSettingsStorage::Result SyncableExtensionSettingsStorage::Get() {
48 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
49 return delegate_->Get();
50 }
51
52 ExtensionSettingsStorage::Result SyncableExtensionSettingsStorage::Set(
53 const std::string& key, const Value& value) {
54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
55 Result result = delegate_->Set(key, value);
56 if (result.HasError()) {
57 return result;
58 }
59 if (sync_processor_) {
60 SendAddsOrUpdatesToSync(*result.GetSettings());
61 }
62 return result;
63 }
64
65 ExtensionSettingsStorage::Result SyncableExtensionSettingsStorage::Set(
66 const DictionaryValue& values) {
67 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
68 Result result = delegate_->Set(values);
69 if (result.HasError()) {
70 return result;
71 }
72 if (sync_processor_) {
73 SendAddsOrUpdatesToSync(*result.GetSettings());
74 }
75 return result;
76 }
77
78 ExtensionSettingsStorage::Result SyncableExtensionSettingsStorage::Remove(
79 const std::string& key) {
80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
81 Result result = delegate_->Remove(key);
82 if (result.HasError()) {
83 return result;
84 }
85 if (sync_processor_) {
86 std::vector<std::string> keys;
87 keys.push_back(key);
88 SendDeletesToSync(keys);
89 }
90 return result;
91 }
92
93 ExtensionSettingsStorage::Result SyncableExtensionSettingsStorage::Remove(
94 const std::vector<std::string>& keys) {
95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
96 Result result = delegate_->Remove(keys);
97 if (result.HasError()) {
98 return result;
99 }
100 if (sync_processor_) {
101 SendDeletesToSync(keys);
102 }
103 return result;
104 }
105
106 ExtensionSettingsStorage::Result SyncableExtensionSettingsStorage::Clear() {
107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
108 Result result = delegate_->Clear();
109 if (result.HasError()) {
110 return result;
111 }
112 if (sync_processor_) {
113 SendDeletesToSync(
114 std::vector<std::string>(synced_keys_.begin(), synced_keys_.end()));
115 }
116 return result;
117 }
118
119 // Sync-related methods.
120
121 SyncError SyncableExtensionSettingsStorage::StartSyncing(
122 const DictionaryValue& sync_state, SyncChangeProcessor* sync_processor) {
123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
124 DCHECK(!sync_processor_);
125 DCHECK(synced_keys_.empty());
126 sync_processor_ = sync_processor;
127 InsertAll(sync_state, &synced_keys_);
128
129 Result maybe_settings = delegate_->Get();
130 if (maybe_settings.HasError()) {
131 return SyncError(
132 FROM_HERE,
133 std::string("Failed to get settings: ") + maybe_settings.GetError(),
134 syncable::EXTENSION_SETTINGS);
135 }
136
137 DictionaryValue* settings = maybe_settings.GetSettings();
138 if (sync_state.empty()) {
139 return SendLocalSettingsToSync(*settings);
140 }
141 return OverwriteLocalSettingsWithSync(sync_state, *settings);
142 }
143
144 SyncError SyncableExtensionSettingsStorage::SendLocalSettingsToSync(
145 const DictionaryValue& settings) {
146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
147 SyncChangeList changes;
148 for (DictionaryValue::key_iterator it = settings.begin_keys();
149 it != settings.end_keys(); ++it) {
150 Value* value;
151 settings.GetWithoutPathExpansion(*it, &value);
152 changes.push_back(
153 extension_settings_sync_util::CreateAdd(extension_id_, *it, *value));
154 }
155
156 if (changes.empty()) {
157 return SyncError();
158 }
159
160 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
161 if (error.IsSet()) {
162 return error;
163 }
164
165 InsertAll(settings, &synced_keys_);
166 return SyncError();
167 }
168
169 SyncError SyncableExtensionSettingsStorage::OverwriteLocalSettingsWithSync(
170 const DictionaryValue& sync_state, const DictionaryValue& settings) {
171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
172 // Treat this as a list of changes to sync and use ProcessSyncChanges.
173 // This gives notifications etc for free.
174 scoped_ptr<DictionaryValue> new_sync_state(sync_state.DeepCopy());
175
176 ExtensionSettingSyncDataList changes;
177 for (DictionaryValue::key_iterator it = settings.begin_keys();
178 it != settings.end_keys(); ++it) {
179 Value* sync_value = NULL;
180 if (new_sync_state->RemoveWithoutPathExpansion(*it, &sync_value)) {
181 Value* local_value = NULL;
182 settings.GetWithoutPathExpansion(*it, &local_value);
183 if (!local_value->Equals(sync_value)) {
184 // Sync value is different, update local setting with new value.
185 changes.push_back(
186 ExtensionSettingSyncData(
187 SyncChange::ACTION_UPDATE, extension_id_, *it, sync_value));
188 }
189 } else {
190 // Not synced, delete local setting.
191 changes.push_back(
192 ExtensionSettingSyncData(
193 SyncChange::ACTION_DELETE,
194 extension_id_,
195 *it,
196 new DictionaryValue()));
197 }
198 }
199
200 // Add all new settings to local settings.
201 while (!new_sync_state->empty()) {
202 std::string key = *new_sync_state->begin_keys();
203 Value* value;
204 new_sync_state->RemoveWithoutPathExpansion(key, &value);
205 changes.push_back(
206 ExtensionSettingSyncData(
207 SyncChange::ACTION_ADD, extension_id_, key, value));
208 }
209
210 if (changes.empty()) {
211 return SyncError();
212 }
213
214 std::vector<SyncError> sync_errors(ProcessSyncChanges(changes));
215 if (sync_errors.empty()) {
216 return SyncError();
217 }
218 // TODO(kalman): something sensible with multiple errors.
219 return sync_errors[0];
220 }
221
222 void SyncableExtensionSettingsStorage::StopSyncing() {
223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
224 DCHECK(sync_processor_);
225 sync_processor_ = NULL;
226 synced_keys_.clear();
227 }
228
229 std::vector<SyncError> SyncableExtensionSettingsStorage::ProcessSyncChanges(
230 const ExtensionSettingSyncDataList& sync_changes) {
231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
232 DCHECK(sync_processor_);
233 DCHECK(!sync_changes.empty()) << "No sync changes for " << extension_id_;
234
235 std::vector<SyncError> errors;
236
237 for (ExtensionSettingSyncDataList::const_iterator it = sync_changes.begin();
238 it != sync_changes.end(); ++it) {
239 DCHECK_EQ(extension_id_, it->extension_id());
240 switch (it->change_type()) {
241 case SyncChange::ACTION_ADD:
242 case SyncChange::ACTION_UPDATE: {
243 synced_keys_.insert(it->key());
244 Result result = delegate_->Set(it->key(), it->value());
245 if (result.HasError()) {
246 errors.push_back(SyncError(
247 FROM_HERE,
248 std::string("Error pushing sync change to local settings: ") +
249 result.GetError(),
250 syncable::EXTENSION_SETTINGS));
251 }
252 break;
253 }
254
255 case SyncChange::ACTION_DELETE: {
256 synced_keys_.erase(it->key());
257 Result result = delegate_->Remove(it->key());
258 if (result.HasError()) {
259 errors.push_back(SyncError(
260 FROM_HERE,
261 std::string("Error removing sync change from local settings: ") +
262 result.GetError(),
263 syncable::EXTENSION_SETTINGS));
264 }
265 break;
266 }
267
268 default:
269 NOTREACHED();
270 }
271 }
272
273 return errors;
274 }
275
276 void SyncableExtensionSettingsStorage::SendAddsOrUpdatesToSync(
277 const DictionaryValue& settings) {
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
279 DCHECK(sync_processor_);
280
281 SyncChangeList changes;
282 for (DictionaryValue::key_iterator it = settings.begin_keys();
283 it != settings.end_keys(); ++it) {
284 Value* value = NULL;
285 settings.GetWithoutPathExpansion(*it, &value);
286 DCHECK(value);
287 if (synced_keys_.count(*it)) {
288 // Key is synced, send ACTION_UPDATE to sync.
289 changes.push_back(
290 extension_settings_sync_util::CreateUpdate(
291 extension_id_, *it, *value));
292 } else {
293 // Key is not synced, send ACTION_ADD to sync.
294 changes.push_back(
295 extension_settings_sync_util::CreateAdd(extension_id_, *it, *value));
296 }
297 }
298
299 if (changes.empty()) {
300 return;
301 }
302
303 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
304 if (error.IsSet()) {
305 LOG(WARNING) << "Failed to send changes to sync: " << error.message();
306 return;
307 }
308
309 InsertAll(settings, &synced_keys_);
310 }
311
312 void SyncableExtensionSettingsStorage::SendDeletesToSync(
313 const std::vector<std::string>& keys) {
314 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
315 DCHECK(sync_processor_);
316
317 SyncChangeList changes;
318 for (std::vector<std::string>::const_iterator it = keys.begin();
319 it != keys.end(); ++it) {
320 // Only remove from sync if it's actually synced.
321 if (synced_keys_.count(*it)) {
322 changes.push_back(
323 extension_settings_sync_util::CreateDelete(extension_id_, *it));
324 }
325 }
326
327 if (changes.empty()) {
328 return;
329 }
330
331 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
332 if (error.IsSet()) {
333 LOG(WARNING) << "Failed to send changes to sync: " << error.message();
334 return;
335 }
336
337 for (std::vector<std::string>::const_iterator it = keys.begin();
338 it != keys.end(); ++it) {
339 synced_keys_.erase(*it);
340 }
341 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/syncable_extension_settings_storage.h ('k') | chrome/browser/profiles/profile_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698