OLD | NEW |
---|---|
(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 SendLocalSettingsToSync(*settings); | |
140 } else { | |
141 OverwriteLocalSettingsWithSync(sync_state, *settings); | |
142 } | |
143 return SyncError(); | |
144 } | |
145 | |
146 void SyncableExtensionSettingsStorage::SendLocalSettingsToSync( | |
147 const DictionaryValue& settings) { | |
148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
149 SyncChangeList changes; | |
150 for (DictionaryValue::key_iterator it = settings.begin_keys(); | |
151 it != settings.end_keys(); ++it) { | |
152 Value* value; | |
153 settings.GetWithoutPathExpansion(*it, &value); | |
154 changes.push_back( | |
155 extension_settings_sync_util::CreateAdd(extension_id_, *it, *value)); | |
156 } | |
157 | |
158 if (changes.empty()) { | |
159 return; | |
160 } | |
161 | |
162 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, changes); | |
163 if (error.IsSet()) { | |
164 LOG(WARNING) << "Failed to send changes to sync: " << error.message(); | |
akalin
2011/09/20 14:53:11
have this return an error and propagate to StartSy
not at google - send to devlin
2011/09/21 00:20:14
Done.
| |
165 return; | |
166 } | |
167 | |
168 InsertAll(settings, &synced_keys_); | |
169 } | |
170 | |
171 void SyncableExtensionSettingsStorage::OverwriteLocalSettingsWithSync( | |
172 const DictionaryValue& sync_state, const DictionaryValue& settings) { | |
173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
174 // Treat this as a list of changes to sync and use ProcessSyncChanges. | |
175 // This gives notifications etc for free. | |
176 scoped_ptr<DictionaryValue> new_sync_state(sync_state.DeepCopy()); | |
177 | |
178 ExtensionSettingSyncDataList changes; | |
179 for (DictionaryValue::key_iterator it = settings.begin_keys(); | |
180 it != settings.end_keys(); ++it) { | |
181 Value* sync_value = NULL; | |
182 if (new_sync_state->RemoveWithoutPathExpansion(*it, &sync_value)) { | |
183 Value* local_value = NULL; | |
184 settings.GetWithoutPathExpansion(*it, &local_value); | |
185 if (!local_value->Equals(sync_value)) { | |
186 // Sync value is different, update local setting with new value. | |
187 changes.push_back( | |
188 ExtensionSettingSyncData( | |
189 SyncChange::ACTION_UPDATE, extension_id_, *it, sync_value)); | |
190 } | |
191 } else { | |
192 // Not synced, delete local setting. | |
193 changes.push_back( | |
194 ExtensionSettingSyncData( | |
195 SyncChange::ACTION_DELETE, | |
196 extension_id_, | |
197 *it, | |
198 new DictionaryValue())); | |
199 } | |
200 } | |
201 | |
202 // Add all new settings to local settings. | |
203 while (!new_sync_state->empty()) { | |
204 std::string key = *new_sync_state->begin_keys(); | |
205 Value* value; | |
206 new_sync_state->RemoveWithoutPathExpansion(key, &value); | |
207 changes.push_back( | |
208 ExtensionSettingSyncData( | |
209 SyncChange::ACTION_ADD, extension_id_, key, value)); | |
210 } | |
211 | |
212 if (!changes.empty()) { | |
213 ProcessSyncChanges(changes); | |
akalin
2011/09/20 14:53:11
propagate return value from here to StartSyncing
not at google - send to devlin
2011/09/21 00:20:14
Done.
| |
214 } | |
215 } | |
216 | |
217 void SyncableExtensionSettingsStorage::StopSyncing() { | |
218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
219 DCHECK(sync_processor_); | |
220 sync_processor_ = NULL; | |
221 synced_keys_.clear(); | |
222 } | |
223 | |
224 std::vector<SyncError> SyncableExtensionSettingsStorage::ProcessSyncChanges( | |
225 const ExtensionSettingSyncDataList& sync_changes) { | |
226 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
227 DCHECK(sync_processor_); | |
228 DCHECK(!sync_changes.empty()) << "No sync changes for " << extension_id_; | |
229 | |
230 std::vector<SyncError> errors; | |
231 | |
232 for (ExtensionSettingSyncDataList::const_iterator it = sync_changes.begin(); | |
233 it != sync_changes.end(); ++it) { | |
234 DCHECK_EQ(extension_id_, it->extension_id()); | |
235 switch (it->change_type()) { | |
236 case SyncChange::ACTION_ADD: | |
237 case SyncChange::ACTION_UPDATE: { | |
238 synced_keys_.insert(it->key()); | |
239 Result result = delegate_->Set(it->key(), it->value()); | |
240 if (result.HasError()) { | |
241 errors.push_back(SyncError( | |
242 FROM_HERE, | |
243 std::string("Error pushing sync change to local settings: ") + | |
244 result.GetError(), | |
245 syncable::EXTENSION_SETTINGS)); | |
246 } | |
247 break; | |
248 } | |
249 | |
250 case SyncChange::ACTION_DELETE: { | |
251 synced_keys_.erase(it->key()); | |
252 Result result = delegate_->Remove(it->key()); | |
253 if (result.HasError()) { | |
254 errors.push_back(SyncError( | |
255 FROM_HERE, | |
256 std::string("Error removing sync change from local settings: ") + | |
257 result.GetError(), | |
258 syncable::EXTENSION_SETTINGS)); | |
259 } | |
260 break; | |
261 } | |
262 | |
263 default: | |
264 NOTREACHED(); | |
265 } | |
266 } | |
267 | |
268 return errors; | |
269 } | |
270 | |
271 void SyncableExtensionSettingsStorage::SendAddsOrUpdatesToSync( | |
272 const DictionaryValue& settings) { | |
273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
274 DCHECK(sync_processor_); | |
275 | |
276 SyncChangeList changes; | |
277 for (DictionaryValue::key_iterator it = settings.begin_keys(); | |
278 it != settings.end_keys(); ++it) { | |
279 Value* value = NULL; | |
280 settings.GetWithoutPathExpansion(*it, &value); | |
281 DCHECK(value); | |
282 if (synced_keys_.count(*it)) { | |
283 // Key is synced, send ACTION_UPDATE to sync. | |
284 changes.push_back( | |
285 extension_settings_sync_util::CreateUpdate( | |
286 extension_id_, *it, *value)); | |
287 } else { | |
288 // Key is not synced, send ACTION_ADD to sync. | |
289 changes.push_back( | |
290 extension_settings_sync_util::CreateAdd(extension_id_, *it, *value)); | |
291 } | |
292 } | |
293 | |
294 if (changes.empty()) { | |
295 return; | |
296 } | |
297 | |
298 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, changes); | |
299 if (error.IsSet()) { | |
300 LOG(WARNING) << "Failed to send changes to sync: " << error.message(); | |
301 return; | |
302 } | |
303 | |
304 InsertAll(settings, &synced_keys_); | |
305 } | |
306 | |
307 void SyncableExtensionSettingsStorage::SendDeletesToSync( | |
308 const std::vector<std::string>& keys) { | |
309 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
310 DCHECK(sync_processor_); | |
311 | |
312 SyncChangeList changes; | |
313 for (std::vector<std::string>::const_iterator it = keys.begin(); | |
314 it != keys.end(); ++it) { | |
315 // Only remove from sync if it's actually synced. | |
316 if (synced_keys_.count(*it)) { | |
317 changes.push_back( | |
318 extension_settings_sync_util::CreateDelete(extension_id_, *it)); | |
319 } | |
320 } | |
321 | |
322 if (changes.empty()) { | |
323 return; | |
324 } | |
325 | |
326 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, changes); | |
327 if (error.IsSet()) { | |
328 LOG(WARNING) << "Failed to send changes to sync: " << error.message(); | |
329 return; | |
330 } | |
331 | |
332 for (std::vector<std::string>::const_iterator it = keys.begin(); | |
333 it != keys.end(); ++it) { | |
334 synced_keys_.erase(*it); | |
335 } | |
336 } | |
OLD | NEW |