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/drive/drive_api_util.h"
12 #include "chrome/browser/google_apis/drive_api_parser.h"
13 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
14 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
15 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
16 #include "chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_util.h"
18 namespace sync_file_system {
19 namespace drive_backend {
23 ////////////////////////////////////////////////////////////////////////////////
24 // Functions below are for wrapping the access to legacy GData WAPI classes.
26 bool IsDeleted(const google_apis::ResourceEntry& entry) {
27 return entry.deleted();
30 bool HasNoParents(const google_apis::ResourceEntry& entry) {
31 return !entry.GetLinkByType(google_apis::Link::LINK_PARENT);
34 bool HasFolderAsParent(const google_apis::ResourceEntry& entry,
35 const std::string& parent_id) {
36 const ScopedVector<google_apis::Link>& links = entry.links();
37 for (ScopedVector<google_apis::Link>::const_iterator itr = links.begin();
38 itr != links.end(); ++itr) {
39 const google_apis::Link& link = **itr;
40 if (link.type() != google_apis::Link::LINK_PARENT)
42 if (drive::util::ExtractResourceIdFromUrl(link.href()) == parent_id)
48 bool LessOnCreationTime(const google_apis::ResourceEntry& left,
49 const google_apis::ResourceEntry& right) {
50 return left.published_time() < right.published_time();
53 // Posts a request to continue listing. Returns false if the list doesn't need
55 bool GetRemainingFileList(
56 google_apis::CancelCallback* cancel_callback,
57 drive::DriveServiceInterface* api_service,
58 const google_apis::ResourceList& resource_list,
59 const google_apis::GetResourceListCallback& callback) {
61 if (!resource_list.GetNextFeedURL(&next_url))
64 *cancel_callback = api_service->GetRemainingFileList(next_url, callback);
68 std::string GetID(const google_apis::ResourceEntry& entry) {
69 return entry.resource_id();
72 ScopedVector<google_apis::FileResource> ConvertResourceEntriesToFileResources(
73 const ScopedVector<google_apis::ResourceEntry>& entries) {
74 ScopedVector<google_apis::FileResource> resources;
75 for (ScopedVector<google_apis::ResourceEntry>::const_iterator itr =
80 drive::util::ConvertResourceEntryToFileResource(
83 return resources.Pass();
86 // Functions above are for wrapping the access to legacy GData WAPI classes.
87 ////////////////////////////////////////////////////////////////////////////////
91 SyncEngineInitializer::SyncEngineInitializer(
92 base::SequencedTaskRunner* task_runner,
93 drive::DriveServiceInterface* drive_service,
94 const base::FilePath& database_path)
95 : task_runner_(task_runner),
96 drive_service_(drive_service),
97 database_path_(database_path),
98 find_sync_root_retry_count_(0),
99 largest_change_id_(0),
100 weak_ptr_factory_(this) {
102 DCHECK(drive_service_);
105 SyncEngineInitializer::~SyncEngineInitializer() {
106 if (!cancel_callback_.is_null())
107 cancel_callback_.Run();
110 void SyncEngineInitializer::Run(const SyncStatusCallback& callback) {
111 MetadataDatabase::Create(
112 task_runner_.get(), database_path_,
113 base::Bind(&SyncEngineInitializer::DidCreateMetadataDatabase,
114 weak_ptr_factory_.GetWeakPtr(), callback));
117 scoped_ptr<MetadataDatabase> SyncEngineInitializer::PassMetadataDatabase() {
118 return metadata_database_.Pass();
121 void SyncEngineInitializer::DidCreateMetadataDatabase(
122 const SyncStatusCallback& callback,
123 SyncStatusCode status,
124 scoped_ptr<MetadataDatabase> instance) {
125 if (status != SYNC_STATUS_OK) {
126 callback.Run(status);
131 metadata_database_ = instance.Pass();
132 if (metadata_database_->HasSyncRoot()) {
133 callback.Run(SYNC_STATUS_OK);
137 GetAboutResource(callback);
140 void SyncEngineInitializer::GetAboutResource(
141 const SyncStatusCallback& callback) {
142 drive_service_->GetAboutResource(
143 base::Bind(&SyncEngineInitializer::DidGetAboutResource,
144 weak_ptr_factory_.GetWeakPtr(), callback));
147 void SyncEngineInitializer::DidGetAboutResource(
148 const SyncStatusCallback& callback,
149 google_apis::GDataErrorCode error,
150 scoped_ptr<google_apis::AboutResource> about_resource) {
151 cancel_callback_.Reset();
152 if (error != google_apis::HTTP_SUCCESS) {
153 callback.Run(GDataErrorCodeToSyncStatusCode(error));
157 DCHECK(about_resource);
158 root_folder_id_ = about_resource->root_folder_id();
159 largest_change_id_ = about_resource->largest_change_id();
161 DCHECK(!root_folder_id_.empty());
162 FindSyncRoot(callback);
165 void SyncEngineInitializer::FindSyncRoot(const SyncStatusCallback& callback) {
166 if (find_sync_root_retry_count_++ >= kMaxRetry) {
167 callback.Run(SYNC_STATUS_FAILED);
171 cancel_callback_ = drive_service_->SearchByTitle(
172 kSyncRootFolderTitle,
173 std::string(), // parent_folder_id
174 base::Bind(&SyncEngineInitializer::DidFindSyncRoot,
175 weak_ptr_factory_.GetWeakPtr(),
179 void SyncEngineInitializer::DidFindSyncRoot(
180 const SyncStatusCallback& callback,
181 google_apis::GDataErrorCode error,
182 scoped_ptr<google_apis::ResourceList> resource_list) {
183 cancel_callback_.Reset();
184 if (error != google_apis::HTTP_SUCCESS) {
185 callback.Run(GDataErrorCodeToSyncStatusCode(error));
189 ScopedVector<google_apis::ResourceEntry>* entries =
190 resource_list->mutable_entries();
191 for (ScopedVector<google_apis::ResourceEntry>::iterator itr =
193 itr != entries->end(); ++itr) {
194 google_apis::ResourceEntry* entry = *itr;
196 // Ignore deleted folder.
197 if (IsDeleted(*entry))
200 // Pick an orphaned folder or a direct child of the root folder and
202 DCHECK(!root_folder_id_.empty());
203 if (!HasNoParents(*entry) && !HasFolderAsParent(*entry, root_folder_id_))
206 if (!sync_root_folder_ || LessOnCreationTime(*entry, *sync_root_folder_)) {
207 sync_root_folder_.reset(entry);
212 // If there are more results, retrieve them.
213 if (GetRemainingFileList(
215 drive_service_, *resource_list,
216 base::Bind(&SyncEngineInitializer::DidFindSyncRoot,
217 weak_ptr_factory_.GetWeakPtr(),
221 if (!sync_root_folder_) {
222 CreateSyncRoot(callback);
226 if (!HasNoParents(*sync_root_folder_)) {
227 DetachSyncRoot(callback);
231 ListAppRootFolders(callback);
234 void SyncEngineInitializer::CreateSyncRoot(const SyncStatusCallback& callback) {
235 DCHECK(!sync_root_folder_);
236 cancel_callback_ = drive_service_->AddNewDirectory(
237 root_folder_id_, kSyncRootFolderTitle,
238 base::Bind(&SyncEngineInitializer::DidCreateSyncRoot,
239 weak_ptr_factory_.GetWeakPtr(),
243 void SyncEngineInitializer::DidCreateSyncRoot(
244 const SyncStatusCallback& callback,
245 google_apis::GDataErrorCode error,
246 scoped_ptr<google_apis::ResourceEntry> entry) {
247 DCHECK(!sync_root_folder_);
248 cancel_callback_.Reset();
249 if (error != google_apis::HTTP_SUCCESS &&
250 error != google_apis::HTTP_CREATED) {
251 callback.Run(GDataErrorCodeToSyncStatusCode(error));
255 FindSyncRoot(callback);
258 void SyncEngineInitializer::DetachSyncRoot(const SyncStatusCallback& callback) {
259 DCHECK(sync_root_folder_);
260 cancel_callback_ = drive_service_->RemoveResourceFromDirectory(
261 root_folder_id_, GetID(*sync_root_folder_),
262 base::Bind(&SyncEngineInitializer::DidDetachSyncRoot,
263 weak_ptr_factory_.GetWeakPtr(),
267 void SyncEngineInitializer::DidDetachSyncRoot(
268 const SyncStatusCallback& callback,
269 google_apis::GDataErrorCode error) {
270 cancel_callback_.Reset();
271 if (error != google_apis::HTTP_SUCCESS) {
272 callback.Run(GDataErrorCodeToSyncStatusCode(error));
275 ListAppRootFolders(callback);
278 void SyncEngineInitializer::ListAppRootFolders(
279 const SyncStatusCallback& callback) {
280 DCHECK(sync_root_folder_);
281 cancel_callback_ = drive_service_->GetResourceListInDirectory(
282 GetID(*sync_root_folder_),
283 base::Bind(&SyncEngineInitializer::DidListAppRootFolders,
284 weak_ptr_factory_.GetWeakPtr(),
288 void SyncEngineInitializer::DidListAppRootFolders(
289 const SyncStatusCallback& callback,
290 google_apis::GDataErrorCode error,
291 scoped_ptr<google_apis::ResourceList> resource_list) {
292 cancel_callback_.Reset();
293 if (error != google_apis::HTTP_SUCCESS) {
294 callback.Run(GDataErrorCodeToSyncStatusCode(error));
298 ScopedVector<google_apis::ResourceEntry>* new_entries =
299 resource_list->mutable_entries();
300 app_root_folders_.insert(app_root_folders_.end(),
301 new_entries->begin(), new_entries->end());
302 new_entries->weak_clear();
304 if (GetRemainingFileList(
308 base::Bind(&SyncEngineInitializer::DidListAppRootFolders,
309 weak_ptr_factory_.GetWeakPtr(), callback)))
312 PopulateDatabase(callback);
315 void SyncEngineInitializer::PopulateDatabase(
316 const SyncStatusCallback& callback) {
317 DCHECK(sync_root_folder_);
318 metadata_database_->PopulateInitialData(
320 *drive::util::ConvertResourceEntryToFileResource(
322 ConvertResourceEntriesToFileResources(app_root_folders_),
323 base::Bind(&SyncEngineInitializer::DidPopulateDatabase,
324 weak_ptr_factory_.GetWeakPtr(),
328 void SyncEngineInitializer::DidPopulateDatabase(
329 const SyncStatusCallback& callback,
330 SyncStatusCode status) {
331 if (status != SYNC_STATUS_OK) {
332 callback.Run(status);
336 callback.Run(SYNC_STATUS_OK);
339 } // namespace drive_backend
340 } // namespace sync_file_system