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/settings_sync_processor.h"
6#include "chrome/browser/extensions/api/storage/settings_sync_util.h"
7#include "content/public/browser/browser_thread.h"
8#include "extensions/browser/api/storage/settings_namespace.h"
9#include "sync/api/sync_change_processor.h"
10#include "sync/api/sync_data.h"
11#include "sync/protocol/extension_setting_specifics.pb.h"
12
13using content::BrowserThread;
14
15namespace extensions {
16
17SettingsSyncProcessor::SettingsSyncProcessor(
18    const std::string& extension_id,
19    syncer::ModelType type,
20    syncer::SyncChangeProcessor* sync_processor)
21    : extension_id_(extension_id),
22      type_(type),
23      sync_processor_(sync_processor),
24      initialized_(false) {
25  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
26  CHECK(type == syncer::EXTENSION_SETTINGS || type == syncer::APP_SETTINGS);
27  CHECK(sync_processor);
28}
29
30SettingsSyncProcessor::~SettingsSyncProcessor() {
31  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
32}
33
34void SettingsSyncProcessor::Init(const base::DictionaryValue& initial_state) {
35  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
36  CHECK(!initialized_) << "Init called multiple times";
37
38  for (base::DictionaryValue::Iterator i(initial_state); !i.IsAtEnd();
39       i.Advance())
40    synced_keys_.insert(i.key());
41
42  initialized_ = true;
43}
44
45syncer::SyncError SettingsSyncProcessor::SendChanges(
46    const ValueStoreChangeList& changes) {
47  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
48  CHECK(initialized_) << "Init not called";
49
50  syncer::SyncChangeList sync_changes;
51  std::set<std::string> added_keys;
52  std::set<std::string> deleted_keys;
53
54  for (ValueStoreChangeList::const_iterator i = changes.begin();
55      i != changes.end(); ++i) {
56    const std::string& key = i->key();
57    const base::Value* value = i->new_value();
58    if (value) {
59      if (synced_keys_.count(key)) {
60        // New value, key is synced; send ACTION_UPDATE.
61        sync_changes.push_back(settings_sync_util::CreateUpdate(
62            extension_id_, key, *value, type_));
63      } else {
64        // New value, key is not synced; send ACTION_ADD.
65        sync_changes.push_back(settings_sync_util::CreateAdd(
66            extension_id_, key, *value, type_));
67        added_keys.insert(key);
68      }
69    } else {
70      if (synced_keys_.count(key)) {
71        // Clearing value, key is synced; send ACTION_DELETE.
72        sync_changes.push_back(settings_sync_util::CreateDelete(
73            extension_id_, key, type_));
74        deleted_keys.insert(key);
75      } else {
76        LOG(WARNING) << "Deleted " << key << " but not in synced_keys_";
77      }
78    }
79  }
80
81  if (sync_changes.empty())
82    return syncer::SyncError();
83
84  syncer::SyncError error =
85      sync_processor_->ProcessSyncChanges(FROM_HERE, sync_changes);
86  if (error.IsSet())
87    return error;
88
89  synced_keys_.insert(added_keys.begin(), added_keys.end());
90  for (std::set<std::string>::iterator i = deleted_keys.begin();
91      i != deleted_keys.end(); ++i) {
92    synced_keys_.erase(*i);
93  }
94
95  return syncer::SyncError();
96}
97
98void SettingsSyncProcessor::NotifyChanges(const ValueStoreChangeList& changes) {
99  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
100  CHECK(initialized_) << "Init not called";
101
102  for (ValueStoreChangeList::const_iterator i = changes.begin();
103      i != changes.end(); ++i) {
104    if (i->new_value())
105      synced_keys_.insert(i->key());
106    else
107      synced_keys_.erase(i->key());
108  }
109}
110
111}  // namespace extensions
112