blob: 106fda94e7fc3d22f83d94f7ebdac811dbe338ff [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/android/webapk/webapk_database.h"
#include <memory>
#include <string>
#include "base/check.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/sequence_checker.h"
#include "chrome/browser/android/webapk/proto/webapk_database.pb.h"
#include "chrome/browser/android/webapk/webapk_registry_update.h"
#include "chrome/browser/android/webapk/webapk_sync_bridge.h"
#include "components/sync/model/data_type_store.h"
#include "components/sync/model/data_type_store_service.h"
#include "components/sync/model/metadata_batch.h"
#include "components/sync/model/metadata_change_list.h"
#include "components/sync/model/model_error.h"
#include "components/sync/protocol/web_apk_specifics.pb.h"
namespace webapk {
WebApkDatabase::WebApkDatabase(
syncer::DataTypeStoreService* data_type_store_service,
ReportErrorCallback error_callback)
: data_type_store_service_(data_type_store_service),
error_callback_(std::move(error_callback)) {
CHECK(data_type_store_service_);
}
WebApkDatabase::~WebApkDatabase() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void WebApkDatabase::OpenDatabase(RegistryOpenedCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(!store_);
syncer::OnceDataTypeStoreFactory store_factory =
data_type_store_service_->GetStoreFactory();
std::move(store_factory)
.Run(syncer::WEB_APKS,
base::BindOnce(&WebApkDatabase::OnDatabaseOpened,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void WebApkDatabase::Write(
const RegistryUpdateData& update_data,
std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
CompletionCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(opened_);
std::unique_ptr<syncer::DataTypeStore::WriteBatch> write_batch =
store_->CreateWriteBatch();
// |update_data| can be empty here but we should write |metadata_change_list|
// anyway.
write_batch->TakeMetadataChangesFrom(std::move(metadata_change_list));
for (const std::unique_ptr<WebApkProto>& webapk :
update_data.apps_to_create) {
write_batch->WriteData(
ManifestIdStrToAppId(webapk->sync_data().manifest_id()),
webapk->SerializeAsString());
}
for (const std::string& app_id : update_data.apps_to_delete) {
write_batch->DeleteData(app_id);
}
store_->CommitWriteBatch(
std::move(write_batch),
base::BindOnce(&WebApkDatabase::OnDataWritten,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void WebApkDatabase::DeleteAllDataAndMetadata(
syncer::DataTypeStore::CallbackWithResult callback) {
CHECK(store_);
store_->DeleteAllDataAndMetadata(std::move(callback));
}
void WebApkDatabase::OnDatabaseOpened(
RegistryOpenedCallback callback,
const std::optional<syncer::ModelError>& error,
std::unique_ptr<syncer::DataTypeStore> store) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (error) {
error_callback_.Run(*error);
DLOG(ERROR) << "WebApks LevelDB opening error: " << error->ToString();
return;
}
store_ = std::move(store);
store_->ReadAllDataAndMetadata(
base::BindOnce(&WebApkDatabase::OnAllDataAndMetadataRead,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void WebApkDatabase::OnAllDataAndMetadataRead(
RegistryOpenedCallback callback,
const std::optional<syncer::ModelError>& error,
std::unique_ptr<syncer::DataTypeStore::RecordList> data_records,
std::unique_ptr<syncer::MetadataBatch> metadata_batch) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (error) {
error_callback_.Run(*error);
DLOG(ERROR) << "WebApks LevelDB read error: " << error->ToString();
return;
}
Registry registry;
for (const syncer::DataTypeStore::Record& record : *data_records) {
std::unique_ptr<WebApkProto> proto = std::make_unique<WebApkProto>();
const bool parsed = proto->ParseFromString(record.value);
if (!parsed) {
DLOG(ERROR) << "WebApks LevelDB parse error: can't parse proto.";
}
registry.emplace(record.id, std::move(proto));
}
RecordSyncedWebApkCountHistogram(registry.size());
opened_ = true;
// This should be a tail call: a callback code may indirectly call |this|
// methods, like WebApkDatabase::Write()
std::move(callback).Run(std::move(registry), std::move(metadata_batch));
}
void WebApkDatabase::OnDataWritten(
CompletionCallback callback,
const std::optional<syncer::ModelError>& error) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (error) {
error_callback_.Run(*error);
DLOG(ERROR) << "WebApks LevelDB write error: " << error->ToString();
}
std::move(callback).Run(!error);
}
void WebApkDatabase::RecordSyncedWebApkCountHistogram(int num_web_apks) const {
base::UmaHistogramExactLinear("WebApk.Sync.SyncedWebApkCount", num_web_apks,
51 /* max_count */);
}
} // namespace webapk