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 "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 { | |
18 | |
19 // Default implementation for dispatching an event. Can be replaced for unit | |
20 // tests by EntryWatcherService::SetDispatchEventImplForTesting(). | |
21 void DispatchEventImpl(extensions::EventRouter* event_router, | |
22 const std::string& extension_id, | |
23 scoped_ptr<extensions::Event> event) { | |
24 event_router->DispatchEventToExtension(extension_id, event.Pass()); | |
25 } | |
26 | |
27 // Default implementation for acquiring a file system context for a specific | |
28 // |extension_id| and |context|. | |
29 fileapi::FileSystemContext* GetFileSystemContextImpl( | |
30 const std::string& extension_id, | |
31 content::BrowserContext* context) { | |
32 const GURL site = | |
33 extensions::util::GetSiteForExtensionId(extension_id, context); | |
34 return content::BrowserContext::GetStoragePartitionForSite(context, site) | |
35 ->GetFileSystemContext(); | |
36 } | |
37 | |
38 } // namespace | |
39 | |
40 EntryWatcherService::EntryWatcherService(content::BrowserContext* context) | |
41 : context_(context), | |
42 dispatch_event_impl_(base::Bind(&DispatchEventImpl, | |
43 extensions::EventRouter::Get(context))), | |
44 get_file_system_context_impl_(base::Bind(&GetFileSystemContextImpl)), | |
45 observing_(this), | |
46 weak_ptr_factory_(this) { | |
47 // TODO(mtomasz): Restore persistent watchers. | |
48 } | |
49 | |
50 EntryWatcherService::~EntryWatcherService() { | |
51 } | |
52 | |
53 void EntryWatcherService::SetDispatchEventImplForTesting( | |
54 const DispatchEventImplCallback& callback) { | |
55 dispatch_event_impl_ = callback; | |
56 } | |
57 | |
58 void EntryWatcherService::SetGetFileSystemContextImplForTesting( | |
59 const GetFileSystemContextImplCallback& callback) { | |
60 get_file_system_context_impl_ = callback; | |
61 } | |
62 | |
63 void EntryWatcherService::WatchDirectory( | |
64 const std::string& extension_id, | |
65 const fileapi::FileSystemURL& url, | |
66 bool recursive, | |
67 const fileapi::WatcherManager::StatusCallback& callback) { | |
68 // TODO(mtomasz): Add support for recursive watchers. | |
69 if (recursive) { | |
70 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
71 FROM_HERE, | |
72 base::Bind(callback, base::File::FILE_ERROR_INVALID_OPERATION)); | |
73 return; | |
74 } | |
75 | |
76 fileapi::FileSystemContext* const context = | |
77 get_file_system_context_impl_.Run(extension_id, context_); | |
78 DCHECK(context); | |
79 | |
80 fileapi::WatcherManager* const watcher_manager = | |
81 context->GetWatcherManager(url.type()); | |
82 if (!watcher_manager) { | |
83 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
84 FROM_HERE, | |
85 base::Bind(callback, base::File::FILE_ERROR_INVALID_OPERATION)); | |
86 return; | |
87 } | |
88 | |
89 watcher_manager->WatchDirectory( | |
90 url, | |
91 recursive, | |
92 base::Bind(&EntryWatcherService::OnWatchDirectoryCompleted, | |
93 weak_ptr_factory_.GetWeakPtr(), | |
94 extension_id, | |
95 url, | |
96 recursive, | |
97 callback)); | |
98 } | |
99 | |
100 void EntryWatcherService::UnwatchEntry( | |
101 const std::string& extension_id, | |
102 const fileapi::FileSystemURL& url, | |
103 const fileapi::WatcherManager::StatusCallback& callback) { | |
104 fileapi::FileSystemContext* const context = | |
105 get_file_system_context_impl_.Run(extension_id, context_); | |
106 DCHECK(context); | |
107 | |
108 fileapi::WatcherManager* const watcher_manager = | |
109 context->GetWatcherManager(url.type()); | |
110 if (!watcher_manager) { | |
111 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
112 FROM_HERE, | |
113 base::Bind(callback, base::File::FILE_ERROR_INVALID_OPERATION)); | |
114 return; | |
115 } | |
116 | |
117 watcher_manager->UnwatchEntry( | |
118 url, | |
119 base::Bind(&EntryWatcherService::OnUnwatchEntryCompleted, | |
120 weak_ptr_factory_.GetWeakPtr(), | |
121 extension_id, | |
122 url, | |
123 callback)); | |
124 } | |
125 | |
126 std::vector<fileapi::FileSystemURL> EntryWatcherService::GetWatchedEntries( | |
127 const std::string& extension_id) { | |
128 std::vector<fileapi::FileSystemURL> result; | |
129 for (WatcherMap::const_iterator it = watchers_.begin(); it != watchers_.end(); | |
130 ++it) { | |
131 const std::map<std::string, EntryWatcher>::const_iterator watcher_it = | |
132 it->second.find(extension_id); | |
133 if (watcher_it != it->second.end()) | |
134 result.push_back(watcher_it->second.url); | |
135 } | |
136 | |
137 return result; | |
138 } | |
139 | |
140 void EntryWatcherService::OnEntryChanged(const fileapi::FileSystemURL& url) { | |
141 const WatcherMap::const_iterator it = watchers_.find(url.ToGURL()); | |
142 DCHECK(it != watchers_.end()); | |
143 for (std::map<std::string, EntryWatcher>::const_iterator watcher_it = | |
144 it->second.begin(); | |
145 watcher_it != it->second.end(); | |
146 ++watcher_it) { | |
147 const std::string& extension_id = watcher_it->first; | |
148 extensions::api::file_system::EntryChangedEvent event; | |
149 dispatch_event_impl_.Run( | |
150 extension_id, | |
151 make_scoped_ptr(new extensions::Event( | |
152 extensions::api::file_system::OnEntryChanged::kEventName, | |
153 extensions::api::file_system::OnEntryChanged::Create(event)))); | |
154 } | |
155 } | |
156 | |
157 void EntryWatcherService::OnEntryRemoved(const fileapi::FileSystemURL& url) { | |
158 WatcherMap::const_iterator it = watchers_.find(url.ToGURL()); | |
159 DCHECK(it != watchers_.end()); | |
160 for (std::map<std::string, EntryWatcher>::const_iterator watcher_it = | |
161 it->second.begin(); | |
162 watcher_it != it->second.end(); | |
163 ++watcher_it) { | |
164 const std::string& extension_id = watcher_it->first; | |
165 extensions::api::file_system::EntryRemovedEvent event; | |
166 dispatch_event_impl_.Run( | |
167 extension_id, | |
168 make_scoped_ptr(new extensions::Event( | |
169 extensions::api::file_system::OnEntryRemoved::kEventName, | |
170 extensions::api::file_system::OnEntryRemoved::Create(event)))); | |
171 } | |
172 } | |
173 | |
174 void EntryWatcherService::OnWatchDirectoryCompleted( | |
175 const std::string& extension_id, | |
176 const fileapi::FileSystemURL& url, | |
177 bool recursive, | |
178 const fileapi::WatcherManager::StatusCallback& callback, | |
179 base::File::Error result) { | |
180 if (result != base::File::FILE_OK) { | |
181 callback.Run(result); | |
182 return; | |
183 } | |
184 | |
185 fileapi::FileSystemContext* const context = | |
186 get_file_system_context_impl_.Run(extension_id, context_); | |
187 DCHECK(context); | |
188 | |
189 fileapi::WatcherManager* const watcher_manager = | |
190 context->GetWatcherManager(url.type()); | |
191 if (!watcher_manager) { | |
192 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); | |
193 return; | |
194 } | |
195 | |
196 // Observe the manager if not observed yet. | |
197 if (!observing_.IsObserving(watcher_manager)) | |
198 observing_.Add(watcher_manager); | |
199 | |
200 const GURL gurl = url.ToGURL(); | |
201 watchers_[gurl][extension_id] = | |
202 EntryWatcher(url, true /* directory */, recursive); | |
203 | |
204 // TODO(mtomasz): Save in preferences. | |
205 | |
206 callback.Run(base::File::FILE_OK); | |
207 } | |
208 | |
209 void EntryWatcherService::OnUnwatchEntryCompleted( | |
210 const std::string& extension_id, | |
211 const fileapi::FileSystemURL& url, | |
212 const fileapi::WatcherManager::StatusCallback& callback, | |
213 base::File::Error result) { | |
214 if (result != base::File::FILE_OK) { | |
215 callback.Run(result); | |
216 return; | |
217 } | |
218 | |
219 DCHECK_EQ(base::File::FILE_OK, result); | |
benwells
2014/08/14 05:16:32
This DCHECK can be removed as well.
mtomasz
2014/08/15 05:35:57
Done.
| |
220 | |
221 const GURL gurl = url.ToGURL(); | |
222 if (watchers_[gurl].erase(extension_id) == 0) { | |
223 callback.Run(base::File::FILE_ERROR_NOT_FOUND); | |
224 return; | |
225 } | |
226 | |
227 if (watchers_[gurl].empty()) | |
228 watchers_.erase(gurl); | |
229 | |
230 // TODO(mtomasz): Save in preferences. | |
231 | |
232 callback.Run(base::File::FILE_OK); | |
233 } | |
234 | |
235 EntryWatcherService::EntryWatcher::EntryWatcher() | |
236 : directory(false), recursive(false) { | |
237 } | |
238 | |
239 EntryWatcherService::EntryWatcher::EntryWatcher( | |
240 const fileapi::FileSystemURL& url, | |
241 bool directory, | |
242 bool recursive) | |
243 : url(url), directory(directory), recursive(recursive) { | |
244 } | |
245 | |
246 EntryWatcherService::EntryWatcher::~EntryWatcher() { | |
247 } | |
OLD | NEW |