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 "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 |