blob: 93eefa626d5823a5598832f299b01c359e18e550 [file]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/sync_tab_context/tab_context_item_sync_bridge.h"
#include <utility>
#include "base/strings/strcat.h"
#include "base/uuid.h"
#include "components/sync/model/in_memory_metadata_change_list.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/model/mutable_data_batch.h"
#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "components/sync_tab_context/container_id.h"
namespace sync_tab_context {
namespace {
std::string GetClientTag(const ContainerId& container_id,
const std::string& item_id) {
return base::StrCat({container_id.value().AsLowercaseString(), ":", item_id});
}
} // namespace
TabContextItemSyncBridge::TabContextItemSyncBridge(
std::unique_ptr<syncer::DataTypeLocalChangeProcessor> change_processor)
: syncer::DataTypeSyncBridge(std::move(change_processor)) {
this->change_processor()->ModelReadyToSync(
std::make_unique<syncer::MetadataBatch>());
}
TabContextItemSyncBridge::~TabContextItemSyncBridge() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
bool TabContextItemSyncBridge::UploadItem(
const ContainerId& container_id,
const std::string& item_id,
sync_pb::EncryptedData encrypted_data) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(container_id.value().is_valid());
CHECK(!item_id.empty());
if (!change_processor()->IsTrackingMetadata()) {
return false;
}
sync_pb::EncryptedTabContextItemSpecifics specifics;
specifics.set_container_id(container_id.value().AsLowercaseString());
specifics.set_item_id(item_id);
*specifics.mutable_encrypted_data() = std::move(encrypted_data);
const std::string storage_key =
sync_tab_context::GetClientTag(container_id, item_id);
std::unique_ptr<syncer::MetadataChangeList> metadata_change_list =
CreateMetadataChangeList();
auto entity_data = std::make_unique<syncer::EntityData>();
*entity_data->specifics.mutable_encrypted_tab_context_item() =
std::move(specifics);
entity_data->name = storage_key;
change_processor()->Put(storage_key, std::move(entity_data),
metadata_change_list.get());
return true;
}
std::unique_ptr<syncer::MetadataChangeList>
TabContextItemSyncBridge::CreateMetadataChangeList() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return std::make_unique<syncer::InMemoryMetadataChangeList>();
}
std::optional<syncer::ModelError> TabContextItemSyncBridge::MergeFullSyncData(
std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
syncer::EntityChangeList entity_changes) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return ApplyIncrementalSyncChanges(std::move(metadata_change_list),
std::move(entity_changes));
}
std::optional<syncer::ModelError>
TabContextItemSyncBridge::ApplyIncrementalSyncChanges(
std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
syncer::EntityChangeList entity_changes) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (metadata_change_list) {
metadata_change_list->DropAllChanges();
}
return std::nullopt;
}
std::unique_ptr<syncer::DataBatch> TabContextItemSyncBridge::GetDataForCommit(
StorageKeyList storage_keys) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This being a commit-only datatype without even tracking in-flight changes
// (and definitely no persistence) at the bridge level means there is no data
// to return. This code should be usually unreachable, except for edge cases
// like the browser having been restarted while in-flight changes existed. In
// such scenarios, such in-flight changes will be lost.
return std::make_unique<syncer::MutableDataBatch>();
}
std::unique_ptr<syncer::DataBatch>
TabContextItemSyncBridge::GetAllDataForDebugging() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This being a commit-only datatype without even tracking in-flight changes
// at the bridge level means there are no entities to return.
return std::make_unique<syncer::MutableDataBatch>();
}
std::string TabContextItemSyncBridge::GetClientTag(
const syncer::EntityData& entity_data) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const sync_pb::EncryptedTabContextItemSpecifics& specifics =
entity_data.specifics.encrypted_tab_context_item();
return sync_tab_context::GetClientTag(
ContainerId(base::Uuid::ParseCaseInsensitive(specifics.container_id())),
specifics.item_id());
}
std::string TabContextItemSyncBridge::GetStorageKey(
const syncer::EntityData& entity_data) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return GetClientTag(entity_data);
}
sync_pb::EntitySpecifics
TabContextItemSyncBridge::TrimAllSupportedFieldsFromRemoteSpecifics(
const sync_pb::EntitySpecifics& entity_specifics) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return sync_pb::EntitySpecifics();
}
bool TabContextItemSyncBridge::IsEntityDataValid(
const syncer::EntityData& entity_data) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const sync_pb::EncryptedTabContextItemSpecifics& specifics =
entity_data.specifics.encrypted_tab_context_item();
return base::Uuid::ParseCaseInsensitive(specifics.container_id())
.is_valid() &&
!specifics.item_id().empty() && specifics.has_encrypted_data();
}
} // namespace sync_tab_context