Home | History | Annotate | Download | only in storage
      1 // Copyright (c) 2012 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/api/storage/syncable_settings_storage.h"
      6 
      7 #include "chrome/browser/extensions/api/storage/settings_namespace.h"
      8 #include "chrome/browser/extensions/api/storage/settings_sync_processor.h"
      9 #include "chrome/browser/extensions/api/storage/settings_sync_util.h"
     10 #include "content/public/browser/browser_thread.h"
     11 #include "sync/api/sync_data.h"
     12 #include "sync/protocol/extension_setting_specifics.pb.h"
     13 
     14 namespace extensions {
     15 
     16 using content::BrowserThread;
     17 
     18 SyncableSettingsStorage::SyncableSettingsStorage(
     19     const scoped_refptr<ObserverListThreadSafe<SettingsObserver> >&
     20         observers,
     21     const std::string& extension_id,
     22     ValueStore* delegate)
     23     : observers_(observers),
     24       extension_id_(extension_id),
     25       delegate_(delegate) {
     26   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     27 }
     28 
     29 SyncableSettingsStorage::~SyncableSettingsStorage() {
     30   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     31 }
     32 
     33 size_t SyncableSettingsStorage::GetBytesInUse(const std::string& key) {
     34   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     35   return delegate_->GetBytesInUse(key);
     36 }
     37 
     38 size_t SyncableSettingsStorage::GetBytesInUse(
     39     const std::vector<std::string>& keys) {
     40   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     41   return delegate_->GetBytesInUse(keys);
     42 }
     43 
     44 size_t SyncableSettingsStorage::GetBytesInUse() {
     45   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     46   return delegate_->GetBytesInUse();
     47 }
     48 
     49 ValueStore::ReadResult SyncableSettingsStorage::Get(
     50     const std::string& key) {
     51   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     52   return delegate_->Get(key);
     53 }
     54 
     55 ValueStore::ReadResult SyncableSettingsStorage::Get(
     56     const std::vector<std::string>& keys) {
     57   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     58   return delegate_->Get(keys);
     59 }
     60 
     61 ValueStore::ReadResult SyncableSettingsStorage::Get() {
     62   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     63   return delegate_->Get();
     64 }
     65 
     66 ValueStore::WriteResult SyncableSettingsStorage::Set(
     67     WriteOptions options, const std::string& key, const Value& value) {
     68   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     69   WriteResult result = delegate_->Set(options, key, value);
     70   if (result->HasError()) {
     71     return result.Pass();
     72   }
     73   SyncResultIfEnabled(result);
     74   return result.Pass();
     75 }
     76 
     77 ValueStore::WriteResult SyncableSettingsStorage::Set(
     78     WriteOptions options, const base::DictionaryValue& values) {
     79   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     80   WriteResult result = delegate_->Set(options, values);
     81   if (result->HasError()) {
     82     return result.Pass();
     83   }
     84   SyncResultIfEnabled(result);
     85   return result.Pass();
     86 }
     87 
     88 ValueStore::WriteResult SyncableSettingsStorage::Remove(
     89     const std::string& key) {
     90   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     91   WriteResult result = delegate_->Remove(key);
     92   if (result->HasError()) {
     93     return result.Pass();
     94   }
     95   SyncResultIfEnabled(result);
     96   return result.Pass();
     97 }
     98 
     99 ValueStore::WriteResult SyncableSettingsStorage::Remove(
    100     const std::vector<std::string>& keys) {
    101   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    102   WriteResult result = delegate_->Remove(keys);
    103   if (result->HasError()) {
    104     return result.Pass();
    105   }
    106   SyncResultIfEnabled(result);
    107   return result.Pass();
    108 }
    109 
    110 ValueStore::WriteResult SyncableSettingsStorage::Clear() {
    111   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    112   WriteResult result = delegate_->Clear();
    113   if (result->HasError()) {
    114     return result.Pass();
    115   }
    116   SyncResultIfEnabled(result);
    117   return result.Pass();
    118 }
    119 
    120 void SyncableSettingsStorage::SyncResultIfEnabled(
    121     const ValueStore::WriteResult& result) {
    122   if (sync_processor_.get() && !result->changes().empty()) {
    123     syncer::SyncError error = sync_processor_->SendChanges(result->changes());
    124     if (error.IsSet())
    125       StopSyncing();
    126   }
    127 }
    128 
    129 // Sync-related methods.
    130 
    131 syncer::SyncError SyncableSettingsStorage::StartSyncing(
    132     const base::DictionaryValue& sync_state,
    133     scoped_ptr<SettingsSyncProcessor> sync_processor) {
    134   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    135   DCHECK(!sync_processor_.get());
    136 
    137   sync_processor_ = sync_processor.Pass();
    138   sync_processor_->Init(sync_state);
    139 
    140   ReadResult maybe_settings = delegate_->Get();
    141   if (maybe_settings->HasError()) {
    142     return syncer::SyncError(
    143         FROM_HERE,
    144         syncer::SyncError::DATATYPE_ERROR,
    145         std::string("Failed to get settings: ") + maybe_settings->error(),
    146         sync_processor_->type());
    147   }
    148 
    149   const base::DictionaryValue& settings = *maybe_settings->settings().get();
    150   if (sync_state.empty())
    151     return SendLocalSettingsToSync(settings);
    152   else
    153     return OverwriteLocalSettingsWithSync(sync_state, settings);
    154 }
    155 
    156 syncer::SyncError SyncableSettingsStorage::SendLocalSettingsToSync(
    157     const base::DictionaryValue& settings) {
    158   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    159 
    160   ValueStoreChangeList changes;
    161   for (base::DictionaryValue::Iterator i(settings); !i.IsAtEnd(); i.Advance()) {
    162     changes.push_back(ValueStoreChange(i.key(), NULL, i.value().DeepCopy()));
    163   }
    164 
    165   if (changes.empty())
    166     return syncer::SyncError();
    167 
    168   syncer::SyncError error = sync_processor_->SendChanges(changes);
    169   if (error.IsSet())
    170     StopSyncing();
    171 
    172   return error;
    173 }
    174 
    175 syncer::SyncError SyncableSettingsStorage::OverwriteLocalSettingsWithSync(
    176     const base::DictionaryValue& sync_state,
    177     const base::DictionaryValue& settings) {
    178   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    179   // Treat this as a list of changes to sync and use ProcessSyncChanges.
    180   // This gives notifications etc for free.
    181   scoped_ptr<base::DictionaryValue> new_sync_state(sync_state.DeepCopy());
    182 
    183   SettingSyncDataList changes;
    184   for (base::DictionaryValue::Iterator it(settings); !it.IsAtEnd(); it.Advance()) {
    185     scoped_ptr<Value> sync_value;
    186     if (new_sync_state->RemoveWithoutPathExpansion(it.key(), &sync_value)) {
    187       if (sync_value->Equals(&it.value())) {
    188         // Sync and local values are the same, no changes to send.
    189       } else {
    190         // Sync value is different, update local setting with new value.
    191         changes.push_back(
    192             SettingSyncData(
    193                 syncer::SyncChange::ACTION_UPDATE,
    194                 extension_id_,
    195                 it.key(),
    196                 sync_value.Pass()));
    197       }
    198     } else {
    199       // Not synced, delete local setting.
    200       changes.push_back(
    201           SettingSyncData(
    202               syncer::SyncChange::ACTION_DELETE,
    203               extension_id_,
    204               it.key(),
    205               scoped_ptr<Value>(new base::DictionaryValue())));
    206     }
    207   }
    208 
    209   // Add all new settings to local settings.
    210   while (!new_sync_state->empty()) {
    211     base::DictionaryValue::Iterator first_entry(*new_sync_state);
    212     std::string key = first_entry.key();
    213     scoped_ptr<Value> value;
    214     CHECK(new_sync_state->RemoveWithoutPathExpansion(key, &value));
    215     changes.push_back(
    216         SettingSyncData(
    217             syncer::SyncChange::ACTION_ADD,
    218             extension_id_,
    219             key,
    220             value.Pass()));
    221   }
    222 
    223   if (changes.empty())
    224     return syncer::SyncError();
    225 
    226   return ProcessSyncChanges(changes);
    227 }
    228 
    229 void SyncableSettingsStorage::StopSyncing() {
    230   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    231   sync_processor_.reset();
    232 }
    233 
    234 syncer::SyncError SyncableSettingsStorage::ProcessSyncChanges(
    235     const SettingSyncDataList& sync_changes) {
    236   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    237   DCHECK(!sync_changes.empty()) << "No sync changes for " << extension_id_;
    238 
    239   if (!sync_processor_.get()) {
    240     return syncer::SyncError(
    241         FROM_HERE,
    242         syncer::SyncError::DATATYPE_ERROR,
    243         std::string("Sync is inactive for ") + extension_id_,
    244         syncer::UNSPECIFIED);
    245   }
    246 
    247   std::vector<syncer::SyncError> errors;
    248   ValueStoreChangeList changes;
    249 
    250   for (SettingSyncDataList::const_iterator it = sync_changes.begin();
    251       it != sync_changes.end(); ++it) {
    252     DCHECK_EQ(extension_id_, it->extension_id());
    253 
    254     const std::string& key = it->key();
    255     const Value& value = it->value();
    256 
    257     scoped_ptr<Value> current_value;
    258     {
    259       ReadResult maybe_settings = Get(it->key());
    260       if (maybe_settings->HasError()) {
    261         errors.push_back(syncer::SyncError(
    262             FROM_HERE,
    263             syncer::SyncError::DATATYPE_ERROR,
    264             std::string("Error getting current sync state for ") +
    265                 extension_id_ + "/" + key + ": " + maybe_settings->error(),
    266             sync_processor_->type()));
    267         continue;
    268       }
    269       Value* value = NULL;
    270       if (maybe_settings->settings()->GetWithoutPathExpansion(key, &value)) {
    271         current_value.reset(value->DeepCopy());
    272       }
    273     }
    274 
    275     syncer::SyncError error;
    276 
    277     switch (it->change_type()) {
    278       case syncer::SyncChange::ACTION_ADD:
    279         if (!current_value.get()) {
    280           error = OnSyncAdd(key, value.DeepCopy(), &changes);
    281         } else {
    282           // Already a value; hopefully a local change has beaten sync in a
    283           // race and it's not a bug, so pretend it's an update.
    284           LOG(WARNING) << "Got add from sync for existing setting " <<
    285               extension_id_ << "/" << key;
    286           error = OnSyncUpdate(
    287               key, current_value.release(), value.DeepCopy(), &changes);
    288         }
    289         break;
    290 
    291       case syncer::SyncChange::ACTION_UPDATE:
    292         if (current_value.get()) {
    293           error = OnSyncUpdate(
    294               key, current_value.release(), value.DeepCopy(), &changes);
    295         } else {
    296           // Similarly, pretend it's an add.
    297           LOG(WARNING) << "Got update from sync for nonexistent setting" <<
    298               extension_id_ << "/" << key;
    299           error = OnSyncAdd(key, value.DeepCopy(), &changes);
    300         }
    301         break;
    302 
    303       case syncer::SyncChange::ACTION_DELETE:
    304         if (current_value.get()) {
    305           error = OnSyncDelete(key, current_value.release(), &changes);
    306         } else {
    307           // Similarly, ignore it.
    308           LOG(WARNING) << "Got delete from sync for nonexistent setting " <<
    309               extension_id_ << "/" << key;
    310         }
    311         break;
    312 
    313       default:
    314         NOTREACHED();
    315     }
    316 
    317     if (error.IsSet()) {
    318       errors.push_back(error);
    319     }
    320   }
    321 
    322   sync_processor_->NotifyChanges(changes);
    323 
    324   observers_->Notify(
    325       &SettingsObserver::OnSettingsChanged,
    326       extension_id_,
    327       settings_namespace::SYNC,
    328       ValueStoreChange::ToJson(changes));
    329 
    330   // TODO(kalman): Something sensible with multiple errors.
    331   return errors.empty() ? syncer::SyncError() : errors[0];
    332 }
    333 
    334 syncer::SyncError SyncableSettingsStorage::OnSyncAdd(
    335     const std::string& key,
    336     Value* new_value,
    337     ValueStoreChangeList* changes) {
    338   DCHECK(new_value);
    339   WriteResult result = delegate_->Set(IGNORE_QUOTA, key, *new_value);
    340   if (result->HasError()) {
    341     return syncer::SyncError(
    342         FROM_HERE,
    343         syncer::SyncError::DATATYPE_ERROR,
    344         std::string("Error pushing sync add to local settings: ") +
    345             result->error(),
    346         sync_processor_->type());
    347   }
    348   changes->push_back(ValueStoreChange(key, NULL, new_value));
    349   return syncer::SyncError();
    350 }
    351 
    352 syncer::SyncError SyncableSettingsStorage::OnSyncUpdate(
    353     const std::string& key,
    354     Value* old_value,
    355     Value* new_value,
    356     ValueStoreChangeList* changes) {
    357   DCHECK(old_value);
    358   DCHECK(new_value);
    359   WriteResult result = delegate_->Set(IGNORE_QUOTA, key, *new_value);
    360   if (result->HasError()) {
    361     return syncer::SyncError(
    362         FROM_HERE,
    363         syncer::SyncError::DATATYPE_ERROR,
    364         std::string("Error pushing sync update to local settings: ") +
    365             result->error(),
    366         sync_processor_->type());
    367   }
    368   changes->push_back(ValueStoreChange(key, old_value, new_value));
    369   return syncer::SyncError();
    370 }
    371 
    372 syncer::SyncError SyncableSettingsStorage::OnSyncDelete(
    373     const std::string& key,
    374     Value* old_value,
    375     ValueStoreChangeList* changes) {
    376   DCHECK(old_value);
    377   WriteResult result = delegate_->Remove(key);
    378   if (result->HasError()) {
    379     return syncer::SyncError(
    380         FROM_HERE,
    381         syncer::SyncError::DATATYPE_ERROR,
    382         std::string("Error pushing sync remove to local settings: ") +
    383             result->error(),
    384         sync_processor_->type());
    385   }
    386   changes->push_back(ValueStoreChange(key, old_value, NULL));
    387   return syncer::SyncError();
    388 }
    389 
    390 }  // namespace extensions
    391