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/list_changes_task.h"
6 
7 #include <stddef.h>
8 #include <utility>
9 #include <vector>
10 
11 #include "base/bind.h"
12 #include "base/format_macros.h"
13 #include "base/location.h"
14 #include "base/stl_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
17 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
18 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
19 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
20 #include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h"
21 #include "chrome/browser/sync_file_system/drive_backend/sync_task_token.h"
22 #include "chrome/browser/sync_file_system/logger.h"
23 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
24 #include "components/drive/service/drive_service_interface.h"
25 #include "google_apis/drive/drive_api_parser.h"
26 
27 namespace sync_file_system {
28 namespace drive_backend {
29 
ListChangesTask(SyncEngineContext * sync_context)30 ListChangesTask::ListChangesTask(SyncEngineContext* sync_context)
31     : sync_context_(sync_context) {}
32 
~ListChangesTask()33 ListChangesTask::~ListChangesTask() {
34 }
35 
RunPreflight(std::unique_ptr<SyncTaskToken> token)36 void ListChangesTask::RunPreflight(std::unique_ptr<SyncTaskToken> token) {
37   token->InitializeTaskLog("List Changes");
38 
39   if (!IsContextReady()) {
40     token->RecordLog("Failed to get required service.");
41     SyncTaskManager::NotifyTaskDone(std::move(token), SYNC_STATUS_FAILED);
42     return;
43   }
44 
45   SyncTaskManager::UpdateTaskBlocker(
46       std::move(token), std::unique_ptr<TaskBlocker>(new TaskBlocker),
47       base::Bind(&ListChangesTask::StartListing,
48                  weak_ptr_factory_.GetWeakPtr()));
49 }
50 
StartListing(std::unique_ptr<SyncTaskToken> token)51 void ListChangesTask::StartListing(std::unique_ptr<SyncTaskToken> token) {
52   drive_service()->GetChangeList(
53       metadata_database()->GetLargestFetchedChangeID() + 1,
54       base::Bind(&ListChangesTask::DidListChanges,
55                  weak_ptr_factory_.GetWeakPtr(), base::Passed(&token)));
56 }
57 
DidListChanges(std::unique_ptr<SyncTaskToken> token,google_apis::DriveApiErrorCode error,std::unique_ptr<google_apis::ChangeList> change_list)58 void ListChangesTask::DidListChanges(
59     std::unique_ptr<SyncTaskToken> token,
60     google_apis::DriveApiErrorCode error,
61     std::unique_ptr<google_apis::ChangeList> change_list) {
62   SyncStatusCode status = DriveApiErrorCodeToSyncStatusCode(error);
63   if (status != SYNC_STATUS_OK) {
64     token->RecordLog("Failed to fetch change list.");
65     SyncTaskManager::NotifyTaskDone(std::move(token),
66                                     SYNC_STATUS_NETWORK_ERROR);
67     return;
68   }
69 
70   if (!change_list) {
71     NOTREACHED();
72     token->RecordLog("Got invalid change list.");
73     SyncTaskManager::NotifyTaskDone(std::move(token), SYNC_STATUS_FAILED);
74     return;
75   }
76 
77   auto* mutable_items = change_list->mutable_items();
78 
79   // google_apis::ChangeList can contain both FileResource and TeamDriveResource
80   // entries. We only care about FileResource entries, so filter out any entries
81   // that are TeamDriveReasource.
82   base::EraseIf(*mutable_items, [](const auto& change_resource) {
83     return change_resource->type() ==
84            google_apis::ChangeResource::ChangeType::TEAM_DRIVE;
85   });
86 
87   change_list_.reserve(change_list_.size() + mutable_items->size());
88 
89   std::move(mutable_items->begin(), mutable_items->end(),
90             std::back_inserter(change_list_));
91   change_list->mutable_items()->clear();
92 
93   if (!change_list->next_link().is_empty()) {
94     drive_service()->GetRemainingChangeList(
95         change_list->next_link(),
96         base::Bind(
97             &ListChangesTask::DidListChanges,
98             weak_ptr_factory_.GetWeakPtr(),
99             base::Passed(&token)));
100     return;
101   }
102 
103   if (change_list_.empty()) {
104     token->RecordLog("Got no change.");
105     SyncTaskManager::NotifyTaskDone(std::move(token),
106                                     SYNC_STATUS_NO_CHANGE_TO_SYNC);
107     return;
108   }
109 
110   std::unique_ptr<TaskBlocker> task_blocker(new TaskBlocker);
111   task_blocker->exclusive = true;
112   SyncTaskManager::UpdateTaskBlocker(
113       std::move(token), std::move(task_blocker),
114       base::Bind(&ListChangesTask::CheckInChangeList,
115                  weak_ptr_factory_.GetWeakPtr(),
116                  change_list->largest_change_id()));
117 }
118 
CheckInChangeList(int64_t largest_change_id,std::unique_ptr<SyncTaskToken> token)119 void ListChangesTask::CheckInChangeList(int64_t largest_change_id,
120                                         std::unique_ptr<SyncTaskToken> token) {
121   token->RecordLog(base::StringPrintf(
122       "Got %" PRIuS " changes, updating MetadataDatabase.",
123       change_list_.size()));
124 
125   DCHECK(file_ids_.empty());
126   file_ids_.reserve(change_list_.size());
127   for (size_t i = 0; i < change_list_.size(); ++i)
128     file_ids_.push_back(change_list_[i]->file_id());
129 
130   SyncStatusCode status = metadata_database()->UpdateByChangeList(
131       largest_change_id, std::move(change_list_));
132   if (status != SYNC_STATUS_OK) {
133     SyncTaskManager::NotifyTaskDone(std::move(token), status);
134     return;
135   }
136 
137   status = metadata_database()->SweepDirtyTrackers(file_ids_);
138   SyncTaskManager::NotifyTaskDone(std::move(token), status);
139 }
140 
IsContextReady()141 bool ListChangesTask::IsContextReady() {
142   return sync_context_->GetMetadataDatabase() &&
143       sync_context_->GetDriveService();
144 }
145 
metadata_database()146 MetadataDatabase* ListChangesTask::metadata_database() {
147   return sync_context_->GetMetadataDatabase();
148 }
149 
drive_service()150 drive::DriveServiceInterface* ListChangesTask::drive_service() {
151   set_used_network(true);
152   return sync_context_->GetDriveService();
153 }
154 
155 }  // namespace drive_backend
156 }  // namespace sync_file_system
157