Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / sync_file_system / drive_backend / sync_engine_initializer.cc
blob96886fde10b0a3c2aa9e0e16091a1abdc77d3fae
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/sync_file_system/drive_backend/sync_engine_initializer.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/logging.h"
10 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
11 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
12 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
13 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
14 #include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h"
15 #include "chrome/browser/sync_file_system/drive_backend/sync_task_token.h"
16 #include "chrome/browser/sync_file_system/logger.h"
17 #include "components/drive/service/drive_api_service.h"
18 #include "google_apis/drive/drive_api_parser.h"
20 namespace sync_file_system {
21 namespace drive_backend {
23 namespace {
25 ////////////////////////////////////////////////////////////////////////////////
26 // Functions below are for wrapping the access to legacy GData WAPI classes.
28 bool HasNoParents(const google_apis::FileResource& entry) {
29 return entry.parents().empty();
32 bool HasFolderAsParent(const google_apis::FileResource& entry,
33 const std::string& parent_id) {
34 for (size_t i = 0; i < entry.parents().size(); ++i) {
35 if (entry.parents()[i].file_id() == parent_id)
36 return true;
38 return false;
41 bool LessOnCreationTime(const google_apis::FileResource& left,
42 const google_apis::FileResource& right) {
43 return left.created_date() < right.created_date();
46 // Functions above are for wrapping the access to legacy GData WAPI classes.
47 ////////////////////////////////////////////////////////////////////////////////
49 } // namespace
51 SyncEngineInitializer::SyncEngineInitializer(
52 SyncEngineContext* sync_context,
53 const base::FilePath& database_path,
54 leveldb::Env* env_override)
55 : sync_context_(sync_context),
56 env_override_(env_override),
57 database_path_(database_path),
58 find_sync_root_retry_count_(0),
59 largest_change_id_(0),
60 weak_ptr_factory_(this) {
61 DCHECK(sync_context);
64 SyncEngineInitializer::~SyncEngineInitializer() {
65 if (!cancel_callback_.is_null())
66 cancel_callback_.Run();
69 void SyncEngineInitializer::RunPreflight(scoped_ptr<SyncTaskToken> token) {
70 util::Log(logging::LOG_VERBOSE, FROM_HERE, "[Initialize] Start.");
71 DCHECK(sync_context_);
72 DCHECK(sync_context_->GetDriveService());
74 // The metadata seems to have been already initialized. Just return with OK.
75 if (sync_context_->GetMetadataDatabase()) {
76 util::Log(logging::LOG_VERBOSE, FROM_HERE,
77 "[Initialize] Already initialized.");
78 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_OK);
79 return;
82 SyncStatusCode status = SYNC_STATUS_FAILED;
83 scoped_ptr<MetadataDatabase> metadata_database =
84 MetadataDatabase::Create(database_path_, env_override_, &status);
86 if (status != SYNC_STATUS_OK) {
87 util::Log(logging::LOG_VERBOSE, FROM_HERE,
88 "[Initialize] Failed to initialize MetadataDatabase.");
89 SyncTaskManager::NotifyTaskDone(token.Pass(), status);
90 return;
93 DCHECK(metadata_database);
94 metadata_database_ = metadata_database.Pass();
95 if (metadata_database_->HasSyncRoot()) {
96 util::Log(logging::LOG_VERBOSE, FROM_HERE,
97 "[Initialize] Found local cache of sync-root.");
98 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_OK);
99 return;
102 GetAboutResource(token.Pass());
105 scoped_ptr<MetadataDatabase> SyncEngineInitializer::PassMetadataDatabase() {
106 return metadata_database_.Pass();
109 void SyncEngineInitializer::GetAboutResource(
110 scoped_ptr<SyncTaskToken> token) {
111 set_used_network(true);
112 sync_context_->GetDriveService()->GetAboutResource(
113 base::Bind(&SyncEngineInitializer::DidGetAboutResource,
114 weak_ptr_factory_.GetWeakPtr(), base::Passed(&token)));
117 void SyncEngineInitializer::DidGetAboutResource(
118 scoped_ptr<SyncTaskToken> token,
119 google_apis::DriveApiErrorCode error,
120 scoped_ptr<google_apis::AboutResource> about_resource) {
121 cancel_callback_.Reset();
123 SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error);
124 if (status != SYNC_STATUS_OK) {
125 util::Log(logging::LOG_VERBOSE, FROM_HERE,
126 "[Initialize] Failed to get AboutResource.");
127 SyncTaskManager::NotifyTaskDone(token.Pass(), status);
128 return;
131 DCHECK(about_resource);
132 root_folder_id_ = about_resource->root_folder_id();
133 largest_change_id_ = about_resource->largest_change_id();
135 DCHECK(!root_folder_id_.empty());
136 FindSyncRoot(token.Pass());
139 void SyncEngineInitializer::FindSyncRoot(scoped_ptr<SyncTaskToken> token) {
140 if (find_sync_root_retry_count_++ >= kMaxRetry) {
141 util::Log(logging::LOG_VERBOSE, FROM_HERE,
142 "[Initialize] Reached max retry count.");
143 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED);
144 return;
147 set_used_network(true);
148 cancel_callback_ = sync_context_->GetDriveService()->SearchByTitle(
149 kSyncRootFolderTitle,
150 std::string(), // parent_folder_id
151 base::Bind(&SyncEngineInitializer::DidFindSyncRoot,
152 weak_ptr_factory_.GetWeakPtr(),
153 base::Passed(&token)));
156 void SyncEngineInitializer::DidFindSyncRoot(
157 scoped_ptr<SyncTaskToken> token,
158 google_apis::DriveApiErrorCode error,
159 scoped_ptr<google_apis::FileList> file_list) {
160 cancel_callback_.Reset();
162 SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error);
163 if (status != SYNC_STATUS_OK) {
164 util::Log(logging::LOG_VERBOSE, FROM_HERE,
165 "[Initialize] Failed to find sync root.");
166 SyncTaskManager::NotifyTaskDone(token.Pass(), status);
167 return;
170 if (!file_list) {
171 NOTREACHED();
172 util::Log(logging::LOG_VERBOSE, FROM_HERE,
173 "[Initialize] Got invalid resource list.");
174 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED);
175 return;
178 ScopedVector<google_apis::FileResource>* items = file_list->mutable_items();
179 for (ScopedVector<google_apis::FileResource>::iterator itr = items->begin();
180 itr != items->end(); ++itr) {
181 google_apis::FileResource* entry = *itr;
183 // Ignore deleted folder.
184 if (entry->labels().is_trashed())
185 continue;
187 // Pick an orphaned folder or a direct child of the root folder and
188 // ignore others.
189 DCHECK(!root_folder_id_.empty());
190 if (!HasNoParents(*entry) && !HasFolderAsParent(*entry, root_folder_id_))
191 continue;
193 if (!sync_root_folder_ || LessOnCreationTime(*entry, *sync_root_folder_)) {
194 sync_root_folder_.reset(entry);
195 *itr = nullptr;
199 set_used_network(true);
200 // If there are more results, retrieve them.
201 if (!file_list->next_link().is_empty()) {
202 cancel_callback_ = sync_context_->GetDriveService()->GetRemainingFileList(
203 file_list->next_link(),
204 base::Bind(&SyncEngineInitializer::DidFindSyncRoot,
205 weak_ptr_factory_.GetWeakPtr(),
206 base::Passed(&token)));
207 return;
210 if (!sync_root_folder_) {
211 CreateSyncRoot(token.Pass());
212 return;
215 if (!HasNoParents(*sync_root_folder_)) {
216 DetachSyncRoot(token.Pass());
217 return;
220 ListAppRootFolders(token.Pass());
223 void SyncEngineInitializer::CreateSyncRoot(scoped_ptr<SyncTaskToken> token) {
224 DCHECK(!sync_root_folder_);
225 set_used_network(true);
226 drive::AddNewDirectoryOptions options;
227 options.visibility = google_apis::drive::FILE_VISIBILITY_PRIVATE;
228 cancel_callback_ = sync_context_->GetDriveService()->AddNewDirectory(
229 root_folder_id_, kSyncRootFolderTitle, options,
230 base::Bind(&SyncEngineInitializer::DidCreateSyncRoot,
231 weak_ptr_factory_.GetWeakPtr(), base::Passed(&token)));
234 void SyncEngineInitializer::DidCreateSyncRoot(
235 scoped_ptr<SyncTaskToken> token,
236 google_apis::DriveApiErrorCode error,
237 scoped_ptr<google_apis::FileResource> entry) {
238 DCHECK(!sync_root_folder_);
239 cancel_callback_.Reset();
241 SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error);
242 if (status != SYNC_STATUS_OK) {
243 util::Log(logging::LOG_VERBOSE, FROM_HERE,
244 "[Initialize] Failed to create sync root.");
245 SyncTaskManager::NotifyTaskDone(token.Pass(), status);
246 return;
249 FindSyncRoot(token.Pass());
252 void SyncEngineInitializer::DetachSyncRoot(scoped_ptr<SyncTaskToken> token) {
253 DCHECK(sync_root_folder_);
254 set_used_network(true);
255 cancel_callback_ =
256 sync_context_->GetDriveService()->RemoveResourceFromDirectory(
257 root_folder_id_,
258 sync_root_folder_->file_id(),
259 base::Bind(&SyncEngineInitializer::DidDetachSyncRoot,
260 weak_ptr_factory_.GetWeakPtr(),
261 base::Passed(&token)));
264 void SyncEngineInitializer::DidDetachSyncRoot(
265 scoped_ptr<SyncTaskToken> token,
266 google_apis::DriveApiErrorCode error) {
267 cancel_callback_.Reset();
269 SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error);
270 if (status != SYNC_STATUS_OK) {
271 util::Log(logging::LOG_VERBOSE, FROM_HERE,
272 "[Initialize] Failed to detach sync root.");
273 SyncTaskManager::NotifyTaskDone(token.Pass(), status);
274 return;
277 ListAppRootFolders(token.Pass());
280 void SyncEngineInitializer::ListAppRootFolders(
281 scoped_ptr<SyncTaskToken> token) {
282 DCHECK(sync_root_folder_);
283 set_used_network(true);
284 cancel_callback_ =
285 sync_context_->GetDriveService()->GetFileListInDirectory(
286 sync_root_folder_->file_id(),
287 base::Bind(&SyncEngineInitializer::DidListAppRootFolders,
288 weak_ptr_factory_.GetWeakPtr(),
289 base::Passed(&token)));
292 void SyncEngineInitializer::DidListAppRootFolders(
293 scoped_ptr<SyncTaskToken> token,
294 google_apis::DriveApiErrorCode error,
295 scoped_ptr<google_apis::FileList> file_list) {
296 cancel_callback_.Reset();
298 SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error);
299 if (status != SYNC_STATUS_OK) {
300 util::Log(logging::LOG_VERBOSE, FROM_HERE,
301 "[Initialize] Failed to get initial app-root folders.");
302 SyncTaskManager::NotifyTaskDone(token.Pass(), status);
303 return;
306 if (!file_list) {
307 NOTREACHED();
308 util::Log(logging::LOG_VERBOSE, FROM_HERE,
309 "[Initialize] Got invalid initial app-root list.");
310 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED);
311 return;
314 ScopedVector<google_apis::FileResource>* new_entries =
315 file_list->mutable_items();
316 app_root_folders_.insert(app_root_folders_.end(),
317 new_entries->begin(), new_entries->end());
318 new_entries->weak_clear();
320 set_used_network(true);
321 if (!file_list->next_link().is_empty()) {
322 cancel_callback_ =
323 sync_context_->GetDriveService()->GetRemainingFileList(
324 file_list->next_link(),
325 base::Bind(&SyncEngineInitializer::DidListAppRootFolders,
326 weak_ptr_factory_.GetWeakPtr(), base::Passed(&token)));
327 return;
330 PopulateDatabase(token.Pass());
333 void SyncEngineInitializer::PopulateDatabase(
334 scoped_ptr<SyncTaskToken> token) {
335 DCHECK(sync_root_folder_);
336 SyncStatusCode status = metadata_database_->PopulateInitialData(
337 largest_change_id_, *sync_root_folder_, app_root_folders_);
338 if (status != SYNC_STATUS_OK) {
339 util::Log(logging::LOG_VERBOSE, FROM_HERE,
340 "[Initialize] Failed to populate initial data"
341 " to MetadataDatabase.");
342 SyncTaskManager::NotifyTaskDone(token.Pass(), status);
343 return;
346 util::Log(logging::LOG_VERBOSE, FROM_HERE,
347 "[Initialize] Completed successfully.");
348 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_OK);
351 } // namespace drive_backend
352 } // namespace sync_file_system