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"
8 #include "base/callback.h"
9 #include "base/logging.h"
10 #include "chrome/browser/drive/drive_api_service.h"
11 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
12 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
13 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
14 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
15 #include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h"
16 #include "chrome/browser/sync_file_system/drive_backend/sync_task_token.h"
17 #include "chrome/browser/sync_file_system/logger.h"
18 #include "google_apis/drive/drive_api_parser.h"
20 namespace sync_file_system
{
21 namespace drive_backend
{
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
)
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 ////////////////////////////////////////////////////////////////////////////////
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) {
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
);
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
);
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
);
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
);
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
);
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
);
172 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
173 "[Initialize] Got invalid resource list.");
174 SyncTaskManager::NotifyTaskDone(token
.Pass(), SYNC_STATUS_FAILED
);
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())
187 // Pick an orphaned folder or a direct child of the root folder and
189 DCHECK(!root_folder_id_
.empty());
190 if (!HasNoParents(*entry
) && !HasFolderAsParent(*entry
, root_folder_id_
))
193 if (!sync_root_folder_
|| LessOnCreationTime(*entry
, *sync_root_folder_
)) {
194 sync_root_folder_
.reset(entry
);
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
)));
210 if (!sync_root_folder_
) {
211 CreateSyncRoot(token
.Pass());
215 if (!HasNoParents(*sync_root_folder_
)) {
216 DetachSyncRoot(token
.Pass());
220 ListAppRootFolders(token
.Pass());
223 void SyncEngineInitializer::CreateSyncRoot(scoped_ptr
<SyncTaskToken
> token
) {
224 DCHECK(!sync_root_folder_
);
225 set_used_network(true);
226 cancel_callback_
= sync_context_
->GetDriveService()->AddNewDirectory(
227 root_folder_id_
, kSyncRootFolderTitle
, drive::AddNewDirectoryOptions(),
228 base::Bind(&SyncEngineInitializer::DidCreateSyncRoot
,
229 weak_ptr_factory_
.GetWeakPtr(), base::Passed(&token
)));
232 void SyncEngineInitializer::DidCreateSyncRoot(
233 scoped_ptr
<SyncTaskToken
> token
,
234 google_apis::DriveApiErrorCode error
,
235 scoped_ptr
<google_apis::FileResource
> entry
) {
236 DCHECK(!sync_root_folder_
);
237 cancel_callback_
.Reset();
239 SyncStatusCode status
= DriveApiErrorCodeToSyncStatusCode(error
);
240 if (status
!= SYNC_STATUS_OK
) {
241 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
242 "[Initialize] Failed to create sync root.");
243 SyncTaskManager::NotifyTaskDone(token
.Pass(), status
);
247 FindSyncRoot(token
.Pass());
250 void SyncEngineInitializer::DetachSyncRoot(scoped_ptr
<SyncTaskToken
> token
) {
251 DCHECK(sync_root_folder_
);
252 set_used_network(true);
254 sync_context_
->GetDriveService()->RemoveResourceFromDirectory(
256 sync_root_folder_
->file_id(),
257 base::Bind(&SyncEngineInitializer::DidDetachSyncRoot
,
258 weak_ptr_factory_
.GetWeakPtr(),
259 base::Passed(&token
)));
262 void SyncEngineInitializer::DidDetachSyncRoot(
263 scoped_ptr
<SyncTaskToken
> token
,
264 google_apis::DriveApiErrorCode error
) {
265 cancel_callback_
.Reset();
267 SyncStatusCode status
= DriveApiErrorCodeToSyncStatusCode(error
);
268 if (status
!= SYNC_STATUS_OK
) {
269 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
270 "[Initialize] Failed to detach sync root.");
271 SyncTaskManager::NotifyTaskDone(token
.Pass(), status
);
275 ListAppRootFolders(token
.Pass());
278 void SyncEngineInitializer::ListAppRootFolders(
279 scoped_ptr
<SyncTaskToken
> token
) {
280 DCHECK(sync_root_folder_
);
281 set_used_network(true);
283 sync_context_
->GetDriveService()->GetFileListInDirectory(
284 sync_root_folder_
->file_id(),
285 base::Bind(&SyncEngineInitializer::DidListAppRootFolders
,
286 weak_ptr_factory_
.GetWeakPtr(),
287 base::Passed(&token
)));
290 void SyncEngineInitializer::DidListAppRootFolders(
291 scoped_ptr
<SyncTaskToken
> token
,
292 google_apis::DriveApiErrorCode error
,
293 scoped_ptr
<google_apis::FileList
> file_list
) {
294 cancel_callback_
.Reset();
296 SyncStatusCode status
= DriveApiErrorCodeToSyncStatusCode(error
);
297 if (status
!= SYNC_STATUS_OK
) {
298 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
299 "[Initialize] Failed to get initial app-root folders.");
300 SyncTaskManager::NotifyTaskDone(token
.Pass(), status
);
306 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
307 "[Initialize] Got invalid initial app-root list.");
308 SyncTaskManager::NotifyTaskDone(token
.Pass(), SYNC_STATUS_FAILED
);
312 ScopedVector
<google_apis::FileResource
>* new_entries
=
313 file_list
->mutable_items();
314 app_root_folders_
.insert(app_root_folders_
.end(),
315 new_entries
->begin(), new_entries
->end());
316 new_entries
->weak_clear();
318 set_used_network(true);
319 if (!file_list
->next_link().is_empty()) {
321 sync_context_
->GetDriveService()->GetRemainingFileList(
322 file_list
->next_link(),
323 base::Bind(&SyncEngineInitializer::DidListAppRootFolders
,
324 weak_ptr_factory_
.GetWeakPtr(), base::Passed(&token
)));
328 PopulateDatabase(token
.Pass());
331 void SyncEngineInitializer::PopulateDatabase(
332 scoped_ptr
<SyncTaskToken
> token
) {
333 DCHECK(sync_root_folder_
);
334 SyncStatusCode status
= metadata_database_
->PopulateInitialData(
335 largest_change_id_
, *sync_root_folder_
, app_root_folders_
);
336 if (status
!= SYNC_STATUS_OK
) {
337 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
338 "[Initialize] Failed to populate initial data"
339 " to MetadataDatabase.");
340 SyncTaskManager::NotifyTaskDone(token
.Pass(), status
);
344 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
345 "[Initialize] Completed successfully.");
346 SyncTaskManager::NotifyTaskDone(token
.Pass(), SYNC_STATUS_OK
);
349 } // namespace drive_backend
350 } // namespace sync_file_system