list_changes_task.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
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 "base/bind.h"
8#include "base/format_macros.h"
9#include "base/location.h"
10#include "chrome/browser/drive/drive_api_util.h"
11#include "chrome/browser/drive/drive_service_interface.h"
12#include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
13#include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
14#include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
15#include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
16#include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h"
17#include "chrome/browser/sync_file_system/drive_backend/sync_task_token.h"
18#include "chrome/browser/sync_file_system/logger.h"
19#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
20#include "google_apis/drive/drive_api_parser.h"
21#include "google_apis/drive/gdata_wapi_parser.h"
22
23namespace sync_file_system {
24namespace drive_backend {
25
26namespace {
27
28scoped_ptr<google_apis::ChangeResource> ConvertResourceEntryToChangeResource(
29    const google_apis::ResourceEntry& entry) {
30  scoped_ptr<google_apis::ChangeResource> out(new google_apis::ChangeResource);
31  out->set_file_id(entry.resource_id());
32  if (!entry.deleted())
33    out->set_file(drive::util::ConvertResourceEntryToFileResource(entry));
34  out->set_change_id(entry.changestamp());
35  out->set_deleted(entry.deleted());
36
37  return out.Pass();
38}
39
40}  // namespace
41
42ListChangesTask::ListChangesTask(SyncEngineContext* sync_context)
43    : sync_context_(sync_context),
44      weak_ptr_factory_(this) {
45}
46
47ListChangesTask::~ListChangesTask() {
48}
49
50void ListChangesTask::RunPreflight(scoped_ptr<SyncTaskToken> token) {
51  util::Log(logging::LOG_VERBOSE, FROM_HERE, "[Changes] Start.");
52
53  if (!IsContextReady()) {
54    util::Log(logging::LOG_VERBOSE, FROM_HERE,
55              "[Changes] Failed to get required service.");
56    RunSoon(FROM_HERE, base::Bind(&SyncTaskManager::NotifyTaskDone,
57                                  base::Passed(&token),
58                                  SYNC_STATUS_FAILED));
59    return;
60  }
61
62  SyncTaskManager::UpdateBlockingFactor(
63      token.Pass(),
64      scoped_ptr<BlockingFactor>(new BlockingFactor),
65      base::Bind(&ListChangesTask::StartListing,
66                 weak_ptr_factory_.GetWeakPtr()));
67}
68
69void ListChangesTask::StartListing(scoped_ptr<SyncTaskToken> token) {
70  drive_service()->GetChangeList(
71      metadata_database()->GetLargestFetchedChangeID() + 1,
72      base::Bind(&ListChangesTask::DidListChanges,
73                 weak_ptr_factory_.GetWeakPtr(), base::Passed(&token)));
74}
75
76void ListChangesTask::DidListChanges(
77    scoped_ptr<SyncTaskToken> token,
78    google_apis::GDataErrorCode error,
79    scoped_ptr<google_apis::ResourceList> resource_list) {
80  SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
81  if (status != SYNC_STATUS_OK) {
82    util::Log(logging::LOG_VERBOSE, FROM_HERE,
83              "[Changes] Failed to fetch change list.");
84    SyncTaskManager::NotifyTaskDone(
85        token.Pass(), SYNC_STATUS_NETWORK_ERROR);
86    return;
87  }
88
89  if (!resource_list) {
90    NOTREACHED();
91    util::Log(logging::LOG_VERBOSE, FROM_HERE,
92              "[Changes] Got invalid change list.");
93    SyncTaskManager::NotifyTaskDone(
94        token.Pass(), SYNC_STATUS_FAILED);
95    return;
96  }
97
98  change_list_.reserve(change_list_.size() + resource_list->entries().size());
99  for (size_t i = 0; i < resource_list->entries().size(); ++i) {
100    change_list_.push_back(ConvertResourceEntryToChangeResource(
101        *resource_list->entries()[i]).release());
102  }
103
104  GURL next_feed;
105  if (resource_list->GetNextFeedURL(&next_feed)) {
106    drive_service()->GetRemainingChangeList(
107        next_feed,
108        base::Bind(
109            &ListChangesTask::DidListChanges,
110            weak_ptr_factory_.GetWeakPtr(),
111            base::Passed(&token)));
112    return;
113  }
114
115  if (change_list_.empty()) {
116    util::Log(logging::LOG_VERBOSE, FROM_HERE, "[Changes] Got no change.");
117    SyncTaskManager::NotifyTaskDone(
118        token.Pass(), SYNC_STATUS_NO_CHANGE_TO_SYNC);
119    return;
120  }
121
122  scoped_ptr<BlockingFactor> blocking_factor(new BlockingFactor);
123  blocking_factor->exclusive = true;
124  SyncTaskManager::UpdateBlockingFactor(
125      token.Pass(),
126      blocking_factor.Pass(),
127      base::Bind(&ListChangesTask::CheckInChangeList,
128                 weak_ptr_factory_.GetWeakPtr(),
129                 resource_list->largest_changestamp()));
130}
131
132void ListChangesTask::CheckInChangeList(int64 largest_change_id,
133                                        scoped_ptr<SyncTaskToken> token) {
134  util::Log(logging::LOG_VERBOSE, FROM_HERE,
135            "[Changes] Got %" PRIuS " changes, updating MetadataDatabase.",
136            change_list_.size());
137  metadata_database()->UpdateByChangeList(
138      largest_change_id,
139      change_list_.Pass(),
140      base::Bind(&SyncTaskManager::NotifyTaskDone, base::Passed(&token)));
141}
142
143bool ListChangesTask::IsContextReady() {
144  return sync_context_->GetMetadataDatabase() &&
145      sync_context_->GetDriveService();
146}
147
148MetadataDatabase* ListChangesTask::metadata_database() {
149  return sync_context_->GetMetadataDatabase();
150}
151
152drive::DriveServiceInterface* ListChangesTask::drive_service() {
153  set_used_network(true);
154  return sync_context_->GetDriveService();
155}
156
157}  // namespace drive_backend
158}  // namespace sync_file_system
159