Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(243)

Unified Diff: chrome/browser/file_system/entry_watcher_service.cc

Issue 452043003: [ew] Add basic classes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added more tests + comments. Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/file_system/entry_watcher_service.cc
diff --git a/chrome/browser/file_system/entry_watcher_service.cc b/chrome/browser/file_system/entry_watcher_service.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f6cbb5f1ac1e91adf81306cd26d48239a5e5dece
--- /dev/null
+++ b/chrome/browser/file_system/entry_watcher_service.cc
@@ -0,0 +1,299 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/file_system/entry_watcher_service.h"
+
+#include "chrome/browser/extensions/extension_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/api/file_system.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "extensions/browser/event_router.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+
+namespace extensions {
+namespace {
+
+// Default implementation for dispatching an event. Can be replaced for unit
+// tests by EntryWatcherService::SetDispatchEventImplForTesting().
+bool DispatchEventImpl(extensions::EventRouter* event_router,
+ const std::string& extension_id,
+ scoped_ptr<extensions::Event> event) {
+ if (!event_router->ExtensionHasEventListener(extension_id, event->event_name))
+ return false;
+
+ event_router->DispatchEventToExtension(extension_id, event.Pass());
+ return true;
+}
+
+// Default implementation for acquiring a file system context for a specific
+// |extension_id| and |profile|.
+fileapi::FileSystemContext* GetContextImpl(const std::string& extension_id,
+ Profile* profile) {
+ const GURL site =
+ extensions::util::GetSiteForExtensionId(extension_id, profile);
+ return content::BrowserContext::GetStoragePartitionForSite(profile, site)
+ ->GetFileSystemContext();
+}
+
+} // namespace
+
+EntryWatcherService::EntryWatcherService(Profile* profile)
+ : profile_(profile),
+ dispatch_event_impl_(base::Bind(&DispatchEventImpl,
+ extensions::EventRouter::Get(profile))),
+ get_context_impl_(base::Bind(&GetContextImpl)),
+ observing_(this),
+ weak_ptr_factory_(this) {
+ // TODO(mtomasz): Restore persistent watchers.
+}
+
+EntryWatcherService::~EntryWatcherService() {
+}
+
+void EntryWatcherService::SetDispatchEventImplForTesting(
+ const DispatchEventImplCallback& callback) {
+ dispatch_event_impl_ = callback;
+}
+
+void EntryWatcherService::SetGetContextImplForTesting(
+ const GetContextImplCallback& callback) {
+ get_context_impl_ = callback;
+}
+
+void EntryWatcherService::WatchDirectory(
+ const std::string& extension_id,
+ const fileapi::FileSystemURL& url,
+ bool recursive,
+ const fileapi::WatcherManager::StatusCallback& callback) {
+ // TODO(mtomasz): Add support for recursive watchers.
+ if (recursive) {
+ base::MessageLoopProxy::current()->PostTask(
tzik 2014/08/12 10:40:46 MessageLoopProxy seems deprecated ThreadTaskRunner
mtomasz 2014/08/13 03:08:44 Done.
+ FROM_HERE,
+ base::Bind(callback, base::File::FILE_ERROR_INVALID_OPERATION));
+ return;
+ }
+
+ fileapi::FileSystemContext* const context =
+ get_context_impl_.Run(extension_id, profile_);
+ DCHECK(context);
+
+ fileapi::WatcherManager* const watcher_manager =
+ context->GetWatcherManager(url.type());
+ if (!watcher_manager) {
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_SECURITY));
+ return;
+ }
+
+ watcher_manager->WatchDirectory(
+ url,
+ recursive,
+ base::Bind(&EntryWatcherService::OnWatchDirectoryCompleted,
+ weak_ptr_factory_.GetWeakPtr(),
+ extension_id,
+ url,
+ recursive,
+ callback));
+}
+
+void EntryWatcherService::UnwatchEntry(
+ const std::string& extension_id,
+ const fileapi::FileSystemURL& url,
+ const fileapi::WatcherManager::StatusCallback& callback) {
+ fileapi::FileSystemContext* const context =
+ get_context_impl_.Run(extension_id, profile_);
+ DCHECK(context);
+
+ fileapi::WatcherManager* const watcher_manager =
+ context->GetWatcherManager(url.type());
+ if (!watcher_manager) {
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_SECURITY));
+ return;
+ }
+
+ watcher_manager->UnwatchEntry(
+ url,
+ base::Bind(&EntryWatcherService::OnUnwatchEntryCompleted,
+ weak_ptr_factory_.GetWeakPtr(),
+ extension_id,
+ url,
+ callback));
+}
+
+std::vector<fileapi::FileSystemURL> EntryWatcherService::GetWatchedEntries(
+ const std::string& extension_id) {
+ std::vector<fileapi::FileSystemURL> result;
+ for (WatcherMap::const_iterator it = watchers_.begin(); it != watchers_.end();
+ ++it) {
+ const std::map<std::string, EntryWatcher>::const_iterator watcher_it =
+ it->second.find(extension_id);
+ if (watcher_it != it->second.end())
+ result.push_back(watcher_it->second.url);
+ }
+
+ return result;
+}
+
+void EntryWatcherService::OnEntryChanged(const fileapi::FileSystemURL& url) {
+ const WatcherMap::const_iterator it = watchers_.find(url.ToGURL());
+ DCHECK(it != watchers_.end());
+ for (std::map<std::string, EntryWatcher>::const_iterator watcher_it =
+ it->second.begin();
+ watcher_it != it->second.end();
+ ++watcher_it) {
+ const std::string& extension_id = watcher_it->first;
+ api::file_system::EntryChangedEvent event;
+ dispatch_event_impl_.Run(
+ extension_id,
+ make_scoped_ptr(
+ new Event(api::file_system::OnEntryChanged::kEventName,
+ api::file_system::OnEntryChanged::Create(event))));
+ }
+}
+
+void EntryWatcherService::OnEntryRemoved(const fileapi::FileSystemURL& url) {
+ WatcherMap::const_iterator it = watchers_.find(url.ToGURL());
+ DCHECK(it != watchers_.end());
+ for (std::map<std::string, EntryWatcher>::const_iterator watcher_it =
+ it->second.begin();
+ watcher_it != it->second.end();
+ ++watcher_it) {
+ const std::string& extension_id = watcher_it->first;
+ api::file_system::EntryRemovedEvent event;
+ dispatch_event_impl_.Run(
+ extension_id,
+ make_scoped_ptr(
+ new Event(api::file_system::OnEntryRemoved::kEventName,
+ api::file_system::OnEntryRemoved::Create(event))));
+ }
+}
+
+void EntryWatcherService::OnWatchDirectoryCompleted(
+ const std::string& extension_id,
+ const fileapi::FileSystemURL& url,
+ bool recursive,
+ const fileapi::WatcherManager::StatusCallback& callback,
+ base::File::Error result) {
+ if (result != base::File::FILE_OK) {
+ callback.Run(result);
+ return;
+ }
+
+ DCHECK_EQ(base::File::FILE_OK, result);
+
+ fileapi::FileSystemContext* const context =
+ get_context_impl_.Run(extension_id, profile_);
+ DCHECK(context);
+
+ fileapi::WatcherManager* const watcher_manager =
+ context->GetWatcherManager(url.type());
+ if (!watcher_manager) {
+ callback.Run(base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+
+ // Observe the manager if not observed yet.
+ if (!observing_.IsObserving(watcher_manager))
+ observing_.Add(watcher_manager);
+
+ const GURL gurl = url.ToGURL();
+ watchers_[gurl][extension_id] =
+ EntryWatcher(url, true /* directory */, recursive);
+
+ // TODO(mtomasz): Save in preferences.
+
+ callback.Run(base::File::FILE_OK);
+}
+
+void EntryWatcherService::OnUnwatchEntryCompleted(
+ const std::string& extension_id,
+ const fileapi::FileSystemURL& url,
+ const fileapi::WatcherManager::StatusCallback& callback,
+ base::File::Error result) {
+ if (result != base::File::FILE_OK) {
+ callback.Run(result);
+ return;
+ }
+
+ DCHECK_EQ(base::File::FILE_OK, result);
+
+ const GURL gurl = url.ToGURL();
+ if (watchers_[gurl].erase(extension_id) == 0) {
+ callback.Run(base::File::FILE_ERROR_NOT_FOUND);
+ return;
+ }
+
+ if (!watchers_[gurl].size())
tzik 2014/08/12 10:40:46 .empty() is more readable.
mtomasz 2014/08/13 03:08:44 Done.
+ watchers_.erase(gurl);
+
+ fileapi::FileSystemContext* const context =
+ get_context_impl_.Run(extension_id, profile_);
+ DCHECK(context);
+
+ fileapi::WatcherManager* const watcher_manager =
+ context->GetWatcherManager(url.type());
+ if (!watcher_manager) {
+ callback.Run(base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+
+ // TODO(mtomasz): Save in preferences.
+
+ callback.Run(base::File::FILE_OK);
+}
+
+EntryWatcherService::EntryWatcher::EntryWatcher()
+ : directory(false), recursive(false) {
+}
+
+EntryWatcherService::EntryWatcher::EntryWatcher(
+ const fileapi::FileSystemURL& url,
+ bool directory,
+ bool recursive)
+ : url(url), directory(directory), recursive(recursive) {
+}
+
+EntryWatcherService::EntryWatcher::~EntryWatcher() {
+}
+
+// static
+EntryWatcherService* EntryWatcherServiceFactory::Get(
+ content::BrowserContext* context) {
+ return static_cast<EntryWatcherService*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+// static
+EntryWatcherService* EntryWatcherServiceFactory::FindExisting(
+ content::BrowserContext* context) {
+ return static_cast<EntryWatcherService*>(
+ GetInstance()->GetServiceForBrowserContext(context, false));
+}
+
+EntryWatcherServiceFactory* EntryWatcherServiceFactory::GetInstance() {
+ return Singleton<EntryWatcherServiceFactory>::get();
+}
+
+EntryWatcherServiceFactory::EntryWatcherServiceFactory()
+ : BrowserContextKeyedServiceFactory(
+ "EntryWatcherService",
+ BrowserContextDependencyManager::GetInstance()) {
+}
+
+EntryWatcherServiceFactory::~EntryWatcherServiceFactory() {
+}
+
+KeyedService* EntryWatcherServiceFactory::BuildServiceInstanceFor(
+ content::BrowserContext* profile) const {
+ return new EntryWatcherService(Profile::FromBrowserContext(profile));
+}
+
+bool EntryWatcherServiceFactory::ServiceIsCreatedWithBrowserContext() const {
+ return true;
+}
+
+} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698