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.
4
5#include "chrome/browser/chromeos/file_manager/file_watcher.h"
6
7#include "base/bind.h"
8#include "content/public/browser/browser_thread.h"
9#include "google_apis/drive/task_util.h"
10
11using content::BrowserThread;
12
13namespace file_manager {
14namespace {
15
16// Creates a base::FilePathWatcher and starts watching at |watch_path| with
17// |callback|. Returns NULL on failure.
18base::FilePathWatcher* CreateAndStartFilePathWatcher(
19    const base::FilePath& watch_path,
20    const base::FilePathWatcher::Callback& callback) {
21  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
22  DCHECK(!callback.is_null());
23
24  scoped_ptr<base::FilePathWatcher> watcher(new base::FilePathWatcher);
25  if (!watcher->Watch(watch_path, false /* recursive */, callback))
26    return NULL;
27
28  return watcher.release();
29}
30
31}  // namespace
32
33FileWatcher::FileWatcher(const base::FilePath& virtual_path)
34    : local_file_watcher_(NULL),
35      virtual_path_(virtual_path),
36      weak_ptr_factory_(this) {
37  DCHECK_CURRENTLY_ON(BrowserThread::UI);
38}
39
40FileWatcher::~FileWatcher() {
41  DCHECK_CURRENTLY_ON(BrowserThread::UI);
42
43  BrowserThread::DeleteSoon(BrowserThread::FILE,
44                            FROM_HERE,
45                            local_file_watcher_);
46}
47
48void FileWatcher::AddExtension(const std::string& extension_id) {
49  DCHECK_CURRENTLY_ON(BrowserThread::UI);
50
51  extensions_[extension_id]++;
52}
53
54void FileWatcher::RemoveExtension(const std::string& extension_id) {
55  DCHECK_CURRENTLY_ON(BrowserThread::UI);
56
57  ExtensionCountMap::iterator it = extensions_.find(extension_id);
58  if (it == extensions_.end()) {
59    LOG(ERROR) << " Extension [" << extension_id
60               << "] tries to unsubscribe from folder ["
61               << virtual_path_.value()
62               << "] it isn't subscribed";
63    return;
64  }
65
66  // If entry found - decrease it's count and remove if necessary
67  --it->second;
68  if (it->second == 0)
69    extensions_.erase(it);
70}
71
72std::vector<std::string> FileWatcher::GetExtensionIds() const {
73  std::vector<std::string> extension_ids;
74  for (ExtensionCountMap::const_iterator iter = extensions_.begin();
75       iter != extensions_.end(); ++iter) {
76    extension_ids.push_back(iter->first);
77  }
78  return extension_ids;
79}
80
81void FileWatcher::WatchLocalFile(
82    const base::FilePath& local_path,
83    const base::FilePathWatcher::Callback& file_watcher_callback,
84    const BoolCallback& callback) {
85  DCHECK_CURRENTLY_ON(BrowserThread::UI);
86  DCHECK(!callback.is_null());
87  DCHECK(!local_file_watcher_);
88
89  BrowserThread::PostTaskAndReplyWithResult(
90      BrowserThread::FILE,
91      FROM_HERE,
92      base::Bind(&CreateAndStartFilePathWatcher,
93                 local_path,
94                 google_apis::CreateRelayCallback(file_watcher_callback)),
95      base::Bind(&FileWatcher::OnWatcherStarted,
96                 weak_ptr_factory_.GetWeakPtr(),
97                 callback));
98}
99
100void FileWatcher::OnWatcherStarted(
101    const BoolCallback& callback,
102    base::FilePathWatcher* file_watcher) {
103  DCHECK_CURRENTLY_ON(BrowserThread::UI);
104  DCHECK(!callback.is_null());
105  DCHECK(!local_file_watcher_);
106
107  if (file_watcher) {
108    local_file_watcher_ = file_watcher;
109    callback.Run(true);
110  } else {
111    callback.Run(false);
112  }
113}
114
115}  // namespace file_manager
116