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/chromeos/drive/file_system/search_operation.h" 6 7#include <string> 8#include <vector> 9 10#include "base/bind.h" 11#include "base/bind_helpers.h" 12#include "base/callback.h" 13#include "base/task_runner_util.h" 14#include "chrome/browser/chromeos/drive/change_list_loader.h" 15#include "chrome/browser/chromeos/drive/file_system_util.h" 16#include "chrome/browser/chromeos/drive/job_scheduler.h" 17#include "chrome/browser/chromeos/drive/resource_entry_conversion.h" 18#include "chrome/browser/chromeos/drive/resource_metadata.h" 19#include "chrome/browser/drive/drive_api_util.h" 20#include "content/public/browser/browser_thread.h" 21#include "google_apis/drive/drive_api_parser.h" 22#include "url/gurl.h" 23 24using content::BrowserThread; 25 26namespace drive { 27namespace file_system { 28namespace { 29 30// Computes the path of each item in |file_list| returned from the server 31// and stores to |result|, by using |resource_metadata|. If the metadata is not 32// up-to-date and did not contain an item, adds the item to "drive/other" for 33// temporally assigning a path. 34FileError ResolveSearchResultOnBlockingPool( 35 internal::ResourceMetadata* resource_metadata, 36 scoped_ptr<google_apis::FileList> file_list, 37 std::vector<SearchResultInfo>* result) { 38 DCHECK(resource_metadata); 39 DCHECK(result); 40 41 const ScopedVector<google_apis::FileResource>& entries = file_list->items(); 42 result->reserve(entries.size()); 43 for (size_t i = 0; i < entries.size(); ++i) { 44 std::string local_id; 45 FileError error = resource_metadata->GetIdByResourceId( 46 entries[i]->file_id(), &local_id); 47 48 ResourceEntry entry; 49 if (error == FILE_ERROR_OK) 50 error = resource_metadata->GetResourceEntryById(local_id, &entry); 51 52 if (error == FILE_ERROR_NOT_FOUND) { 53 std::string original_parent_id; 54 if (!ConvertFileResourceToResourceEntry(*entries[i], &entry, 55 &original_parent_id)) 56 continue; // Skip non-file entries. 57 58 // The result is absent in local resource metadata. This can happen if 59 // the metadata is not synced to the latest server state yet. In that 60 // case, we temporarily add the file to the special "drive/other" 61 // directory in order to assign a path, which is needed to access the 62 // file through FileSystem API. 63 // 64 // It will be moved to the right place when the metadata gets synced 65 // in normal loading process in ChangeListProcessor. 66 entry.set_parent_local_id(util::kDriveOtherDirLocalId); 67 error = resource_metadata->AddEntry(entry, &local_id); 68 } 69 if (error != FILE_ERROR_OK) 70 return error; 71 base::FilePath path; 72 error = resource_metadata->GetFilePath(local_id, &path); 73 if (error != FILE_ERROR_OK) 74 return error; 75 result->push_back(SearchResultInfo(path, entry.file_info().is_directory())); 76 } 77 78 return FILE_ERROR_OK; 79} 80 81} // namespace 82 83SearchOperation::SearchOperation( 84 base::SequencedTaskRunner* blocking_task_runner, 85 JobScheduler* scheduler, 86 internal::ResourceMetadata* metadata, 87 internal::LoaderController* loader_controller) 88 : blocking_task_runner_(blocking_task_runner), 89 scheduler_(scheduler), 90 metadata_(metadata), 91 loader_controller_(loader_controller), 92 weak_ptr_factory_(this) { 93} 94 95SearchOperation::~SearchOperation() { 96} 97 98void SearchOperation::Search(const std::string& search_query, 99 const GURL& next_link, 100 const SearchCallback& callback) { 101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 102 DCHECK(!callback.is_null()); 103 104 if (next_link.is_empty()) { 105 // This is first request for the |search_query|. 106 scheduler_->Search( 107 search_query, 108 base::Bind(&SearchOperation::SearchAfterGetFileList, 109 weak_ptr_factory_.GetWeakPtr(), callback)); 110 } else { 111 // There is the remaining result so fetch it. 112 scheduler_->GetRemainingFileList( 113 next_link, 114 base::Bind(&SearchOperation::SearchAfterGetFileList, 115 weak_ptr_factory_.GetWeakPtr(), callback)); 116 } 117} 118 119void SearchOperation::SearchAfterGetFileList( 120 const SearchCallback& callback, 121 google_apis::GDataErrorCode gdata_error, 122 scoped_ptr<google_apis::FileList> file_list) { 123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 124 DCHECK(!callback.is_null()); 125 126 FileError error = GDataToFileError(gdata_error); 127 if (error != FILE_ERROR_OK) { 128 callback.Run(error, GURL(), scoped_ptr<std::vector<SearchResultInfo> >()); 129 return; 130 } 131 132 DCHECK(file_list); 133 134 GURL next_url = file_list->next_link(); 135 136 scoped_ptr<std::vector<SearchResultInfo> > result( 137 new std::vector<SearchResultInfo>); 138 if (file_list->items().empty()) { 139 // Short cut. If the resource entry is empty, we don't need to refresh 140 // the resource metadata. 141 callback.Run(FILE_ERROR_OK, next_url, result.Pass()); 142 return; 143 } 144 145 // ResolveSearchResultOnBlockingPool() may add entries newly created on the 146 // server to the local metadata. 147 // This may race with sync tasks so we should ask LoaderController here. 148 std::vector<SearchResultInfo>* result_ptr = result.get(); 149 loader_controller_->ScheduleRun(base::Bind( 150 base::IgnoreResult( 151 &base::PostTaskAndReplyWithResult<FileError, FileError>), 152 blocking_task_runner_, 153 FROM_HERE, 154 base::Bind(&ResolveSearchResultOnBlockingPool, 155 metadata_, 156 base::Passed(&file_list), 157 result_ptr), 158 base::Bind(&SearchOperation::SearchAfterResolveSearchResult, 159 weak_ptr_factory_.GetWeakPtr(), 160 callback, 161 next_url, 162 base::Passed(&result)))); 163} 164 165void SearchOperation::SearchAfterResolveSearchResult( 166 const SearchCallback& callback, 167 const GURL& next_link, 168 scoped_ptr<std::vector<SearchResultInfo> > result, 169 FileError error) { 170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 171 DCHECK(!callback.is_null()); 172 DCHECK(result); 173 174 if (error != FILE_ERROR_OK) { 175 callback.Run(error, GURL(), scoped_ptr<std::vector<SearchResultInfo> >()); 176 return; 177 } 178 179 callback.Run(error, next_link, result.Pass()); 180} 181 182} // namespace file_system 183} // namespace drive 184