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