blob: 47ad2854de4f331ca31c9875e0e4797cb79db42e [file]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_USER_DATA_IMPORTER_CONTENT_STABLE_PORTABILITY_DATA_IMPORTER_H_
#define COMPONENTS_USER_DATA_IMPORTER_CONTENT_STABLE_PORTABILITY_DATA_IMPORTER_H_
#include "base/memory/raw_ptr.h"
#include "base/sequence_checker.h"
#include "base/threading/sequence_bound.h"
#include "build/build_config.h"
#include "components/user_data_importer/content/content_bookmark_parser.h"
#include "components/user_data_importer/utility/bookmark_parser.h"
#include "components/user_data_importer/utility/history_callback_from_rust.h"
#include "components/user_data_importer/utility/importer_metrics_recorder.h"
namespace base {
class File;
class SequencedTaskRunner;
} // namespace base
namespace bookmarks {
class BookmarkModel;
} // namespace bookmarks
namespace history {
class HistoryService;
} // namespace history
class ReadingListModel;
namespace user_data_importer {
struct StablePortabilityHistoryEntry;
// Main model-layer object for extracting the data exported by browsers in the
// stable portability data format. The data is received through a system API in
// several files each containing a single data type.
class StablePortabilityDataImporter {
public:
// A callback used by the caller to obtain the number of successfully imported
// bookmarks, reading list items, or history entries. In case of an error, the
// reported count will be -1.
using ImportCallback = base::OnceCallback<void(int)>;
// Default batch size when importing history. Different values can be passed
// to ImportHistory() for testing purposes.
static constexpr size_t kHistoryBatchSize = 1000;
// `history_service`, `bookmark_model`, and `reading_list_model` may be null,
// but if non-null must outlive this class. `bookmark_parser` must not be
// null.
StablePortabilityDataImporter(
history::HistoryService* history_service,
bookmarks::BookmarkModel* bookmark_model,
ReadingListModel* reading_list_model,
std::unique_ptr<ContentBookmarkParser> bookmark_parser);
~StablePortabilityDataImporter();
// Attempts to import bookmarks from the given `file`. `bookmarks_callback` is
// called at the end of the import process to notify the caller about the
// number of items successfully imported.
void ImportBookmarks(base::File file, ImportCallback bookmarks_callback);
// Attempts to import bookmarks from the given `file`. `reading_list_callback`
// is called at the end of the import process to notify the caller about the
// number of items successfully imported.
void ImportReadingList(base::File file, ImportCallback reading_list_callback);
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
// Attempts to import history from the given `file`. `history_callback` is
// called at the end of the import process to notify the caller about the
// number of items successfully imported.
void ImportHistory(base::File file,
ImportCallback history_callback,
const size_t import_batch_size = kHistoryBatchSize);
#endif // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
private:
// Object used to allow Rust History import pipeline to communicate results
// back to this importer.
class RustHistoryCallbackForStablePortabilityFormat final
: public user_data_importer::HistoryCallbackFromRust<
StablePortabilityHistoryEntry> {
public:
using TransferHistoryCallback = base::RepeatingCallback<void(
std::vector<StablePortabilityHistoryEntry>)>;
explicit RustHistoryCallbackForStablePortabilityFormat(
TransferHistoryCallback transfer_history_callback,
user_data_importer::StablePortabilityDataImporter::ImportCallback
done_callback);
~RustHistoryCallbackForStablePortabilityFormat() override;
// Called from Rust when a batch of history entries has been parsed.
void ImportHistoryEntries(
std::unique_ptr<std::vector<
user_data_importer::StablePortabilityHistoryEntry>> history_entries,
bool completed) override;
// Calls `done_callback_` with 0 to signal that parsing has failed.
void Fail() override;
private:
TransferHistoryCallback transfer_history_callback_;
user_data_importer::StablePortabilityDataImporter::ImportCallback
done_callback_;
size_t parsed_history_entries_count_ = 0;
};
// Encapsulates work which must occur in the background thread.
class BackgroundWorker {
public:
explicit BackgroundWorker(
std::unique_ptr<ContentBookmarkParser> bookmark_parser);
~BackgroundWorker();
void ParseBookmarks(
base::File file,
user_data_importer::BookmarkParser::BookmarkParsingCallback
bookmarks_callback);
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
void ParseHistory(
base::File file,
std::unique_ptr<RustHistoryCallbackForStablePortabilityFormat> callback,
size_t import_batch_size);
#endif // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
private:
std::unique_ptr<ContentBookmarkParser> bookmark_parser_;
};
friend class StablePortabilityDataImporterTest;
// Transfers the history entries to the importer. This is used by the Rust
// History import pipeline to communicate results back to this importer.
void TransferHistoryEntries(
std::vector<StablePortabilityHistoryEntry> history_entries);
// Logs metrics related to history importing and invokes `history_callback`
// with the number of history entries imported. A negative
// `parsed_history_entries_count` is interpreted as an error having occurred
// during the importing.
void OnHistoryImportCompleted(ImportCallback history_callback,
int parsed_history_entries_count);
// Receives the result of parsing bookmarks, and invokes `bookmarks_callback`
// with the number of parsed bookmarks.
void OnBookmarksParsed(ImportCallback bookmarks_callback,
BookmarkParser::BookmarkParsingResult result);
// Logs an error and invokes `bookmarks_callback` with -1, indicating an
// error occurred.
void OnBookmarksParsingError(ImportCallback bookmarks_callback,
BookmarkParser::BookmarkParsingError error);
// Receives the result of parsing the reading list, and invokes
// `reading_list_callback` with the number of parsed reading list items.
void OnReadingListParsed(ImportCallback reading_list_callback,
BookmarkParser::BookmarkParsingResult result);
// Logs an error and invokes `reading_list_callback` with -1, indicating an
// error occurred.
void OnReadingListParsingError(ImportCallback reading_list_callback,
BookmarkParser::BookmarkParsingError error);
// Posts a task on `origin_sequence_task_runner` to call the provided
// callbacks in `StablePortabilityDataImporter::Import`
void PostCallback(auto callback, auto results);
// Number of URLs imported during the history import process.
size_t imported_history_entries_count_ = 0;
// Service used to import history URLs.
const raw_ptr<history::HistoryService> history_service_;
// Service used to import bookmarks.
const raw_ptr<bookmarks::BookmarkModel> bookmark_model_;
// Service used to import reading list items.
const raw_ptr<ReadingListModel> reading_list_model_;
// Helper object which logs metrics about the import flow.
ImporterMetricsRecorder metrics_recorder_;
SEQUENCE_CHECKER(sequence_checker_);
// The task runner from which the import task was launched. The purpose of
// this task runner is to post tasks on the thread where the importer lives,
// which we have to do for all import callbacks.
scoped_refptr<base::SequencedTaskRunner> origin_sequence_task_runner_;
// A queue for tasks which run on the background thread and may block.
scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
// An instance of BackgroundWorker which is bound to
// `background_task_runner_`.
base::SequenceBound<BackgroundWorker> background_worker_;
// Creates WeakPtr to this. Use with caution across sequence boundaries.
base::WeakPtrFactory<StablePortabilityDataImporter> weak_factory_{this};
};
} // namespace user_data_importer
#endif // COMPONENTS_USER_DATA_IMPORTER_CONTENT_STABLE_PORTABILITY_DATA_IMPORTER_H_