chromium/chromeos/ash/components/file_manager/indexing/file_index_service.h

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

#ifndef CHROMEOS_ASH_COMPONENTS_FILE_MANAGER_INDEXING_FILE_INDEX_SERVICE_H_
#define CHROMEOS_ASH_COMPONENTS_FILE_MANAGER_INDEXING_FILE_INDEX_SERVICE_H_

#include <vector>

#include "base/component_export.h"
#include "base/files/file_path.h"
#include "base/threading/sequence_bound.h"
#include "chromeos/ash/components/file_manager/indexing/file_index.h"
#include "chromeos/ash/components/file_manager/indexing/file_info.h"
#include "chromeos/ash/components/file_manager/indexing/query.h"
#include "chromeos/ash/components/file_manager/indexing/term.h"
#include "url/gurl.h"

namespace ash::file_manager {

// The type of callback on which search results are reported.
typedef base::OnceCallback<void(SearchResults)> SearchResultsCallback;

// The type of callback on which operations that manipulate terms, files or
// initialize the index are reported.
typedef base::OnceCallback<void(OpResults)> IndexingOperationCallback;

// A file indexing service. The main task of this service is to efficiently
// associate terms with files. Instead of using files directly, we rely on
// the FileInfo class, which stores file's URL, size and modification time.
// Terms are pairs of field:text, where field identifies where the text is
// coming from. For example, if text is derived from the files content, the
// field can be "content". if the text is a label added to the file, the field
// could be "label".
//
// A typical use of the index is to register file via the PutFileInfo() method
// followed by a call SetTerms() for files, which creates association between
// terms and passed file info. Later, those files can be efficiently retrieved
// by calling the Search() method and passing a query to it. If the underlying
// file is removed from the file system, the RemoveFile() method can be called
// with the URL of the file to purge it from the index.
//
// FileIndexService* service = FileIndexServiceFactory::GetForBrowserContext(
//    context);
// service->PutFileInfo(pinned_file_info,
//                      base::BindOnce([](OpResults results) {
//                        if (results != OpResults::kSuccess) { ... }
//                      }));
// service->PutFileInfo(downloaded_file_info,
//                      base::BindOnce([](OpResults results) {
//                        if (results != OpResults::kSuccess) { ... }
//                      }));
// service->SetTerms({Term("label", "pinned")},
//                    pinned_file_info.file_url,
//                    base::BindOnce([](OpResults results) {
//                      if (results != OpResults::kSuccess) { ... }
//                    }));
// service->AddTerms({Term("label", "downloaded")},
//                    downloaded_file_info.file_url,
//                    base::BindOnce([](OpResults results) {
//                      if (results != OpResults::kSuccess) { ... }
//                    }));
// ...
// std::vector<FileInfo> downloaded_files = service->Search(
//     Query({Term("label", "downloaded")},
//           base::BindOnce([](SearchResults results) {
//             ... // display results
//           })));
class COMPONENT_EXPORT(FILE_MANAGER) FileIndexService {
 public:
  explicit FileIndexService(base::FilePath profile_path);
  ~FileIndexService();

  FileIndexService(const FileIndexService&) = delete;
  FileIndexService& operator=(const FileIndexService&) = delete;

  // Initializes this service; must be called before the service is used.
  void Init(IndexingOperationCallback callback);

  // Registers the given file info with this index. This operation must be
  // completed before terms can be added to or removed from the file with
  // the matching URL.
  void PutFileInfo(const FileInfo& info, IndexingOperationCallback callback);

  // Removes the file uniquely identified by the URL from this index. This is
  // preferred way of removing files over calling the SetTerms method with an
  // empty terms vector. Returns true if the file was found and removed.
  void RemoveFile(const GURL& url, IndexingOperationCallback callback);

  // Moves the the file that was put under the `old_url` to be associated with
  // the `new_url`. If the file with the `old_url` is not found, the callback
  // is called with kFileMissing error. If the association with the `new_url`
  // fails the callback is called with kGenericError. Otherwise, it is called
  // with kSuccess.
  void MoveFile(const GURL& old_url,
                const GURL& new_url,
                IndexingOperationCallback callback);

  // Sets terms associated with the file. You may not set an empty set of terms
  // on the file. Please note that only the passed terms remains associated with
  // the file. Thus if you call this method first with, say,
  // Term("label", "downloaded"), and then call this method with,
  // say, Term("label", "pinned") only the "pinned" label is associated with
  // the given `file_info`. If you want both terms to be associated you must
  // pass both terms in a single call or use the AddTerms() method.
  void SetTerms(const std::vector<Term>& terms,
                const GURL& url,
                IndexingOperationCallback callback);

  // Adds terms associated with the file with the `terms` given as the first
  // argument. Once this operation is finished, the file can be retrieved by any
  // existing terms that were associated with it, or any new terms this call
  // added.
  void AddTerms(const std::vector<Term>& terms,
                const GURL& url,
                IndexingOperationCallback callback);

  // Removes the specified terms from list of terms associated with the given
  // `url`.
  void RemoveTerms(const std::vector<Term>& terms,
                   const GURL& url,
                   IndexingOperationCallback callback);

  // Searches the index for file info matching the specified query.
  void Search(const Query& query, SearchResultsCallback callback);

 private:
  // A fully synchronous file index that handles the asynchronous calls.
  base::SequenceBound<FileIndex> file_index_;

  // Remembers if init was called to prevent multiple calls.
  OpResults inited_ = OpResults::kUndefined;
};

}  // namespace ash::file_manager

#endif  // CHROMEOS_ASH_COMPONENTS_FILE_MANAGER_INDEXING_FILE_INDEX_SERVICE_H_