list_changes_task.cc revision e5d81f57cb97b3b6b7fccc9c5610d21eb81db09d
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  drive_service()->GetChangeList(
63      metadata_database()->GetLargestFetchedChangeID() + 1,
64      base::Bind(&ListChangesTask::DidListChanges,
65                 weak_ptr_factory_.GetWeakPtr(), base::Passed(&token)));
66}
67
68void ListChangesTask::DidListChanges(
69    scoped_ptr<SyncTaskToken> token,
70    google_apis::GDataErrorCode error,
71    scoped_ptr<google_apis::ResourceList> resource_list) {
72  SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
73  if (status != SYNC_STATUS_OK) {
74    util::Log(logging::LOG_VERBOSE, FROM_HERE,
75              "[Changes] Failed to fetch change list.");
76    SyncTaskManager::NotifyTaskDone(
77        token.Pass(), SYNC_STATUS_NETWORK_ERROR);
78    return;
79  }
80
81  if (!resource_list) {
82    NOTREACHED();
83    util::Log(logging::LOG_VERBOSE, FROM_HERE,
84              "[Changes] Got invalid change list.");
85    SyncTaskManager::NotifyTaskDone(
86        token.Pass(), SYNC_STATUS_FAILED);
87    return;
88  }
89
90  change_list_.reserve(change_list_.size() + resource_list->entries().size());
91  for (size_t i = 0; i < resource_list->entries().size(); ++i) {
92    change_list_.push_back(ConvertResourceEntryToChangeResource(
93        *resource_list->entries()[i]).release());
94  }
95
96  // TODO(tzik): http://crbug.com/310964
97  // This may take long time to run in single task.  Run this as a background
98  // task.
99  GURL next_feed;
100  if (resource_list->GetNextFeedURL(&next_feed)) {
101    drive_service()->GetRemainingChangeList(
102        next_feed,
103        base::Bind(
104            &ListChangesTask::DidListChanges,
105            weak_ptr_factory_.GetWeakPtr(),
106            base::Passed(&token)));
107    return;
108  }
109
110  if (change_list_.empty()) {
111    util::Log(logging::LOG_VERBOSE, FROM_HERE, "[Changes] Got no change.");
112    SyncTaskManager::NotifyTaskDone(
113        token.Pass(), SYNC_STATUS_NO_CHANGE_TO_SYNC);
114    return;
115  }
116
117  util::Log(logging::LOG_VERBOSE, FROM_HERE,
118            "[Changes] Got %" PRIuS " changes, updating MetadataDatabase.",
119            change_list_.size());
120  metadata_database()->UpdateByChangeList(
121      resource_list->largest_changestamp(),
122      change_list_.Pass(),
123      base::Bind(&SyncTaskManager::NotifyTaskDone, base::Passed(&token)));
124}
125
126bool ListChangesTask::IsContextReady() {
127  return sync_context_->GetMetadataDatabase() &&
128      sync_context_->GetDriveService();
129}
130
131MetadataDatabase* ListChangesTask::metadata_database() {
132  return sync_context_->GetMetadataDatabase();
133}
134
135drive::DriveServiceInterface* ListChangesTask::drive_service() {
136  set_used_network(true);
137  return sync_context_->GetDriveService();
138}
139
140}  // namespace drive_backend
141}  // namespace sync_file_system
142