Home | History | Annotate | Download | only in file_system
      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 
     24 using content::BrowserThread;
     25 
     26 namespace drive {
     27 namespace file_system {
     28 namespace {
     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.
     34 FileError 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 
     83 SearchOperation::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 
     95 SearchOperation::~SearchOperation() {
     96 }
     97 
     98 void 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 
    119 void 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 
    165 void 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