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

Side by Side Diff: chrome/browser/file_system/entry_watcher_service.cc

Issue 452043003: [ew] Add basic classes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comments. Created 6 years, 4 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 2014 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/file_system/entry_watcher_service.h"
6
7 #include "base/thread_task_runner_handle.h"
8 #include "chrome/browser/extensions/extension_util.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/common/extensions/api/file_system.h"
11 #include "components/keyed_service/content/browser_context_dependency_manager.h"
12 #include "content/public/browser/browser_context.h"
13 #include "content/public/browser/storage_partition.h"
14 #include "extensions/browser/event_router.h"
15 #include "webkit/browser/fileapi/file_system_context.h"
16
17 namespace extensions {
18 namespace {
19
20 // Default implementation for dispatching an event. Can be replaced for unit
21 // tests by EntryWatcherService::SetDispatchEventImplForTesting().
22 bool DispatchEventImpl(extensions::EventRouter* event_router,
23 const std::string& extension_id,
24 scoped_ptr<extensions::Event> event) {
25 if (!event_router->ExtensionHasEventListener(extension_id, event->event_name))
benwells 2014/08/13 05:50:47 Is it necessary to check this and return a bool?
mtomasz 2014/08/13 07:02:08 Right. Removed.
26 return false;
27
28 event_router->DispatchEventToExtension(extension_id, event.Pass());
29 return true;
30 }
31
32 // Default implementation for acquiring a file system context for a specific
33 // |extension_id| and |context|.
34 fileapi::FileSystemContext* GetFileSystemContextImpl(
35 const std::string& extension_id,
36 content::BrowserContext* context) {
37 const GURL site =
38 extensions::util::GetSiteForExtensionId(extension_id, context);
39 return content::BrowserContext::GetStoragePartitionForSite(context, site)
40 ->GetFileSystemContext();
41 }
42
43 } // namespace
44
45 EntryWatcherService::EntryWatcherService(content::BrowserContext* context)
46 : context_(context),
47 dispatch_event_impl_(base::Bind(&DispatchEventImpl,
48 extensions::EventRouter::Get(context))),
49 get_file_system_context_impl_(base::Bind(&GetFileSystemContextImpl)),
50 observing_(this),
51 weak_ptr_factory_(this) {
52 // TODO(mtomasz): Restore persistent watchers.
53 }
54
55 EntryWatcherService::~EntryWatcherService() {
56 }
57
58 void EntryWatcherService::SetDispatchEventImplForTesting(
59 const DispatchEventImplCallback& callback) {
60 dispatch_event_impl_ = callback;
61 }
62
63 void EntryWatcherService::SetGetFileSystemContextImplForTesting(
64 const GetFileSystemContextImplCallback& callback) {
65 get_file_system_context_impl_ = callback;
66 }
67
68 void EntryWatcherService::WatchDirectory(
69 const std::string& extension_id,
70 const fileapi::FileSystemURL& url,
71 bool recursive,
72 const fileapi::WatcherManager::StatusCallback& callback) {
73 // TODO(mtomasz): Add support for recursive watchers.
74 if (recursive) {
75 base::ThreadTaskRunnerHandle::Get()->PostTask(
76 FROM_HERE,
77 base::Bind(callback, base::File::FILE_ERROR_INVALID_OPERATION));
78 return;
79 }
80
81 fileapi::FileSystemContext* const context =
82 get_file_system_context_impl_.Run(extension_id, context_);
83 DCHECK(context);
84
85 fileapi::WatcherManager* const watcher_manager =
86 context->GetWatcherManager(url.type());
87 if (!watcher_manager) {
88 base::ThreadTaskRunnerHandle::Get()->PostTask(
benwells 2014/08/13 05:50:47 Why do you post this and not just run it immediate
mtomasz 2014/08/13 07:02:09 Several times during reviews I was asked to post c
benwells 2014/08/14 05:16:32 OK, makes sense. Could you add a comment explainin
mtomasz 2014/08/15 05:35:57 Done.
89 FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_SECURITY));
benwells 2014/08/13 05:50:47 Why is this a security error?
mtomasz 2014/08/13 07:02:09 Changed to base::File::FILE_ERROR_INVALID_OPERATIO
90 return;
91 }
92
93 watcher_manager->WatchDirectory(
94 url,
95 recursive,
96 base::Bind(&EntryWatcherService::OnWatchDirectoryCompleted,
97 weak_ptr_factory_.GetWeakPtr(),
98 extension_id,
99 url,
100 recursive,
101 callback));
102 }
103
104 void EntryWatcherService::UnwatchEntry(
105 const std::string& extension_id,
106 const fileapi::FileSystemURL& url,
107 const fileapi::WatcherManager::StatusCallback& callback) {
108 fileapi::FileSystemContext* const context =
109 get_file_system_context_impl_.Run(extension_id, context_);
110 DCHECK(context);
111
112 fileapi::WatcherManager* const watcher_manager =
113 context->GetWatcherManager(url.type());
114 if (!watcher_manager) {
115 base::ThreadTaskRunnerHandle::Get()->PostTask(
116 FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_SECURITY));
117 return;
118 }
119
120 watcher_manager->UnwatchEntry(
121 url,
122 base::Bind(&EntryWatcherService::OnUnwatchEntryCompleted,
123 weak_ptr_factory_.GetWeakPtr(),
124 extension_id,
125 url,
126 callback));
127 }
128
129 std::vector<fileapi::FileSystemURL> EntryWatcherService::GetWatchedEntries(
130 const std::string& extension_id) {
131 std::vector<fileapi::FileSystemURL> result;
132 for (WatcherMap::const_iterator it = watchers_.begin(); it != watchers_.end();
133 ++it) {
134 const std::map<std::string, EntryWatcher>::const_iterator watcher_it =
135 it->second.find(extension_id);
136 if (watcher_it != it->second.end())
137 result.push_back(watcher_it->second.url);
138 }
139
140 return result;
141 }
142
143 void EntryWatcherService::OnEntryChanged(const fileapi::FileSystemURL& url) {
144 const WatcherMap::const_iterator it = watchers_.find(url.ToGURL());
145 DCHECK(it != watchers_.end());
146 for (std::map<std::string, EntryWatcher>::const_iterator watcher_it =
147 it->second.begin();
148 watcher_it != it->second.end();
149 ++watcher_it) {
150 const std::string& extension_id = watcher_it->first;
151 api::file_system::EntryChangedEvent event;
152 dispatch_event_impl_.Run(
153 extension_id,
154 make_scoped_ptr(
155 new Event(api::file_system::OnEntryChanged::kEventName,
156 api::file_system::OnEntryChanged::Create(event))));
157 }
158 }
159
160 void EntryWatcherService::OnEntryRemoved(const fileapi::FileSystemURL& url) {
161 WatcherMap::const_iterator it = watchers_.find(url.ToGURL());
162 DCHECK(it != watchers_.end());
163 for (std::map<std::string, EntryWatcher>::const_iterator watcher_it =
164 it->second.begin();
165 watcher_it != it->second.end();
166 ++watcher_it) {
167 const std::string& extension_id = watcher_it->first;
168 api::file_system::EntryRemovedEvent event;
169 dispatch_event_impl_.Run(
170 extension_id,
171 make_scoped_ptr(
172 new Event(api::file_system::OnEntryRemoved::kEventName,
173 api::file_system::OnEntryRemoved::Create(event))));
174 }
175 }
176
177 void EntryWatcherService::OnWatchDirectoryCompleted(
178 const std::string& extension_id,
179 const fileapi::FileSystemURL& url,
180 bool recursive,
181 const fileapi::WatcherManager::StatusCallback& callback,
182 base::File::Error result) {
183 if (result != base::File::FILE_OK) {
184 callback.Run(result);
185 return;
186 }
187
188 DCHECK_EQ(base::File::FILE_OK, result);
benwells 2014/08/13 05:50:47 Is this DCHECK necessary?
mtomasz 2014/08/13 07:02:09 Removed.
189
190 fileapi::FileSystemContext* const context =
191 get_file_system_context_impl_.Run(extension_id, context_);
192 DCHECK(context);
193
194 fileapi::WatcherManager* const watcher_manager =
195 context->GetWatcherManager(url.type());
196 if (!watcher_manager) {
197 callback.Run(base::File::FILE_ERROR_SECURITY);
benwells 2014/08/13 05:50:47 Given that you should have already successfully go
mtomasz 2014/08/13 07:02:09 GetWatcherManager() may return NULL at any point.
benwells 2014/08/14 05:16:32 That seems odd, are you thinking about the cases w
mtomasz 2014/08/15 05:35:56 I don't think it's weird. I can imagine a backend
mtomasz 2014/08/15 05:35:57 I reorganized the code. How about now?
benwells 2014/08/18 22:58:32 I think that is better, but the lifetime issues ar
mtomasz 2014/08/19 06:50:36 Done.
198 return;
199 }
200
201 // Observe the manager if not observed yet.
202 if (!observing_.IsObserving(watcher_manager))
203 observing_.Add(watcher_manager);
204
205 const GURL gurl = url.ToGURL();
206 watchers_[gurl][extension_id] =
207 EntryWatcher(url, true /* directory */, recursive);
208
209 // TODO(mtomasz): Save in preferences.
210
211 callback.Run(base::File::FILE_OK);
212 }
213
214 void EntryWatcherService::OnUnwatchEntryCompleted(
215 const std::string& extension_id,
216 const fileapi::FileSystemURL& url,
217 const fileapi::WatcherManager::StatusCallback& callback,
218 base::File::Error result) {
219 if (result != base::File::FILE_OK) {
220 callback.Run(result);
221 return;
222 }
223
224 DCHECK_EQ(base::File::FILE_OK, result);
225
226 const GURL gurl = url.ToGURL();
227 if (watchers_[gurl].erase(extension_id) == 0) {
228 callback.Run(base::File::FILE_ERROR_NOT_FOUND);
229 return;
230 }
231
232 if (watchers_[gurl].empty())
233 watchers_.erase(gurl);
234
235 fileapi::FileSystemContext* const context =
236 get_file_system_context_impl_.Run(extension_id, context_);
237 DCHECK(context);
238
239 fileapi::WatcherManager* const watcher_manager =
benwells 2014/08/13 05:50:47 Why do you get the watcher manager here?
mtomasz 2014/08/13 07:02:09 Not needed. Removed.
240 context->GetWatcherManager(url.type());
241 if (!watcher_manager) {
242 callback.Run(base::File::FILE_ERROR_SECURITY);
243 return;
244 }
245
246 // TODO(mtomasz): Save in preferences.
247
248 callback.Run(base::File::FILE_OK);
249 }
250
251 EntryWatcherService::EntryWatcher::EntryWatcher()
252 : directory(false), recursive(false) {
253 }
254
255 EntryWatcherService::EntryWatcher::EntryWatcher(
256 const fileapi::FileSystemURL& url,
257 bool directory,
258 bool recursive)
259 : url(url), directory(directory), recursive(recursive) {
260 }
261
262 EntryWatcherService::EntryWatcher::~EntryWatcher() {
263 }
264
265 // static
266 EntryWatcherService* EntryWatcherServiceFactory::Get(
267 content::BrowserContext* context) {
268 return static_cast<EntryWatcherService*>(
269 GetInstance()->GetServiceForBrowserContext(context, true));
270 }
271
272 // static
273 EntryWatcherService* EntryWatcherServiceFactory::FindExisting(
274 content::BrowserContext* context) {
275 return static_cast<EntryWatcherService*>(
276 GetInstance()->GetServiceForBrowserContext(context, false));
277 }
278
279 EntryWatcherServiceFactory* EntryWatcherServiceFactory::GetInstance() {
280 return Singleton<EntryWatcherServiceFactory>::get();
281 }
282
283 EntryWatcherServiceFactory::EntryWatcherServiceFactory()
284 : BrowserContextKeyedServiceFactory(
285 "EntryWatcherService",
286 BrowserContextDependencyManager::GetInstance()) {
287 }
288
289 EntryWatcherServiceFactory::~EntryWatcherServiceFactory() {
290 }
291
292 KeyedService* EntryWatcherServiceFactory::BuildServiceInstanceFor(
293 content::BrowserContext* context) const {
294 return new EntryWatcherService(Profile::FromBrowserContext(context));
295 }
296
297 bool EntryWatcherServiceFactory::ServiceIsCreatedWithBrowserContext() const {
298 return true;
benwells 2014/08/13 05:50:47 Could you add a comment about why this is needed?
mtomasz 2014/08/13 07:02:09 Done.
299 }
300
301 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698