Update broken references to image assets
[chromium-blink-merge.git] / chrome / browser / chromeos / drive / file_write_watcher.cc
bloba7a75aaac7bb7e3ff8224c19c163810241a3060d
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 "google_apis/drive/task_util.h"
17 namespace drive {
18 namespace internal {
20 namespace {
21 const int64 kWriteEventDelayInSeconds = 5;
22 } // namespace
24 // base::FileWatcher needs to live in a thread that is allowed to do File IO
25 // and has a TYPE_IO message loop: that is, FILE thread. This class bridges the
26 // UI thread and FILE thread, and does all the main tasks in the FILE thread.
27 class FileWriteWatcher::FileWriteWatcherImpl {
28 public:
29 explicit FileWriteWatcherImpl(base::SingleThreadTaskRunner* file_task_runner);
31 // Forwards the call to DestoryOnFileThread(). This method must be used to
32 // destruct the instance.
33 void Destroy();
35 // Forwards the call to StartWatchOnFileThread(). |on_start_callback| is
36 // called back on the caller (UI) thread when the watch has started.
37 // |on_write_callback| is called when a write has happened to the path.
38 void StartWatch(const base::FilePath& path,
39 const StartWatchCallback& on_start_callback,
40 const base::Closure& on_write_callback);
42 void set_delay(base::TimeDelta delay) { delay_ = delay; }
44 private:
45 ~FileWriteWatcherImpl();
47 void DestroyOnFileThread();
49 void StartWatchOnFileThread(const base::FilePath& path,
50 const StartWatchCallback& on_start_callback,
51 const base::Closure& on_write_callback);
53 void OnWriteEvent(const base::FilePath& path, bool error);
55 void InvokeCallback(const base::FilePath& path);
57 struct PathWatchInfo {
58 std::vector<base::Closure> on_write_callbacks;
59 base::FilePathWatcher watcher;
60 base::Timer timer;
62 explicit PathWatchInfo(const base::Closure& on_write_callback)
63 : on_write_callbacks(1, on_write_callback),
64 timer(false /* retain_closure_on_reset */, false /* is_repeating */) {
68 base::TimeDelta delay_;
69 std::map<base::FilePath, PathWatchInfo*> watchers_;
70 scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
72 base::ThreadChecker thread_checker_;
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 base::SingleThreadTaskRunner* file_task_runner)
82 : delay_(base::TimeDelta::FromSeconds(kWriteEventDelayInSeconds)),
83 file_task_runner_(file_task_runner),
84 weak_ptr_factory_(this) {
87 void FileWriteWatcher::FileWriteWatcherImpl::Destroy() {
88 DCHECK(thread_checker_.CalledOnValidThread());
90 // Just forwarding the call to FILE thread.
91 file_task_runner_->PostTask(
92 FROM_HERE, 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(thread_checker_.CalledOnValidThread());
102 // Forwarding the call to FILE thread and relaying the |callback|.
103 file_task_runner_->PostTask(
104 FROM_HERE,
105 base::Bind(&FileWriteWatcherImpl::StartWatchOnFileThread,
106 base::Unretained(this), path,
107 google_apis::CreateRelayCallback(on_start_callback),
108 google_apis::CreateRelayCallback(on_write_callback)));
111 FileWriteWatcher::FileWriteWatcherImpl::~FileWriteWatcherImpl() {
112 DCHECK(file_task_runner_->BelongsToCurrentThread());
114 STLDeleteContainerPairSecondPointers(watchers_.begin(), watchers_.end());
117 void FileWriteWatcher::FileWriteWatcherImpl::DestroyOnFileThread() {
118 DCHECK(file_task_runner_->BelongsToCurrentThread());
120 delete this;
123 void FileWriteWatcher::FileWriteWatcherImpl::StartWatchOnFileThread(
124 const base::FilePath& path,
125 const StartWatchCallback& on_start_callback,
126 const base::Closure& on_write_callback) {
127 DCHECK(file_task_runner_->BelongsToCurrentThread());
129 std::map<base::FilePath, PathWatchInfo*>::iterator it = watchers_.find(path);
130 if (it != watchers_.end()) {
131 // We are already watching the path.
132 on_start_callback.Run(true);
133 it->second->on_write_callbacks.push_back(on_write_callback);
134 return;
137 // Start watching |path|.
138 scoped_ptr<PathWatchInfo> info(new PathWatchInfo(on_write_callback));
139 bool ok = info->watcher.Watch(
140 path,
141 false, // recursive
142 base::Bind(&FileWriteWatcherImpl::OnWriteEvent,
143 weak_ptr_factory_.GetWeakPtr()));
144 watchers_[path] = info.release();
145 on_start_callback.Run(ok);
148 void FileWriteWatcher::FileWriteWatcherImpl::OnWriteEvent(
149 const base::FilePath& path,
150 bool error) {
151 DCHECK(file_task_runner_->BelongsToCurrentThread());
153 if (error)
154 return;
156 std::map<base::FilePath, PathWatchInfo*>::iterator it = watchers_.find(path);
157 DCHECK(it != watchers_.end());
159 // Heuristics for detecting the end of successive write operations.
160 // Delay running on_write_event_callback by |delay_| time, and if OnWriteEvent
161 // is called again in the period, the timer is reset. In other words, we
162 // invoke callback when |delay_| has passed after the last OnWriteEvent().
163 it->second->timer.Start(FROM_HERE,
164 delay_,
165 base::Bind(&FileWriteWatcherImpl::InvokeCallback,
166 weak_ptr_factory_.GetWeakPtr(),
167 path));
170 void FileWriteWatcher::FileWriteWatcherImpl::InvokeCallback(
171 const base::FilePath& path) {
172 DCHECK(file_task_runner_->BelongsToCurrentThread());
174 std::map<base::FilePath, PathWatchInfo*>::iterator it = watchers_.find(path);
175 DCHECK(it != watchers_.end());
177 std::vector<base::Closure> callbacks;
178 callbacks.swap(it->second->on_write_callbacks);
179 delete it->second;
180 watchers_.erase(it);
182 for (size_t i = 0; i < callbacks.size(); ++i)
183 callbacks[i].Run();
186 FileWriteWatcher::FileWriteWatcher(
187 base::SingleThreadTaskRunner* file_task_runner)
188 : watcher_impl_(new FileWriteWatcherImpl(file_task_runner)) {
191 FileWriteWatcher::~FileWriteWatcher() {
192 DCHECK(thread_checker_.CalledOnValidThread());
195 void FileWriteWatcher::StartWatch(const base::FilePath& file_path,
196 const StartWatchCallback& on_start_callback,
197 const base::Closure& on_write_callback) {
198 DCHECK(thread_checker_.CalledOnValidThread());
199 watcher_impl_->StartWatch(file_path, on_start_callback, on_write_callback);
202 void FileWriteWatcher::DisableDelayForTesting() {
203 watcher_impl_->set_delay(base::TimeDelta());
206 } // namespace internal
207 } // namespace drive