chromium/chromeos/ash/components/drivefs/drivefs_search_query.cc

// 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