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.
5 #include "components/drive/file_system/search_operation.h"
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 "components/drive/change_list_loader.h"
15 #include "components/drive/drive_api_util.h"
16 #include "components/drive/file_system_core_util.h"
17 #include "components/drive/job_scheduler.h"
18 #include "components/drive/resource_entry_conversion.h"
19 #include "components/drive/resource_metadata.h"
20 #include "google_apis/drive/drive_api_parser.h"
24 namespace file_system
{
27 // Computes the path of each item in |file_list| returned from the server
28 // and stores to |result|, by using |resource_metadata|. If the metadata is not
29 // up-to-date and did not contain an item, adds the item to "drive/other" for
30 // temporally assigning a path.
31 FileError
ResolveSearchResultOnBlockingPool(
32 internal::ResourceMetadata
* resource_metadata
,
33 scoped_ptr
<google_apis::FileList
> file_list
,
34 std::vector
<SearchResultInfo
>* result
) {
35 DCHECK(resource_metadata
);
38 const ScopedVector
<google_apis::FileResource
>& entries
= file_list
->items();
39 result
->reserve(entries
.size());
40 for (size_t i
= 0; i
< entries
.size(); ++i
) {
42 FileError error
= resource_metadata
->GetIdByResourceId(
43 entries
[i
]->file_id(), &local_id
);
46 if (error
== FILE_ERROR_OK
)
47 error
= resource_metadata
->GetResourceEntryById(local_id
, &entry
);
49 if (error
== FILE_ERROR_NOT_FOUND
) {
50 std::string original_parent_id
;
51 if (!ConvertFileResourceToResourceEntry(*entries
[i
], &entry
,
53 continue; // Skip non-file entries.
55 // The result is absent in local resource metadata. This can happen if
56 // the metadata is not synced to the latest server state yet. In that
57 // case, we temporarily add the file to the special "drive/other"
58 // directory in order to assign a path, which is needed to access the
59 // file through FileSystem API.
61 // It will be moved to the right place when the metadata gets synced
62 // in normal loading process in ChangeListProcessor.
63 entry
.set_parent_local_id(util::kDriveOtherDirLocalId
);
64 error
= resource_metadata
->AddEntry(entry
, &local_id
);
66 if (error
!= FILE_ERROR_OK
)
69 error
= resource_metadata
->GetFilePath(local_id
, &path
);
70 if (error
!= FILE_ERROR_OK
)
72 result
->push_back(SearchResultInfo(path
, entry
.file_info().is_directory()));
80 SearchOperation::SearchOperation(
81 base::SequencedTaskRunner
* blocking_task_runner
,
82 JobScheduler
* scheduler
,
83 internal::ResourceMetadata
* metadata
,
84 internal::LoaderController
* loader_controller
)
85 : blocking_task_runner_(blocking_task_runner
),
86 scheduler_(scheduler
),
88 loader_controller_(loader_controller
),
89 weak_ptr_factory_(this) {
92 SearchOperation::~SearchOperation() {
95 void SearchOperation::Search(const std::string
& search_query
,
96 const GURL
& next_link
,
97 const SearchCallback
& callback
) {
98 DCHECK(thread_checker_
.CalledOnValidThread());
99 DCHECK(!callback
.is_null());
101 if (next_link
.is_empty()) {
102 // This is first request for the |search_query|.
105 base::Bind(&SearchOperation::SearchAfterGetFileList
,
106 weak_ptr_factory_
.GetWeakPtr(), callback
));
108 // There is the remaining result so fetch it.
109 scheduler_
->GetRemainingFileList(
111 base::Bind(&SearchOperation::SearchAfterGetFileList
,
112 weak_ptr_factory_
.GetWeakPtr(), callback
));
116 void SearchOperation::SearchAfterGetFileList(
117 const SearchCallback
& callback
,
118 google_apis::DriveApiErrorCode gdata_error
,
119 scoped_ptr
<google_apis::FileList
> file_list
) {
120 DCHECK(thread_checker_
.CalledOnValidThread());
121 DCHECK(!callback
.is_null());
123 FileError error
= GDataToFileError(gdata_error
);
124 if (error
!= FILE_ERROR_OK
) {
125 callback
.Run(error
, GURL(), scoped_ptr
<std::vector
<SearchResultInfo
> >());
131 GURL next_url
= file_list
->next_link();
133 scoped_ptr
<std::vector
<SearchResultInfo
> > result(
134 new std::vector
<SearchResultInfo
>);
135 if (file_list
->items().empty()) {
136 // Short cut. If the resource entry is empty, we don't need to refresh
137 // the resource metadata.
138 callback
.Run(FILE_ERROR_OK
, next_url
, result
.Pass());
142 // ResolveSearchResultOnBlockingPool() may add entries newly created on the
143 // server to the local metadata.
144 // This may race with sync tasks so we should ask LoaderController here.
145 std::vector
<SearchResultInfo
>* result_ptr
= result
.get();
146 loader_controller_
->ScheduleRun(base::Bind(
148 &base::PostTaskAndReplyWithResult
<FileError
, FileError
>),
149 blocking_task_runner_
,
151 base::Bind(&ResolveSearchResultOnBlockingPool
,
153 base::Passed(&file_list
),
155 base::Bind(&SearchOperation::SearchAfterResolveSearchResult
,
156 weak_ptr_factory_
.GetWeakPtr(),
159 base::Passed(&result
))));
162 void SearchOperation::SearchAfterResolveSearchResult(
163 const SearchCallback
& callback
,
164 const GURL
& next_link
,
165 scoped_ptr
<std::vector
<SearchResultInfo
> > result
,
167 DCHECK(thread_checker_
.CalledOnValidThread());
168 DCHECK(!callback
.is_null());
171 if (error
!= FILE_ERROR_OK
) {
172 callback
.Run(error
, GURL(), scoped_ptr
<std::vector
<SearchResultInfo
> >());
176 callback
.Run(error
, next_link
, result
.Pass());
179 } // namespace file_system