Chromium Code Reviews| Index: chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.cc |
| diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.cc b/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.cc |
| index 9cefcf19279b4ae2e40efed3046882c1a12f90c8..1d58eb2aad6b8087b7a34780ddce35c00c38e49a 100644 |
| --- a/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.cc |
| +++ b/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.cc |
| @@ -7,23 +7,99 @@ |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/logging.h" |
| +#include "chrome/browser/drive/drive_api_service.h" |
| +#include "chrome/browser/drive/drive_api_util.h" |
| +#include "chrome/browser/google_apis/drive_api_parser.h" |
| +#include "chrome/browser/sync_file_system/drive_backend/drive_file_sync_util.h" |
| #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h" |
| namespace sync_file_system { |
| namespace drive_backend { |
| +namespace { |
| + |
| +// TODO(tzik): Move them to separate file. |
| +const char kSyncRootFolderTitle[] = "Chrome Syncable FileSystem"; |
| + |
| +// These functions touches GData WAPI classes directly. |
|
kinuko
2013/09/09 12:35:50
touches -> touch
GData WAPI classes -> google_apis
tzik
2013/09/10 06:00:42
Done.
I meant the classes in gdata_wapi_parser.h.
kinuko
2013/09/10 06:43:23
I see, then maybe you can just write like that?
"T
tzik
2013/09/10 08:45:44
Done.
|
| +bool IsDeleted(const google_apis::ResourceEntry& entry) { |
| + return entry.deleted(); |
| +} |
| + |
| +bool HasNoParents(const google_apis::ResourceEntry& entry) { |
| + return !entry.GetLinkByType(google_apis::Link::LINK_PARENT); |
| +} |
| + |
| +bool HasFolderAsParent(const google_apis::ResourceEntry& entry, |
| + const std::string& parent_id) { |
| + const ScopedVector<google_apis::Link>& links = entry.links(); |
| + for (ScopedVector<google_apis::Link>::const_iterator itr = links.begin(); |
| + itr != links.end(); ++itr) { |
| + const google_apis::Link& link = **itr; |
| + if (link.type() != google_apis::Link::LINK_PARENT) |
| + continue; |
| + if (drive::util::ExtractResourceIdFromUrl(link.href()) == parent_id) |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +bool LessOnCreationTime(const google_apis::ResourceEntry& left, |
| + const google_apis::ResourceEntry& right) { |
| + return left.published_time() < right.published_time(); |
| +} |
| + |
| +// Posts a request to continue listing. Returns false if the list don't need |
|
kinuko
2013/09/09 12:35:50
nit: don't -> doesn't
tzik
2013/09/10 06:00:42
Done.
|
| +// listing anymore. |
| +bool GetRemainingFileList( |
| + google_apis::CancelCallback* cancel_callback, |
| + drive::DriveServiceInterface* api_service, |
| + const google_apis::ResourceList& resource_list, |
| + const google_apis::GetResourceListCallback& callback) { |
| + GURL next_url; |
| + if (!resource_list.GetNextFeedURL(&next_url)) |
| + return false; |
| + |
| + *cancel_callback = api_service->GetRemainingFileList(next_url, callback); |
| + return true; |
| +} |
| + |
| +std::string GetID(const google_apis::ResourceEntry& entry) { |
| + return entry.resource_id(); |
| +} |
| + |
| +ScopedVector<google_apis::FileResource> ConvertResourceEntriesToFileResources( |
| + const ScopedVector<google_apis::ResourceEntry>& entries) { |
| + ScopedVector<google_apis::FileResource> resources; |
| + for (ScopedVector<google_apis::ResourceEntry>::const_iterator itr = |
| + entries.begin(); |
| + itr != entries.end(); |
| + ++itr) { |
| + resources.push_back( |
| + drive::util::ConvertResourceEntryToFileResource( |
| + **itr).release()); |
| + } |
| + return resources.Pass(); |
| +} |
| + |
| +} // namespace |
| + |
| SyncEngineInitializer::SyncEngineInitializer( |
| base::SequencedTaskRunner* task_runner, |
| - drive::DriveAPIService* drive_api, |
| + drive::DriveServiceInterface* drive_api, |
| const base::FilePath& database_path) |
| : task_runner_(task_runner), |
| drive_api_(drive_api), |
| database_path_(database_path), |
| + largest_change_id_(0), |
| weak_ptr_factory_(this) { |
| + DCHECK(task_runner); |
| + DCHECK(drive_api_); |
| } |
| SyncEngineInitializer::~SyncEngineInitializer() { |
| - NOTIMPLEMENTED(); |
| + if (!cancel_callback_.is_null()) |
| + cancel_callback_.Run(); |
| } |
| void SyncEngineInitializer::Run(const SyncStatusCallback& callback) { |
| @@ -33,6 +109,10 @@ void SyncEngineInitializer::Run(const SyncStatusCallback& callback) { |
| weak_ptr_factory_.GetWeakPtr(), callback)); |
| } |
| +scoped_ptr<MetadataDatabase> SyncEngineInitializer::PassMetadataDatabase() { |
| + return metadata_database_.Pass(); |
| +} |
| + |
| void SyncEngineInitializer::DidCreateMetadataDatabase( |
| const SyncStatusCallback& callback, |
| SyncStatusCode status, |
| @@ -43,12 +123,206 @@ void SyncEngineInitializer::DidCreateMetadataDatabase( |
| } |
| metadata_database_ = instance.Pass(); |
| + if (metadata_database_->HasSyncRoot()) { |
| + callback.Run(SYNC_STATUS_OK); |
| + return; |
| + } |
| + |
| + GetAboutResource(callback); |
| +} |
| + |
| +void SyncEngineInitializer::GetAboutResource( |
| + const SyncStatusCallback& callback) { |
| + drive_api_->GetAboutResource( |
| + base::Bind(&SyncEngineInitializer::DidGetAboutResource, |
| + weak_ptr_factory_.GetWeakPtr(), callback)); |
| +} |
| + |
| +void SyncEngineInitializer::DidGetAboutResource( |
| + const SyncStatusCallback& callback, |
| + google_apis::GDataErrorCode error, |
| + scoped_ptr<google_apis::AboutResource> about_resource) { |
| + cancel_callback_.Reset(); |
| + if (error != google_apis::HTTP_SUCCESS) { |
| + callback.Run(GDataErrorCodeToSyncStatusCode(error)); |
| + return; |
| + } |
| + |
| + DCHECK(about_resource); |
| + root_folder_id_ = about_resource->root_folder_id(); |
| + largest_change_id_ = about_resource->largest_change_id(); |
| + |
| + DCHECK(!root_folder_id_.empty()); |
| + FindSyncRoot(callback); |
| +} |
| + |
| +void SyncEngineInitializer::FindSyncRoot(const SyncStatusCallback& callback) { |
| + cancel_callback_ = drive_api_->SearchByTitle( |
| + kSyncRootFolderTitle, |
| + std::string(), // parent_folder_id |
| + base::Bind(&SyncEngineInitializer::DidFindSyncRoot, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + callback)); |
| +} |
| + |
| +void SyncEngineInitializer::DidFindSyncRoot( |
| + const SyncStatusCallback& callback, |
| + google_apis::GDataErrorCode error, |
| + scoped_ptr<google_apis::ResourceList> resource_list) { |
| + cancel_callback_.Reset(); |
| + if (error != google_apis::HTTP_SUCCESS) { |
| + callback.Run(GDataErrorCodeToSyncStatusCode(error)); |
| + return; |
| + } |
| + |
| + ScopedVector<google_apis::ResourceEntry>* entries = |
| + resource_list->mutable_entries(); |
| + for (ScopedVector<google_apis::ResourceEntry>::iterator itr = |
| + entries->begin(); |
| + itr != entries->end(); ++itr) { |
| + google_apis::ResourceEntry* entry = *itr; |
| + |
| + // Ignore deleted folder. |
| + if (IsDeleted(*entry)) |
| + continue; |
| + |
| + // Pick an orphaned folder or a direct child of the the root folder and |
|
nhiroki
2013/09/09 14:21:57
"the the" -> "the"
tzik
2013/09/10 06:00:42
Done.
|
| + // ignore others. |
| + DCHECK(!root_folder_id_.empty()); |
| + if (!HasNoParents(*entry) && !HasFolderAsParent(*entry, root_folder_id_)) |
| + continue; |
| + |
| + if (!sync_root_folder_ || LessOnCreationTime(*entry, *sync_root_folder_)) { |
| + sync_root_folder_.reset(entry); |
| + *itr = NULL; |
| + } |
| + } |
| + |
| + // If there are more result, retrieve them. |
|
nhiroki
2013/09/09 14:21:57
"result" -> "results"
tzik
2013/09/10 06:00:42
Done.
|
| + if (GetRemainingFileList( |
| + &cancel_callback_, |
| + drive_api_, *resource_list, |
| + base::Bind(&SyncEngineInitializer::DidFindSyncRoot, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + callback))) |
| + return; |
| + |
| + if (!sync_root_folder_) { |
| + CreateSyncRoot(callback); |
| + return; |
| + } |
| + |
| + if (!HasNoParents(*sync_root_folder_)) { |
| + DetachSyncRoot(callback); |
| + return; |
| + } |
| + |
| + ListAppRootFolders(callback); |
| +} |
| + |
| +void SyncEngineInitializer::CreateSyncRoot(const SyncStatusCallback& callback) { |
| + cancel_callback_ = drive_api_->AddNewDirectory( |
| + root_folder_id_, kSyncRootFolderTitle, |
| + base::Bind(&SyncEngineInitializer::DidCreateSyncRoot, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + callback)); |
| +} |
| + |
| +void SyncEngineInitializer::DidCreateSyncRoot( |
| + const SyncStatusCallback& callback, |
| + google_apis::GDataErrorCode error, |
| + scoped_ptr<google_apis::ResourceEntry> entry) { |
| + cancel_callback_.Reset(); |
| + if (error != google_apis::HTTP_SUCCESS && |
| + error != google_apis::HTTP_CREATED) { |
| + callback.Run(GDataErrorCodeToSyncStatusCode(error)); |
| + return; |
| + } |
| + |
| + FindSyncRoot(callback); |
| +} |
| + |
| +void SyncEngineInitializer::DetachSyncRoot(const SyncStatusCallback& callback) { |
|
nhiroki
2013/09/09 14:21:57
Can we have "DCHECK(sync_root_folder_);" here?
tzik
2013/09/10 06:00:42
Done.
|
| + cancel_callback_ = drive_api_->RemoveResourceFromDirectory( |
| + root_folder_id_, GetID(*sync_root_folder_), |
| + base::Bind(&SyncEngineInitializer::DidDetachSyncRoot, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + callback)); |
| +} |
| + |
| +void SyncEngineInitializer::DidDetachSyncRoot( |
| + const SyncStatusCallback& callback, |
| + google_apis::GDataErrorCode error) { |
| + cancel_callback_.Reset(); |
| + if (error != google_apis::HTTP_SUCCESS) { |
| + callback.Run(GDataErrorCodeToSyncStatusCode(error)); |
| + return; |
| + } |
| + ListAppRootFolders(callback); |
| +} |
| + |
| +void SyncEngineInitializer::ListAppRootFolders( |
| + const SyncStatusCallback& callback) { |
| + DCHECK(sync_root_folder_); |
| + cancel_callback_ = drive_api_->GetResourceListInDirectory( |
| + GetID(*sync_root_folder_), |
| + base::Bind(&SyncEngineInitializer::DidListAppRootFolders, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + callback)); |
| +} |
| + |
| +void SyncEngineInitializer::DidListAppRootFolders( |
| + const SyncStatusCallback& callback, |
| + google_apis::GDataErrorCode error, |
| + scoped_ptr<google_apis::ResourceList> resource_list) { |
| + cancel_callback_.Reset(); |
| + if (error != google_apis::HTTP_SUCCESS) { |
| + callback.Run(GDataErrorCodeToSyncStatusCode(error)); |
| + return; |
| + } |
| + |
| + ScopedVector<google_apis::ResourceEntry>* new_entries = |
| + resource_list->mutable_entries(); |
| + app_root_folders_.insert(app_root_folders_.end(), |
| + new_entries->begin(), new_entries->end()); |
| + new_entries->weak_clear(); |
| + |
| + if (GetRemainingFileList( |
| + &cancel_callback_, |
| + drive_api_, |
| + *resource_list, |
| + base::Bind(&SyncEngineInitializer::DidListAppRootFolders, |
| + weak_ptr_factory_.GetWeakPtr(), callback))) |
| + return; |
| - // TODO(tzik): Set up sync root and populate database with initial folder |
| - // tree. |
| + PopulateDatabase(callback); |
| +} |
| + |
| +void SyncEngineInitializer::PopulateDatabase( |
| + const SyncStatusCallback& callback) { |
| + metadata_database_->PopulateInitialData( |
| + largest_change_id_, |
| + *drive::util::ConvertResourceEntryToFileResource( |
| + *sync_root_folder_), |
| + ConvertResourceEntriesToFileResources(app_root_folders_), |
| + base::Bind(&SyncEngineInitializer::DidPopulateDatabase, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + callback)); |
| +} |
| + |
| +void SyncEngineInitializer::DidPopulateDatabase( |
| + const SyncStatusCallback& callback, |
| + SyncStatusCode status) { |
| + if (status != SYNC_STATUS_OK) { |
| + callback.Run(status); |
| + return; |
| + } |
| + |
| + Finish(callback); |
| +} |
| - NOTIMPLEMENTED(); |
| - callback.Run(SYNC_STATUS_FAILED); |
| +void SyncEngineInitializer::Finish(const SyncStatusCallback& callback) { |
| + callback.Run(SYNC_STATUS_OK); |
|
kinuko
2013/09/09 12:35:50
Does this indirection have some meaning?
tzik
2013/09/10 06:00:42
Deleted.
This was meaningful only for a deleted c
|
| } |
| } // namespace drive_backend |