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#ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_ENTRY_WATCHER_SERVICE_H_
6#define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_ENTRY_WATCHER_SERVICE_H_
7
8#include <map>
9#include <string>
10#include <vector>
11
12#include "base/memory/singleton.h"
13#include "base/memory/weak_ptr.h"
14#include "base/scoped_observer.h"
15#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
16#include "components/keyed_service/core/keyed_service.h"
17#include "storage/browser/fileapi/file_system_url.h"
18#include "storage/browser/fileapi/watcher_manager.h"
19
20namespace content {
21class BrowserContext;
22}  // namespace content
23
24namespace storage {
25class FileSystemContext;
26}  // namespace storage
27
28namespace extensions {
29struct Event;
30class EventRouter;
31
32// Watches entries (files and directories) for changes. Created per profile.
33// TODO(mtomasz): Add support for watching files.
34class EntryWatcherService : public KeyedService,
35                            public storage::WatcherManager::Observer {
36 public:
37  typedef base::Callback<
38      void(const std::string& extension_id, scoped_ptr<Event> event)>
39      DispatchEventImplCallback;
40
41  typedef base::Callback<storage::FileSystemContext*(
42      const std::string& extension_id,
43      content::BrowserContext* context)> GetFileSystemContextImplCallback;
44
45  explicit EntryWatcherService(content::BrowserContext* context);
46  virtual ~EntryWatcherService();
47
48  // Watches a directory. Only one watcher can be set per the same |url| and
49  // |extension_id|.
50  void WatchDirectory(const std::string& extension_id,
51                      const storage::FileSystemURL& url,
52                      bool recursive,
53                      const storage::WatcherManager::StatusCallback& callback);
54
55  // Unwatches an entry (file or directory).
56  void UnwatchEntry(const std::string& extension_id,
57                    const storage::FileSystemURL& url,
58                    const storage::WatcherManager::StatusCallback& callback);
59
60  std::vector<storage::FileSystemURL> GetWatchedEntries(
61      const std::string& extension_id);
62
63  // storage::WatcherManager::Observer overrides.
64  virtual void OnEntryChanged(const storage::FileSystemURL& url) OVERRIDE;
65  virtual void OnEntryRemoved(const storage::FileSystemURL& url) OVERRIDE;
66
67  // Sets a custom dispatcher for tests in order to be able to verify dispatched
68  // events.
69  void SetDispatchEventImplForTesting(
70      const DispatchEventImplCallback& callback);
71
72  // Sets a custom context getter for tests in order to inject a testing
73  // file system context implementation.
74  void SetGetFileSystemContextImplForTesting(
75      const GetFileSystemContextImplCallback& callback);
76
77 private:
78  // Holds information about an active entry watcher.
79  struct EntryWatcher {
80    EntryWatcher();
81    EntryWatcher(const storage::FileSystemURL& url,
82                 bool directory,
83                 bool recursive);
84    ~EntryWatcher();
85
86    storage::FileSystemURL url;
87    bool directory;
88    bool recursive;
89  };
90
91  // Map from a file system url to a map from an extension id to an entry
92  // watcher descriptor.
93  typedef std::map<storage::FileSystemURL,
94                   std::map<std::string, EntryWatcher>,
95                   storage::FileSystemURL::Comparator> WatcherMap;
96
97  // Called when adding a directory watcher is completed with either a success
98  // or an error.
99  void OnWatchDirectoryCompleted(
100      storage::WatcherManager* watcher_manager,
101      const std::string& extension_id,
102      const storage::FileSystemURL& url,
103      bool recursive,
104      const storage::WatcherManager::StatusCallback& callback,
105      base::File::Error result);
106
107  // Called when removing a watcher is completed with either a success or an
108  // error.
109  void OnUnwatchEntryCompleted(
110      const std::string& extension_id,
111      const storage::FileSystemURL& url,
112      const storage::WatcherManager::StatusCallback& callback,
113      base::File::Error result);
114
115  content::BrowserContext* context_;
116  WatcherMap watchers_;
117  DispatchEventImplCallback dispatch_event_impl_;
118  GetFileSystemContextImplCallback get_file_system_context_impl_;
119  ScopedObserver<storage::WatcherManager, storage::WatcherManager::Observer>
120      observing_;
121  base::WeakPtrFactory<EntryWatcherService> weak_ptr_factory_;
122
123  DISALLOW_COPY_AND_ASSIGN(EntryWatcherService);
124};
125
126}  // namespace extensions
127
128#endif  // CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_ENTRY_WATCHER_SERVICE_H_
129