Chromium Code Reviews| 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 |