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/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
{
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 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
);
249 FindSyncRoot(token
.Pass());
252 void SyncEngineInitializer::DetachSyncRoot(scoped_ptr
<SyncTaskToken
> token
) {
253 DCHECK(sync_root_folder_
);
254 set_used_network(true);
256 sync_context_
->GetDriveService()->RemoveResourceFromDirectory(
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
);
277 ListAppRootFolders(token
.Pass());
280 void SyncEngineInitializer::ListAppRootFolders(
281 scoped_ptr
<SyncTaskToken
> token
) {
282 DCHECK(sync_root_folder_
);
283 set_used_network(true);
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
);
308 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
309 "[Initialize] Got invalid initial app-root list.");
310 SyncTaskManager::NotifyTaskDone(token
.Pass(), SYNC_STATUS_FAILED
);
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()) {
323 sync_context_
->GetDriveService()->GetRemainingFileList(
324 file_list
->next_link(),
325 base::Bind(&SyncEngineInitializer::DidListAppRootFolders
,
326 weak_ptr_factory_
.GetWeakPtr(), base::Passed(&token
)));
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
);
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