blob: 4b274017f854f9ec6468cccc81e14a7313cdb075 [file] [log] [blame]
[email protected]90e800c2012-06-12 23:11:001// 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/state_store.h"
6
[email protected]ebaa018d2012-12-11 21:42:537#include "base/bind.h"
8#include "base/message_loop.h"
[email protected]90e800c2012-06-12 23:11:009#include "chrome/common/chrome_notification_types.h"
10#include "chrome/common/extensions/extension.h"
11#include "content/public/browser/notification_service.h"
12#include "content/public/browser/notification_types.h"
13
14namespace {
15
[email protected]ebaa018d2012-12-11 21:42:5316// Delay, in seconds, before we should open the State Store database. We
17// defer it to avoid slowing down startup. See http://crbug.com/161848
18const int kInitDelaySeconds = 5;
19
[email protected]90e800c2012-06-12 23:11:0020std::string GetFullKey(const std::string& extension_id,
21 const std::string& key) {
22 return extension_id + "." + key;
23}
24
25} // namespace
26
27namespace extensions {
28
[email protected]ebaa018d2012-12-11 21:42:5329// Helper class to delay tasks until we're ready to start executing them.
30class StateStore::DelayedTaskQueue {
31 public:
32 DelayedTaskQueue() : ready_(false) {}
33 ~DelayedTaskQueue() {}
34
35 // Queues up a task for invoking once we're ready. Invokes immediately if
36 // we're already ready.
37 void InvokeWhenReady(base::Closure task);
38
39 // Marks us ready, and invokes all pending tasks.
40 void SetReady();
41
42 private:
43 bool ready_;
44 std::vector<base::Closure> pending_tasks_;
45};
46
47void StateStore::DelayedTaskQueue::InvokeWhenReady(base::Closure task) {
48 if (ready_) {
49 task.Run();
50 } else {
51 pending_tasks_.push_back(task);
52 }
53}
54
55void StateStore::DelayedTaskQueue::SetReady() {
56 ready_ = true;
57
58 for (size_t i = 0; i < pending_tasks_.size(); ++i)
59 pending_tasks_[i].Run();
60 pending_tasks_.clear();
61}
62
[email protected]a690e292012-12-19 19:22:4963StateStore::StateStore(Profile* profile,
64 const FilePath& db_path,
65 bool deferred_load)
[email protected]ebaa018d2012-12-11 21:42:5366 : task_queue_(new DelayedTaskQueue()) {
[email protected]90e800c2012-06-12 23:11:0067 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
68 content::Source<Profile>(profile));
69 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
70 content::Source<Profile>(profile));
[email protected]ebaa018d2012-12-11 21:42:5371
[email protected]a690e292012-12-19 19:22:4972 if (deferred_load) {
73 MessageLoop::current()->PostDelayedTask(FROM_HERE,
74 base::Bind(&StateStore::Init, AsWeakPtr(), db_path),
75 base::TimeDelta::FromSeconds(kInitDelaySeconds));
76 } else {
77 Init(db_path);
78 }
[email protected]90e800c2012-06-12 23:11:0079}
80
[email protected]bec64552012-06-13 20:25:4981StateStore::StateStore(Profile* profile, ValueStore* value_store)
[email protected]a690e292012-12-19 19:22:4982 : store_(value_store), task_queue_(new DelayedTaskQueue()) {
[email protected]bec64552012-06-13 20:25:4983 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
84 content::Source<Profile>(profile));
85 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
86 content::Source<Profile>(profile));
[email protected]ebaa018d2012-12-11 21:42:5387
88 // This constructor is for testing. No need to delay Init.
89 Init(FilePath());
[email protected]bec64552012-06-13 20:25:4990}
91
[email protected]90e800c2012-06-12 23:11:0092StateStore::~StateStore() {
93}
94
95void StateStore::RegisterKey(const std::string& key) {
96 registered_keys_.insert(key);
97}
98
99void StateStore::GetExtensionValue(const std::string& extension_id,
100 const std::string& key,
101 ReadCallback callback) {
[email protected]ebaa018d2012-12-11 21:42:53102 task_queue_->InvokeWhenReady(
103 base::Bind(&ValueStoreFrontend::Get, base::Unretained(&store_),
104 GetFullKey(extension_id, key), callback));
[email protected]90e800c2012-06-12 23:11:00105}
106
107void StateStore::SetExtensionValue(
108 const std::string& extension_id,
109 const std::string& key,
110 scoped_ptr<base::Value> value) {
[email protected]ebaa018d2012-12-11 21:42:53111 task_queue_->InvokeWhenReady(
112 base::Bind(&ValueStoreFrontend::Set, base::Unretained(&store_),
113 GetFullKey(extension_id, key), base::Passed(value.Pass())));
[email protected]90e800c2012-06-12 23:11:00114}
115
[email protected]a690e292012-12-19 19:22:49116void StateStore::RemoveExtensionValue(const std::string& extension_id,
117 const std::string& key) {
118 task_queue_->InvokeWhenReady(
119 base::Bind(&ValueStoreFrontend::Remove, base::Unretained(&store_),
120 GetFullKey(extension_id, key)));
121}
122
[email protected]90e800c2012-06-12 23:11:00123void StateStore::Observe(int type,
124 const content::NotificationSource& source,
125 const content::NotificationDetails& details) {
[email protected]90e800c2012-06-12 23:11:00126 switch (type) {
127 case chrome::NOTIFICATION_EXTENSION_INSTALLED:
[email protected]90e800c2012-06-12 23:11:00128 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
[email protected]a690e292012-12-19 19:22:49129 RemoveKeysForExtension(
130 content::Details<const Extension>(details).ptr()->id());
[email protected]90e800c2012-06-12 23:11:00131 break;
132 default:
133 NOTREACHED();
134 return;
135 }
[email protected]a690e292012-12-19 19:22:49136}
[email protected]90e800c2012-06-12 23:11:00137
[email protected]a690e292012-12-19 19:22:49138void StateStore::RemoveKeysForExtension(const std::string& extension_id) {
[email protected]90e800c2012-06-12 23:11:00139 for (std::set<std::string>::iterator key = registered_keys_.begin();
140 key != registered_keys_.end(); ++key) {
[email protected]ebaa018d2012-12-11 21:42:53141 task_queue_->InvokeWhenReady(
142 base::Bind(&ValueStoreFrontend::Remove, base::Unretained(&store_),
143 GetFullKey(extension_id, *key)));
[email protected]90e800c2012-06-12 23:11:00144 }
145}
146
[email protected]ebaa018d2012-12-11 21:42:53147void StateStore::Init(const FilePath& db_path) {
148 if (!db_path.empty())
149 store_.Init(db_path);
150 task_queue_->SetReady();
151}
152
[email protected]90e800c2012-06-12 23:11:00153} // namespace extensions