blob: c570c079a72e2f75d0d510077d8bb0db04b7171c [file] [log] [blame]
[email protected]5051fdde2012-03-19 21:10:141// Copyright (c) 2012 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/gdata/gdata_sync_client.h"
6
[email protected]92b84f332012-03-21 20:45:217#include <sys/types.h>
8#include <sys/stat.h>
9#include <unistd.h>
10
[email protected]3653146a2012-05-29 13:41:4711#include <vector>
12
[email protected]92b84f332012-03-21 20:45:2113#include "base/bind.h"
14#include "base/file_util.h"
15#include "base/message_loop_proxy.h"
16#include "base/threading/sequenced_worker_pool.h"
[email protected]a5381772012-04-05 02:20:0417#include "chrome/browser/chromeos/cros/cros_library.h"
[email protected]5051fdde2012-03-19 21:10:1418#include "chrome/browser/chromeos/gdata/gdata_file_system.h"
[email protected]a5381772012-04-05 02:20:0419#include "chrome/browser/prefs/pref_change_registrar.h"
20#include "chrome/browser/prefs/pref_service.h"
21#include "chrome/browser/profiles/profile.h"
22#include "chrome/common/pref_names.h"
[email protected]92b84f332012-03-21 20:45:2123#include "content/public/browser/browser_thread.h"
24
25using content::BrowserThread;
[email protected]5051fdde2012-03-19 21:10:1426
27namespace gdata {
[email protected]92b84f332012-03-21 20:45:2128namespace {
29
30// Scans the pinned directory and returns pinned-but-not-fetched files.
31void ScanPinnedDirectory(const FilePath& directory,
32 std::vector<std::string>* resource_ids) {
33 using file_util::FileEnumerator;
34
35 DVLOG(1) << "Scanning " << directory.value();
36 FileEnumerator::FileType file_types =
37 static_cast<FileEnumerator::FileType>(FileEnumerator::FILES |
38 FileEnumerator::SHOW_SYM_LINKS);
39
40 FileEnumerator enumerator(directory, false /* recursive */, file_types);
41 for (FilePath file_path = enumerator.Next(); !file_path.empty();
42 file_path = enumerator.Next()) {
43 // Check if it's a symlink.
44 FileEnumerator::FindInfo find_info;
45 enumerator.GetFindInfo(&find_info);
46 const bool is_symlink = S_ISLNK(find_info.stat.st_mode);
47 if (!is_symlink) {
48 LOG(WARNING) << "Removing " << file_path.value() << " (not a symlink)";
49 file_util::Delete(file_path, false /* recursive */);
50 continue;
51 }
52 // Read the symbolic link.
53 FilePath destination;
54 if (!file_util::ReadSymbolicLink(file_path, &destination)) {
55 LOG(WARNING) << "Removing " << file_path.value() << " (not readable)";
56 file_util::Delete(file_path, false /* recursive */);
57 continue;
58 }
59 // Remove the symbolic link if it's dangling. Something went wrong.
60 if (!file_util::PathExists(destination)) {
61 LOG(WARNING) << "Removing " << file_path.value() << " (dangling)";
62 file_util::Delete(file_path, false /* recursive */);
63 continue;
64 }
65 // Add it to the output list, if the symlink points to /dev/null.
66 if (destination == FilePath::FromUTF8Unsafe("/dev/null")) {
67 std::string resource_id = file_path.BaseName().AsUTF8Unsafe();
68 resource_ids->push_back(resource_id);
69 }
70 }
71}
72
73} // namespace
[email protected]5051fdde2012-03-19 21:10:1474
[email protected]a5381772012-04-05 02:20:0475GDataSyncClient::GDataSyncClient(Profile* profile,
76 GDataFileSystemInterface* file_system)
77 : profile_(profile),
78 file_system_(file_system),
79 registrar_(new PrefChangeRegistrar),
[email protected]8a686f082012-03-27 06:03:5180 fetch_loop_is_running_(false),
[email protected]92b84f332012-03-21 20:45:2181 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]5051fdde2012-03-19 21:10:1483}
84
85GDataSyncClient::~GDataSyncClient() {
[email protected]92b84f332012-03-21 20:45:2186 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]13cfee922012-03-20 01:04:4487 if (file_system_)
88 file_system_->RemoveObserver(this);
[email protected]2416a2e2012-05-07 20:58:4989
90 chromeos::NetworkLibrary* network_library =
91 chromeos::CrosLibrary::Get()->GetNetworkLibrary();
92 if (network_library)
93 network_library->RemoveNetworkManagerObserver(this);
[email protected]13cfee922012-03-20 01:04:4494}
95
[email protected]bf57c872012-03-22 23:17:1596void GDataSyncClient::Initialize() {
[email protected]92b84f332012-03-21 20:45:2197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
98
[email protected]13cfee922012-03-20 01:04:4499 file_system_->AddObserver(this);
[email protected]a5381772012-04-05 02:20:04100
[email protected]2416a2e2012-05-07 20:58:49101 chromeos::NetworkLibrary* network_library =
102 chromeos::CrosLibrary::Get()->GetNetworkLibrary();
103 if (network_library)
104 network_library->AddNetworkManagerObserver(this);
105 else
106 LOG(ERROR) << "NetworkLibrary is not present";
107
[email protected]a5381772012-04-05 02:20:04108 registrar_->Init(profile_->GetPrefs());
109 registrar_->Add(prefs::kDisableGData, this);
110 registrar_->Add(prefs::kDisableGDataOverCellular, this);
[email protected]5051fdde2012-03-19 21:10:14111}
112
[email protected]ffd60e432012-03-24 20:36:00113void GDataSyncClient::StartInitialScan(const base::Closure& closure) {
[email protected]92b84f332012-03-21 20:45:21114 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]ffd60e432012-03-24 20:36:00115 DCHECK(!closure.is_null());
[email protected]92b84f332012-03-21 20:45:21116
117 // Start scanning the pinned directory in the cache.
118 std::vector<std::string>* resource_ids = new std::vector<std::string>;
119 const bool posted =
120 BrowserThread::GetBlockingPool()->PostTaskAndReply(
121 FROM_HERE,
122 base::Bind(&ScanPinnedDirectory,
[email protected]79c441f82012-04-24 06:07:54123 file_system_->GetCacheDirectoryPath(
[email protected]3653146a2012-05-29 13:41:47124 GDataCache::CACHE_TYPE_PINNED),
[email protected]92b84f332012-03-21 20:45:21125 resource_ids),
126 base::Bind(&GDataSyncClient::OnInitialScanComplete,
127 weak_ptr_factory_.GetWeakPtr(),
[email protected]ffd60e432012-03-24 20:36:00128 closure,
[email protected]92b84f332012-03-21 20:45:21129 base::Owned(resource_ids)));
130 DCHECK(posted);
131}
132
[email protected]8a686f082012-03-27 06:03:51133void GDataSyncClient::StartFetchLoop() {
134 if (!fetch_loop_is_running_)
135 DoFetchLoop();
136}
137
[email protected]adf84402012-03-25 21:56:38138void GDataSyncClient::DoFetchLoop() {
139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
140
[email protected]a5381772012-04-05 02:20:04141 if (queue_.empty() || ShouldStopFetchLoop()) {
142 // Note that |queue_| is not cleared so the fetch loop can resume.
[email protected]8a686f082012-03-27 06:03:51143 fetch_loop_is_running_ = false;
[email protected]adf84402012-03-25 21:56:38144 return;
[email protected]8a686f082012-03-27 06:03:51145 }
146 fetch_loop_is_running_ = true;
[email protected]adf84402012-03-25 21:56:38147
148 const std::string resource_id = queue_.front();
149 queue_.pop_front();
150
151 DVLOG(1) << "Fetching " << resource_id;
[email protected]40101ae2012-04-21 05:43:02152 file_system_->GetFileByResourceId(
[email protected]adf84402012-03-25 21:56:38153 resource_id,
154 base::Bind(&GDataSyncClient::OnFetchFileComplete,
155 weak_ptr_factory_.GetWeakPtr(),
[email protected]73c7f712012-04-27 20:45:27156 resource_id),
157 GetDownloadDataCallback());
[email protected]92b84f332012-03-21 20:45:21158}
159
[email protected]a5381772012-04-05 02:20:04160bool GDataSyncClient::ShouldStopFetchLoop() {
161 // Should stop if the gdata feature was disabled while running the fetch
162 // loop.
163 if (profile_->GetPrefs()->GetBoolean(prefs::kDisableGData))
164 return true;
165
166 // Something must be wrong if the network library is not present.
167 chromeos::NetworkLibrary* network_library =
168 chromeos::CrosLibrary::Get()->GetNetworkLibrary();
169 if (!network_library)
170 return true;
171
172 // Something must be wrong if the active network is not present.
173 const chromeos::Network* active_network = network_library->active_network();
174 if (!active_network)
175 return true;
176
177 // Should stop if the network is not online.
178 if (!active_network->online())
179 return true;
180
181 // Should stop if the current connection is on cellular network, and
182 // fetching is disabled over cellular.
183 if (profile_->GetPrefs()->GetBoolean(prefs::kDisableGDataOverCellular) &&
184 active_network->type() == chromeos::TYPE_CELLULAR)
185 return true;
186
187 return false;
188}
189
[email protected]8c4b51262012-03-21 23:42:47190void GDataSyncClient::OnCacheInitialized() {
[email protected]adf84402012-03-25 21:56:38191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
192
[email protected]8a686f082012-03-27 06:03:51193 // Start the initial scan. Once it's complete, start the fetch loop.
194 StartInitialScan(base::Bind(&GDataSyncClient::StartFetchLoop,
[email protected]adf84402012-03-25 21:56:38195 weak_ptr_factory_.GetWeakPtr()));
[email protected]8c4b51262012-03-21 23:42:47196}
197
[email protected]5051fdde2012-03-19 21:10:14198void GDataSyncClient::OnFilePinned(const std::string& resource_id,
199 const std::string& md5) {
[email protected]adf84402012-03-25 21:56:38200 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
201
202 // Add it to the queue, kick off the loop.
203 queue_.push_back(resource_id);
[email protected]8a686f082012-03-27 06:03:51204 StartFetchLoop();
[email protected]5051fdde2012-03-19 21:10:14205}
206
[email protected]8c4b51262012-03-21 23:42:47207void GDataSyncClient::OnFileUnpinned(const std::string& resource_id,
208 const std::string& md5) {
[email protected]adf84402012-03-25 21:56:38209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
210
211 // Remove the resource_id if it's in the queue. This can happen if the user
212 // cancels pinning before the file is fetched.
213 std::deque<std::string>::iterator iter =
214 std::find(queue_.begin(), queue_.end(), resource_id);
215 if (iter != queue_.end())
216 queue_.erase(iter);
[email protected]8c4b51262012-03-21 23:42:47217}
218
[email protected]92b84f332012-03-21 20:45:21219void GDataSyncClient::OnInitialScanComplete(
[email protected]ffd60e432012-03-24 20:36:00220 const base::Closure& closure,
[email protected]92b84f332012-03-21 20:45:21221 std::vector<std::string>* resource_ids) {
222 DCHECK(resource_ids);
223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
224
225 for (size_t i = 0; i < resource_ids->size(); ++i) {
226 const std::string& resource_id = (*resource_ids)[i];
227 DVLOG(1) << "Queuing " << resource_id;
[email protected]adf84402012-03-25 21:56:38228 queue_.push_back(resource_id);
[email protected]92b84f332012-03-21 20:45:21229 }
[email protected]ffd60e432012-03-24 20:36:00230
231 closure.Run();
[email protected]92b84f332012-03-21 20:45:21232}
233
[email protected]adf84402012-03-25 21:56:38234void GDataSyncClient::OnFetchFileComplete(const std::string& resource_id,
235 base::PlatformFileError error,
236 const FilePath& local_path,
[email protected]ff14110f2012-03-26 05:25:12237 const std::string& ununsed_mime_type,
[email protected]adf84402012-03-25 21:56:38238 GDataFileType file_type) {
239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
240
241 if (error == base::PLATFORM_FILE_OK) {
242 DVLOG(1) << "Fetched " << resource_id << ": " << local_path.value();
243 } else {
244 // TODO(satorux): We should re-queue if the error is recoverable.
[email protected]086290f2012-05-09 19:34:49245 LOG(WARNING) << "Failed to fetch " << resource_id << ": " << error;
[email protected]adf84402012-03-25 21:56:38246 }
247
[email protected]8a686f082012-03-27 06:03:51248 // Continue the loop.
[email protected]adf84402012-03-25 21:56:38249 DoFetchLoop();
250}
251
[email protected]2416a2e2012-05-07 20:58:49252void GDataSyncClient::OnNetworkManagerChanged(
253 chromeos::NetworkLibrary* network_library) {
[email protected]a5381772012-04-05 02:20:04254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
255
256 // Resume the fetch loop if the network is back online. Note that we don't
257 // need to check the type of the network as it will be checked in
258 // ShouldStopFetchLoop() as soon as the loop is resumed.
[email protected]2416a2e2012-05-07 20:58:49259 const chromeos::Network* active_network = network_library->active_network();
260 if (active_network && active_network->online())
[email protected]a5381772012-04-05 02:20:04261 StartFetchLoop();
262}
263
264void GDataSyncClient::Observe(int type,
265 const content::NotificationSource& source,
266 const content::NotificationDetails& details) {
267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
268
269 // Resume the fetch loop if gdata preferences are changed. Note that we
270 // don't need to check the new values here as these will be checked in
271 // ShouldStopFetchLoop() as soon as the loop is resumed.
272 StartFetchLoop();
273}
274
[email protected]5051fdde2012-03-19 21:10:14275} // namespace gdata