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