// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/ash/components/drivefs/drivefs_search_query.h"
#include <optional>
#include <utility>
#include <vector>
#include "base/functional/bind.h"
#include "base/memory/weak_ptr.h"
#include "chromeos/ash/components/drivefs/drivefs_search_query_delegate.h"
#include "chromeos/ash/components/drivefs/mojom/drivefs.mojom.h"
#include "components/drive/file_errors.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace drivefs {
namespace {
bool IsCloudSharedWithMeQuery(const drivefs::mojom::QueryParametersPtr& query) {
return query->query_source ==
drivefs::mojom::QueryParameters::QuerySource::kCloudOnly &&
query->shared_with_me && !query->text_content && !query->title;
}
} // namespace
DriveFsSearchQuery::DriveFsSearchQuery(
base::WeakPtr<DriveFsSearchQueryDelegate> delegate,
mojom::QueryParametersPtr query)
: delegate_(std::move(delegate)), query_(std::move(query)) {
Init();
}
DriveFsSearchQuery::~DriveFsSearchQuery() = default;
mojom::QueryParameters::QuerySource DriveFsSearchQuery::source() {
return query_->query_source;
}
void DriveFsSearchQuery::Init() {
remote_.reset();
if (delegate_ == nullptr) {
return;
}
// The only cacheable query is 'shared with me'.
if (IsCloudSharedWithMeQuery(query_)) {
// Check if we should have the response cached.
if (delegate_->WithinQueryCacheTtl()) {
query_->query_source =
drivefs::mojom::QueryParameters::QuerySource::kLocalOnly;
}
}
if (delegate_->IsOffline() &&
query_->query_source !=
drivefs::mojom::QueryParameters::QuerySource::kLocalOnly) {
// No point trying cloud query if we know we are offline.
AdjustQueryForOffline();
}
delegate_->StartMojoSearchQuery(remote_.BindNewPipeAndPassReceiver(),
query_.Clone());
}
void DriveFsSearchQuery::GetNextPage(
mojom::SearchQuery::GetNextPageCallback callback) {
// `remote_` might not be bound if `delegate_` was null when `Init()` was
// called.
if (remote_.is_bound()) {
remote_->GetNextPage(mojo::WrapCallbackWithDefaultInvokeIfNotRun(
base::BindOnce(&DriveFsSearchQuery::OnGetNextPage,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
drive::FILE_ERROR_ABORT, std::nullopt));
} else {
OnGetNextPage(std::move(callback), drive::FILE_ERROR_ABORT, std::nullopt);
}
}
void DriveFsSearchQuery::OnGetNextPage(
mojom::SearchQuery::GetNextPageCallback callback,
drive::FileError error,
std::optional<std::vector<drivefs::mojom::QueryItemPtr>> items) {
if (!first_page_returned_ && error == drive::FILE_ERROR_NO_CONNECTION &&
query_->query_source !=
drivefs::mojom::QueryParameters::QuerySource::kLocalOnly) {
// Retry with offline query only if we have never returned any pages.
AdjustQueryForOffline();
Init();
GetNextPage(std::move(callback));
return;
}
if (delegate_ != nullptr && error == drive::FILE_ERROR_OK &&
IsCloudSharedWithMeQuery(query_)) {
// Mark that DriveFS should have cached the required info.
delegate_->UpdateLastSharedWithMeResponse();
}
if (drive::IsFileErrorOk(error)) {
first_page_returned_ = true;
}
std::move(callback).Run(error, std::move(items));
}
void DriveFsSearchQuery::AdjustQueryForOffline() {
query_->query_source =
drivefs::mojom::QueryParameters::QuerySource::kLocalOnly;
if (query_->text_content) {
// Full-text searches not supported offline.
std::swap(query_->text_content, query_->title);
query_->text_content.reset();
}
}
} // namespace drivefs