sync_engine_initializer.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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. 4 5#include "chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h" 6 7#include "base/bind.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" 17 18namespace sync_file_system { 19namespace drive_backend { 20 21namespace { 22 23//////////////////////////////////////////////////////////////////////////////// 24// Functions below are for wrapping the access to legacy GData WAPI classes. 25 26bool IsDeleted(const google_apis::ResourceEntry& entry) { 27 return entry.deleted(); 28} 29 30bool HasNoParents(const google_apis::ResourceEntry& entry) { 31 return !entry.GetLinkByType(google_apis::Link::LINK_PARENT); 32} 33 34bool 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) 41 continue; 42 if (drive::util::ExtractResourceIdFromUrl(link.href()) == parent_id) 43 return true; 44 } 45 return false; 46} 47 48bool LessOnCreationTime(const google_apis::ResourceEntry& left, 49 const google_apis::ResourceEntry& right) { 50 return left.published_time() < right.published_time(); 51} 52 53// Posts a request to continue listing. Returns false if the list doesn't need 54// listing anymore. 55bool 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) { 60 GURL next_url; 61 if (!resource_list.GetNextFeedURL(&next_url)) 62 return false; 63 64 *cancel_callback = api_service->GetRemainingFileList(next_url, callback); 65 return true; 66} 67 68std::string GetID(const google_apis::ResourceEntry& entry) { 69 return entry.resource_id(); 70} 71 72ScopedVector<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 = 76 entries.begin(); 77 itr != entries.end(); 78 ++itr) { 79 resources.push_back( 80 drive::util::ConvertResourceEntryToFileResource( 81 **itr).release()); 82 } 83 return resources.Pass(); 84} 85 86// Functions above are for wrapping the access to legacy GData WAPI classes. 87//////////////////////////////////////////////////////////////////////////////// 88 89} // namespace 90 91SyncEngineInitializer::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 largest_change_id_(0), 99 weak_ptr_factory_(this) { 100 DCHECK(task_runner); 101 DCHECK(drive_service_); 102} 103 104SyncEngineInitializer::~SyncEngineInitializer() { 105 if (!cancel_callback_.is_null()) 106 cancel_callback_.Run(); 107} 108 109void SyncEngineInitializer::Run(const SyncStatusCallback& callback) { 110 MetadataDatabase::Create( 111 task_runner_.get(), database_path_, 112 base::Bind(&SyncEngineInitializer::DidCreateMetadataDatabase, 113 weak_ptr_factory_.GetWeakPtr(), callback)); 114} 115 116scoped_ptr<MetadataDatabase> SyncEngineInitializer::PassMetadataDatabase() { 117 return metadata_database_.Pass(); 118} 119 120void SyncEngineInitializer::DidCreateMetadataDatabase( 121 const SyncStatusCallback& callback, 122 SyncStatusCode status, 123 scoped_ptr<MetadataDatabase> instance) { 124 if (status != SYNC_STATUS_OK) { 125 callback.Run(status); 126 return; 127 } 128 129 DCHECK(instance); 130 metadata_database_ = instance.Pass(); 131 if (metadata_database_->HasSyncRoot()) { 132 callback.Run(SYNC_STATUS_OK); 133 return; 134 } 135 136 GetAboutResource(callback); 137} 138 139void SyncEngineInitializer::GetAboutResource( 140 const SyncStatusCallback& callback) { 141 drive_service_->GetAboutResource( 142 base::Bind(&SyncEngineInitializer::DidGetAboutResource, 143 weak_ptr_factory_.GetWeakPtr(), callback)); 144} 145 146void SyncEngineInitializer::DidGetAboutResource( 147 const SyncStatusCallback& callback, 148 google_apis::GDataErrorCode error, 149 scoped_ptr<google_apis::AboutResource> about_resource) { 150 cancel_callback_.Reset(); 151 if (error != google_apis::HTTP_SUCCESS) { 152 callback.Run(GDataErrorCodeToSyncStatusCode(error)); 153 return; 154 } 155 156 DCHECK(about_resource); 157 root_folder_id_ = about_resource->root_folder_id(); 158 largest_change_id_ = about_resource->largest_change_id(); 159 160 DCHECK(!root_folder_id_.empty()); 161 FindSyncRoot(callback); 162} 163 164void SyncEngineInitializer::FindSyncRoot(const SyncStatusCallback& callback) { 165 cancel_callback_ = drive_service_->SearchByTitle( 166 kSyncRootFolderTitle, 167 std::string(), // parent_folder_id 168 base::Bind(&SyncEngineInitializer::DidFindSyncRoot, 169 weak_ptr_factory_.GetWeakPtr(), 170 callback)); 171} 172 173void SyncEngineInitializer::DidFindSyncRoot( 174 const SyncStatusCallback& callback, 175 google_apis::GDataErrorCode error, 176 scoped_ptr<google_apis::ResourceList> resource_list) { 177 cancel_callback_.Reset(); 178 if (error != google_apis::HTTP_SUCCESS) { 179 callback.Run(GDataErrorCodeToSyncStatusCode(error)); 180 return; 181 } 182 183 ScopedVector<google_apis::ResourceEntry>* entries = 184 resource_list->mutable_entries(); 185 for (ScopedVector<google_apis::ResourceEntry>::iterator itr = 186 entries->begin(); 187 itr != entries->end(); ++itr) { 188 google_apis::ResourceEntry* entry = *itr; 189 190 // Ignore deleted folder. 191 if (IsDeleted(*entry)) 192 continue; 193 194 // Pick an orphaned folder or a direct child of the root folder and 195 // ignore others. 196 DCHECK(!root_folder_id_.empty()); 197 if (!HasNoParents(*entry) && !HasFolderAsParent(*entry, root_folder_id_)) 198 continue; 199 200 if (!sync_root_folder_ || LessOnCreationTime(*entry, *sync_root_folder_)) { 201 sync_root_folder_.reset(entry); 202 *itr = NULL; 203 } 204 } 205 206 // If there are more results, retrieve them. 207 if (GetRemainingFileList( 208 &cancel_callback_, 209 drive_service_, *resource_list, 210 base::Bind(&SyncEngineInitializer::DidFindSyncRoot, 211 weak_ptr_factory_.GetWeakPtr(), 212 callback))) 213 return; 214 215 if (!sync_root_folder_) { 216 CreateSyncRoot(callback); 217 return; 218 } 219 220 if (!HasNoParents(*sync_root_folder_)) { 221 DetachSyncRoot(callback); 222 return; 223 } 224 225 ListAppRootFolders(callback); 226} 227 228void SyncEngineInitializer::CreateSyncRoot(const SyncStatusCallback& callback) { 229 DCHECK(!sync_root_folder_); 230 cancel_callback_ = drive_service_->AddNewDirectory( 231 root_folder_id_, kSyncRootFolderTitle, 232 base::Bind(&SyncEngineInitializer::DidCreateSyncRoot, 233 weak_ptr_factory_.GetWeakPtr(), 234 callback)); 235} 236 237void SyncEngineInitializer::DidCreateSyncRoot( 238 const SyncStatusCallback& callback, 239 google_apis::GDataErrorCode error, 240 scoped_ptr<google_apis::ResourceEntry> entry) { 241 DCHECK(!sync_root_folder_); 242 cancel_callback_.Reset(); 243 if (error != google_apis::HTTP_SUCCESS && 244 error != google_apis::HTTP_CREATED) { 245 callback.Run(GDataErrorCodeToSyncStatusCode(error)); 246 return; 247 } 248 249 FindSyncRoot(callback); 250} 251 252void SyncEngineInitializer::DetachSyncRoot(const SyncStatusCallback& callback) { 253 DCHECK(sync_root_folder_); 254 cancel_callback_ = drive_service_->RemoveResourceFromDirectory( 255 root_folder_id_, GetID(*sync_root_folder_), 256 base::Bind(&SyncEngineInitializer::DidDetachSyncRoot, 257 weak_ptr_factory_.GetWeakPtr(), 258 callback)); 259} 260 261void SyncEngineInitializer::DidDetachSyncRoot( 262 const SyncStatusCallback& callback, 263 google_apis::GDataErrorCode error) { 264 cancel_callback_.Reset(); 265 if (error != google_apis::HTTP_SUCCESS) { 266 callback.Run(GDataErrorCodeToSyncStatusCode(error)); 267 return; 268 } 269 ListAppRootFolders(callback); 270} 271 272void SyncEngineInitializer::ListAppRootFolders( 273 const SyncStatusCallback& callback) { 274 DCHECK(sync_root_folder_); 275 cancel_callback_ = drive_service_->GetResourceListInDirectory( 276 GetID(*sync_root_folder_), 277 base::Bind(&SyncEngineInitializer::DidListAppRootFolders, 278 weak_ptr_factory_.GetWeakPtr(), 279 callback)); 280} 281 282void SyncEngineInitializer::DidListAppRootFolders( 283 const SyncStatusCallback& callback, 284 google_apis::GDataErrorCode error, 285 scoped_ptr<google_apis::ResourceList> resource_list) { 286 cancel_callback_.Reset(); 287 if (error != google_apis::HTTP_SUCCESS) { 288 callback.Run(GDataErrorCodeToSyncStatusCode(error)); 289 return; 290 } 291 292 ScopedVector<google_apis::ResourceEntry>* new_entries = 293 resource_list->mutable_entries(); 294 app_root_folders_.insert(app_root_folders_.end(), 295 new_entries->begin(), new_entries->end()); 296 new_entries->weak_clear(); 297 298 if (GetRemainingFileList( 299 &cancel_callback_, 300 drive_service_, 301 *resource_list, 302 base::Bind(&SyncEngineInitializer::DidListAppRootFolders, 303 weak_ptr_factory_.GetWeakPtr(), callback))) 304 return; 305 306 PopulateDatabase(callback); 307} 308 309void SyncEngineInitializer::PopulateDatabase( 310 const SyncStatusCallback& callback) { 311 DCHECK(sync_root_folder_); 312 metadata_database_->PopulateInitialData( 313 largest_change_id_, 314 *drive::util::ConvertResourceEntryToFileResource( 315 *sync_root_folder_), 316 ConvertResourceEntriesToFileResources(app_root_folders_), 317 base::Bind(&SyncEngineInitializer::DidPopulateDatabase, 318 weak_ptr_factory_.GetWeakPtr(), 319 callback)); 320} 321 322void SyncEngineInitializer::DidPopulateDatabase( 323 const SyncStatusCallback& callback, 324 SyncStatusCode status) { 325 if (status != SYNC_STATUS_OK) { 326 callback.Run(status); 327 return; 328 } 329 330 callback.Run(SYNC_STATUS_OK); 331} 332 333} // namespace drive_backend 334} // namespace sync_file_system 335