Add ENABLE_MEDIA_ROUTER define to builds other than Android and iOS.
[chromium-blink-merge.git] / chrome / browser / chromeos / drive / file_write_watcher.cc
blob48d750095e30e085f06776e4db3482989589cb99
1 // Copyright 2013 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.
5 #include "chrome/browser/chromeos/drive/file_write_watcher.h"
7 #include <map>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/files/file_path_watcher.h"
13 #include "base/stl_util.h"
14 #include "base/timer/timer.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "google_apis/drive/task_util.h"
18 using content::BrowserThread;
20 namespace drive {
21 namespace internal {
23 namespace {
24 const int64 kWriteEventDelayInSeconds = 5;
25 } // namespace
27 // base::FileWatcher needs to live in a thread that is allowed to do File IO
28 // and has a TYPE_IO message loop: that is, FILE thread. This class bridges the
29 // UI thread and FILE thread, and does all the main tasks in the FILE thread.
30 class FileWriteWatcher::FileWriteWatcherImpl {
31 public:
32 FileWriteWatcherImpl();
34 // Forwards the call to DestoryOnFileThread(). This method must be used to
35 // destruct the instance.
36 void Destroy();
38 // Forwards the call to StartWatchOnFileThread(). |on_start_callback| is
39 // called back on the caller (UI) thread when the watch has started.
40 // |on_write_callback| is called when a write has happened to the path.
41 void StartWatch(const base::FilePath& path,
42 const StartWatchCallback& on_start_callback,
43 const base::Closure& on_write_callback);
45 void set_delay(base::TimeDelta delay) { delay_ = delay; }
47 private:
48 ~FileWriteWatcherImpl();
50 void DestroyOnFileThread();
52 void StartWatchOnFileThread(const base::FilePath& path,
53 const StartWatchCallback& on_start_callback,
54 const base::Closure& on_write_callback);
56 void OnWriteEvent(const base::FilePath& path, bool error);
58 void InvokeCallback(const base::FilePath& path);
60 struct PathWatchInfo {
61 std::vector<base::Closure> on_write_callbacks;
62 base::FilePathWatcher watcher;
63 base::Timer timer;
65 explicit PathWatchInfo(const base::Closure& on_write_callback)
66 : on_write_callbacks(1, on_write_callback),
67 timer(false /* retain_closure_on_reset */, false /* is_repeating */) {
71 base::TimeDelta delay_;
72 std::map<base::FilePath, PathWatchInfo*> watchers_;
74 // Note: This should remain the last member so it'll be destroyed and
75 // invalidate its weak pointers before any other members are destroyed.
76 base::WeakPtrFactory<FileWriteWatcherImpl> weak_ptr_factory_;
77 DISALLOW_COPY_AND_ASSIGN(FileWriteWatcherImpl);
80 FileWriteWatcher::FileWriteWatcherImpl::FileWriteWatcherImpl()
81 : delay_(base::TimeDelta::FromSeconds(kWriteEventDelayInSeconds)),
82 weak_ptr_factory_(this) {
83 DCHECK_CURRENTLY_ON(BrowserThread::UI);
86 void FileWriteWatcher::FileWriteWatcherImpl::Destroy() {
87 DCHECK_CURRENTLY_ON(BrowserThread::UI);
89 // Just forwarding the call to FILE thread.
90 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)->PostTask(
91 FROM_HERE,
92 base::Bind(&FileWriteWatcherImpl::DestroyOnFileThread,
93 base::Unretained(this)));
96 void FileWriteWatcher::FileWriteWatcherImpl::StartWatch(
97 const base::FilePath& path,
98 const StartWatchCallback& on_start_callback,
99 const base::Closure& on_write_callback) {
100 DCHECK_CURRENTLY_ON(BrowserThread::UI);
102 // Forwarding the call to FILE thread and relaying the |callback|.
103 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)->PostTask(
104 FROM_HERE,
105 base::Bind(&FileWriteWatcherImpl::StartWatchOnFileThread,
106 base::Unretained(this),
107 path,
108 google_apis::CreateRelayCallback(on_start_callback),
109 google_apis::CreateRelayCallback(on_write_callback)));
112 FileWriteWatcher::FileWriteWatcherImpl::~FileWriteWatcherImpl() {
113 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
115 STLDeleteContainerPairSecondPointers(watchers_.begin(), watchers_.end());
118 void FileWriteWatcher::FileWriteWatcherImpl::DestroyOnFileThread() {
119 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
121 delete this;
124 void FileWriteWatcher::FileWriteWatcherImpl::StartWatchOnFileThread(
125 const base::FilePath& path,
126 const StartWatchCallback& on_start_callback,
127 const base::Closure& on_write_callback) {
128 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
130 std::map<base::FilePath, PathWatchInfo*>::iterator it = watchers_.find(path);
131 if (it != watchers_.end()) {
132 // We are already watching the path.
133 on_start_callback.Run(true);
134 it->second->on_write_callbacks.push_back(on_write_callback);
135 return;
138 // Start watching |path|.
139 scoped_ptr<PathWatchInfo> info(new PathWatchInfo(on_write_callback));
140 bool ok = info->watcher.Watch(
141 path,
142 false, // recursive
143 base::Bind(&FileWriteWatcherImpl::OnWriteEvent,
144 weak_ptr_factory_.GetWeakPtr()));
145 watchers_[path] = info.release();
146 on_start_callback.Run(ok);
149 void FileWriteWatcher::FileWriteWatcherImpl::OnWriteEvent(
150 const base::FilePath& path,
151 bool error) {
152 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
154 if (error)
155 return;
157 std::map<base::FilePath, PathWatchInfo*>::iterator it = watchers_.find(path);
158 DCHECK(it != watchers_.end());
160 // Heuristics for detecting the end of successive write operations.
161 // Delay running on_write_event_callback by |delay_| time, and if OnWriteEvent
162 // is called again in the period, the timer is reset. In other words, we
163 // invoke callback when |delay_| has passed after the last OnWriteEvent().
164 it->second->timer.Start(FROM_HERE,
165 delay_,
166 base::Bind(&FileWriteWatcherImpl::InvokeCallback,
167 weak_ptr_factory_.GetWeakPtr(),
168 path));
171 void FileWriteWatcher::FileWriteWatcherImpl::InvokeCallback(
172 const base::FilePath& path) {
173 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
175 std::map<base::FilePath, PathWatchInfo*>::iterator it = watchers_.find(path);
176 DCHECK(it != watchers_.end());
178 std::vector<base::Closure> callbacks;
179 callbacks.swap(it->second->on_write_callbacks);
180 delete it->second;
181 watchers_.erase(it);
183 for (size_t i = 0; i < callbacks.size(); ++i)
184 callbacks[i].Run();
187 FileWriteWatcher::FileWriteWatcher()
188 : watcher_impl_(new FileWriteWatcherImpl) {
189 DCHECK_CURRENTLY_ON(BrowserThread::UI);
192 FileWriteWatcher::~FileWriteWatcher() {
193 DCHECK_CURRENTLY_ON(BrowserThread::UI);
196 void FileWriteWatcher::StartWatch(const base::FilePath& file_path,
197 const StartWatchCallback& on_start_callback,
198 const base::Closure& on_write_callback) {
199 DCHECK_CURRENTLY_ON(BrowserThread::UI);
200 watcher_impl_->StartWatch(file_path, on_start_callback, on_write_callback);
203 void FileWriteWatcher::DisableDelayForTesting() {
204 watcher_impl_->set_delay(base::TimeDelta());
207 } // namespace internal
208 } // namespace drive