OLD | NEW |
---|---|
(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 | |
OLD | NEW |