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

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: Added more tests + 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 "chrome/browser/extensions/extension_util.h"
8 #include "chrome/browser/profiles/profile.h"
9 #include "chrome/common/extensions/api/file_system.h"
10 #include "components/keyed_service/content/browser_context_dependency_manager.h"
11 #include "content/public/browser/browser_context.h"
12 #include "content/public/browser/storage_partition.h"
13 #include "extensions/browser/event_router.h"
14 #include "webkit/browser/fileapi/file_system_context.h"
15
16 namespace extensions {
17 namespace {
18
19 // Default implementation for dispatching an event. Can be replaced for unit
20 // tests by EntryWatcherService::SetDispatchEventImplForTesting().
21 bool DispatchEventImpl(extensions::EventRouter* event_router,
22 const std::string& extension_id,
23 scoped_ptr<extensions::Event> event) {
24 if (!event_router->ExtensionHasEventListener(extension_id, event->event_name))
25 return false;
26
27 event_router->DispatchEventToExtension(extension_id, event.Pass());
28 return true;
29 }
30
31 // Default implementation for acquiring a file system context for a specific
32 // |extension_id| and |profile|.
33 fileapi::FileSystemContext* GetContextImpl(const std::string& extension_id,
34 Profile* profile) {
35 const GURL site =
36 extensions::util::GetSiteForExtensionId(extension_id, profile);
37 return content::BrowserContext::GetStoragePartitionForSite(profile, site)
38 ->GetFileSystemContext();
39 }
40
41 } // namespace
42
43 EntryWatcherService::EntryWatcherService(Profile* profile)
44 : profile_(profile),
45 dispatch_event_impl_(base::Bind(&DispatchEventImpl,
46 extensions::EventRouter::Get(profile))),
47 get_context_impl_(base::Bind(&GetContextImpl)),
48 observing_(this),
49 weak_ptr_factory_(this) {
50 // TODO(mtomasz): Restore persistent watchers.
51 }
52
53 EntryWatcherService::~EntryWatcherService() {
54 }
55
56 void EntryWatcherService::SetDispatchEventImplForTesting(
57 const DispatchEventImplCallback& callback) {
58 dispatch_event_impl_ = callback;
59 }
60
61 void EntryWatcherService::SetGetContextImplForTesting(
62 const GetContextImplCallback& callback) {
63 get_context_impl_ = callback;
64 }
65
66 void EntryWatcherService::WatchDirectory(
67 const std::string& extension_id,
68 const fileapi::FileSystemURL& url,
69 bool recursive,
70 const fileapi::WatcherManager::StatusCallback& callback) {
71 // TODO(mtomasz): Add support for recursive watchers.
72 if (recursive) {
73 base::MessageLoopProxy::current()->PostTask(
tzik 2014/08/12 10:40:46 MessageLoopProxy seems deprecated ThreadTaskRunner
mtomasz 2014/08/13 03:08:44 Done.
74 FROM_HERE,
75 base::Bind(callback, base::File::FILE_ERROR_INVALID_OPERATION));
76 return;
77 }
78
79 fileapi::FileSystemContext* const context =
80 get_context_impl_.Run(extension_id, profile_);
81 DCHECK(context);
82
83 fileapi::WatcherManager* const watcher_manager =
84 context->GetWatcherManager(url.type());
85 if (!watcher_manager) {
86 base::MessageLoopProxy::current()->PostTask(
87 FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_SECURITY));
88 return;
89 }
90
91 watcher_manager->WatchDirectory(
92 url,
93 recursive,
94 base::Bind(&EntryWatcherService::OnWatchDirectoryCompleted,
95 weak_ptr_factory_.GetWeakPtr(),
96 extension_id,
97 url,
98 recursive,
99 callback));
100 }
101
102 void EntryWatcherService::UnwatchEntry(
103 const std::string& extension_id,
104 const fileapi::FileSystemURL& url,
105 const fileapi::WatcherManager::StatusCallback& callback) {
106 fileapi::FileSystemContext* const context =
107 get_context_impl_.Run(extension_id, profile_);
108 DCHECK(context);
109
110 fileapi::WatcherManager* const watcher_manager =
111 context->GetWatcherManager(url.type());
112 if (!watcher_manager) {
113 base::MessageLoopProxy::current()->PostTask(
114 FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_SECURITY));
115 return;
116 }
117
118 watcher_manager->UnwatchEntry(
119 url,
120 base::Bind(&EntryWatcherService::OnUnwatchEntryCompleted,
121 weak_ptr_factory_.GetWeakPtr(),
122 extension_id,
123 url,
124 callback));
125 }
126
127 std::vector<fileapi::FileSystemURL> EntryWatcherService::GetWatchedEntries(
128 const std::string& extension_id) {
129 std::vector<fileapi::FileSystemURL> result;
130 for (WatcherMap::const_iterator it = watchers_.begin(); it != watchers_.end();
131 ++it) {
132 const std::map<std::string, EntryWatcher>::const_iterator watcher_it =
133 it->second.find(extension_id);
134 if (watcher_it != it->second.end())
135 result.push_back(watcher_it->second.url);
136 }
137
138 return result;
139 }
140
141 void EntryWatcherService::OnEntryChanged(const fileapi::FileSystemURL& url) {
142 const WatcherMap::const_iterator it = watchers_.find(url.ToGURL());
143 DCHECK(it != watchers_.end());
144 for (std::map<std::string, EntryWatcher>::const_iterator watcher_it =
145 it->second.begin();
146 watcher_it != it->second.end();
147 ++watcher_it) {
148 const std::string& extension_id = watcher_it->first;
149 api::file_system::EntryChangedEvent event;
150 dispatch_event_impl_.Run(
151 extension_id,
152 make_scoped_ptr(
153 new Event(api::file_system::OnEntryChanged::kEventName,
154 api::file_system::OnEntryChanged::Create(event))));
155 }
156 }
157
158 void EntryWatcherService::OnEntryRemoved(const fileapi::FileSystemURL& url) {
159 WatcherMap::const_iterator it = watchers_.find(url.ToGURL());
160 DCHECK(it != watchers_.end());
161 for (std::map<std::string, EntryWatcher>::const_iterator watcher_it =
162 it->second.begin();
163 watcher_it != it->second.end();
164 ++watcher_it) {
165 const std::string& extension_id = watcher_it->first;
166 api::file_system::EntryRemovedEvent event;
167 dispatch_event_impl_.Run(
168 extension_id,
169 make_scoped_ptr(
170 new Event(api::file_system::OnEntryRemoved::kEventName,
171 api::file_system::OnEntryRemoved::Create(event))));
172 }
173 }
174
175 void EntryWatcherService::OnWatchDirectoryCompleted(
176 const std::string& extension_id,
177 const fileapi::FileSystemURL& url,
178 bool recursive,
179 const fileapi::WatcherManager::StatusCallback& callback,
180 base::File::Error result) {
181 if (result != base::File::FILE_OK) {
182 callback.Run(result);
183 return;
184 }
185
186 DCHECK_EQ(base::File::FILE_OK, result);
187
188 fileapi::FileSystemContext* const context =
189 get_context_impl_.Run(extension_id, profile_);
190 DCHECK(context);
191
192 fileapi::WatcherManager* const watcher_manager =
193 context->GetWatcherManager(url.type());
194 if (!watcher_manager) {
195 callback.Run(base::File::FILE_ERROR_SECURITY);
196 return;
197 }
198
199 // Observe the manager if not observed yet.
200 if (!observing_.IsObserving(watcher_manager))
201 observing_.Add(watcher_manager);
202
203 const GURL gurl = url.ToGURL();
204 watchers_[gurl][extension_id] =
205 EntryWatcher(url, true /* directory */, recursive);
206
207 // TODO(mtomasz): Save in preferences.
208
209 callback.Run(base::File::FILE_OK);
210 }
211
212 void EntryWatcherService::OnUnwatchEntryCompleted(
213 const std::string& extension_id,
214 const fileapi::FileSystemURL& url,
215 const fileapi::WatcherManager::StatusCallback& callback,
216 base::File::Error result) {
217 if (result != base::File::FILE_OK) {
218 callback.Run(result);
219 return;
220 }
221
222 DCHECK_EQ(base::File::FILE_OK, result);
223
224 const GURL gurl = url.ToGURL();
225 if (watchers_[gurl].erase(extension_id) == 0) {
226 callback.Run(base::File::FILE_ERROR_NOT_FOUND);
227 return;
228 }
229
230 if (!watchers_[gurl].size())
tzik 2014/08/12 10:40:46 .empty() is more readable.
mtomasz 2014/08/13 03:08:44 Done.
231 watchers_.erase(gurl);
232
233 fileapi::FileSystemContext* const context =
234 get_context_impl_.Run(extension_id, profile_);
235 DCHECK(context);
236
237 fileapi::WatcherManager* const watcher_manager =
238 context->GetWatcherManager(url.type());
239 if (!watcher_manager) {
240 callback.Run(base::File::FILE_ERROR_SECURITY);
241 return;
242 }
243
244 // TODO(mtomasz): Save in preferences.
245
246 callback.Run(base::File::FILE_OK);
247 }
248
249 EntryWatcherService::EntryWatcher::EntryWatcher()
250 : directory(false), recursive(false) {
251 }
252
253 EntryWatcherService::EntryWatcher::EntryWatcher(
254 const fileapi::FileSystemURL& url,
255 bool directory,
256 bool recursive)
257 : url(url), directory(directory), recursive(recursive) {
258 }
259
260 EntryWatcherService::EntryWatcher::~EntryWatcher() {
261 }
262
263 // static
264 EntryWatcherService* EntryWatcherServiceFactory::Get(
265 content::BrowserContext* context) {
266 return static_cast<EntryWatcherService*>(
267 GetInstance()->GetServiceForBrowserContext(context, true));
268 }
269
270 // static
271 EntryWatcherService* EntryWatcherServiceFactory::FindExisting(
272 content::BrowserContext* context) {
273 return static_cast<EntryWatcherService*>(
274 GetInstance()->GetServiceForBrowserContext(context, false));
275 }
276
277 EntryWatcherServiceFactory* EntryWatcherServiceFactory::GetInstance() {
278 return Singleton<EntryWatcherServiceFactory>::get();
279 }
280
281 EntryWatcherServiceFactory::EntryWatcherServiceFactory()
282 : BrowserContextKeyedServiceFactory(
283 "EntryWatcherService",
284 BrowserContextDependencyManager::GetInstance()) {
285 }
286
287 EntryWatcherServiceFactory::~EntryWatcherServiceFactory() {
288 }
289
290 KeyedService* EntryWatcherServiceFactory::BuildServiceInstanceFor(
291 content::BrowserContext* profile) const {
292 return new EntryWatcherService(Profile::FromBrowserContext(profile));
293 }
294
295 bool EntryWatcherServiceFactory::ServiceIsCreatedWithBrowserContext() const {
296 return true;
297 }
298
299 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698