blob: 0bcab29fd3861fa69d44e8e0775ad51c928ad730 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "peridot/bin/ledger/app/ledger_repository_impl.h"
#include <trace/event.h>
#include "peridot/bin/ledger/cloud_sync/impl/ledger_sync_impl.h"
#include "peridot/bin/ledger/p2p_sync/public/ledger_communicator.h"
#include "peridot/bin/ledger/storage/impl/ledger_storage_impl.h"
#include "peridot/bin/ledger/sync_coordinator/public/ledger_sync.h"
#include "peridot/lib/convert/convert.h"
namespace ledger {
LedgerRepositoryImpl::LedgerRepositoryImpl(
DetachedPath content_path, Environment* environment,
std::unique_ptr<SyncWatcherSet> watchers,
std::unique_ptr<sync_coordinator::UserSync> user_sync,
std::unique_ptr<DiskCleanupManager> disk_cleanup_manager)
: content_path_(std::move(content_path)),
environment_(environment),
encryption_service_factory_(environment),
watchers_(std::move(watchers)),
user_sync_(std::move(user_sync)),
disk_cleanup_manager_(std::move(disk_cleanup_manager)) {
bindings_.set_empty_set_handler([this] { CheckEmpty(); });
ledger_managers_.set_on_empty([this] { CheckEmpty(); });
ledger_repository_debug_bindings_.set_empty_set_handler(
[this] { CheckEmpty(); });
disk_cleanup_manager_->set_on_empty([this] { CheckEmpty(); });
}
LedgerRepositoryImpl::~LedgerRepositoryImpl() {}
void LedgerRepositoryImpl::BindRepository(
fidl::InterfaceRequest<ledger_internal::LedgerRepository>
repository_request) {
bindings_.AddBinding(this, std::move(repository_request));
}
void LedgerRepositoryImpl::PageIsClosedAndSynced(
fxl::StringView ledger_name, storage::PageIdView page_id,
fit::function<void(Status, PagePredicateResult)> callback) {
LedgerManager* ledger_manager =
GetLedgerManager(ledger_name, CreateIfMissing::YES);
FXL_DCHECK(ledger_manager);
ledger_manager->PageIsClosedAndSynced(page_id, std::move(callback));
}
void LedgerRepositoryImpl::PageIsClosedOfflineAndEmpty(
fxl::StringView ledger_name, storage::PageIdView page_id,
fit::function<void(Status, PagePredicateResult)> callback) {
LedgerManager* ledger_manager =
GetLedgerManager(ledger_name, CreateIfMissing::YES);
FXL_DCHECK(ledger_manager);
ledger_manager->PageIsClosedOfflineAndEmpty(page_id, std::move(callback));
}
void LedgerRepositoryImpl::DeletePageStorage(
fxl::StringView ledger_name, storage::PageIdView page_id,
fit::function<void(Status)> callback) {
LedgerManager* ledger_manager =
GetLedgerManager(ledger_name, CreateIfMissing::YES);
FXL_DCHECK(ledger_manager);
return ledger_manager->DeletePageStorage(page_id, std::move(callback));
}
std::vector<fidl::InterfaceRequest<ledger_internal::LedgerRepository>>
LedgerRepositoryImpl::Unbind() {
std::vector<fidl::InterfaceRequest<ledger_internal::LedgerRepository>>
handles;
for (auto& binding : bindings_.bindings()) {
handles.push_back(binding->Unbind());
}
bindings_.CloseAll();
return handles;
}
LedgerManager* LedgerRepositoryImpl::GetLedgerManager(
convert::ExtendedStringView ledger_name,
CreateIfMissing create_if_missing) {
FXL_DCHECK(!ledger_name.empty());
// If the Ledger instance is already open return it directly.
auto it = ledger_managers_.find(ledger_name);
if (it != ledger_managers_.end()) {
return &(it->second);
}
if (create_if_missing == CreateIfMissing::NO) {
return nullptr;
}
std::string name_as_string = convert::ToString(ledger_name);
std::unique_ptr<encryption::EncryptionService> encryption_service =
encryption_service_factory_.MakeEncryptionService(name_as_string);
auto ledger_storage = std::make_unique<storage::LedgerStorageImpl>(
environment_, encryption_service.get(), content_path_, name_as_string);
std::unique_ptr<sync_coordinator::LedgerSync> ledger_sync;
if (user_sync_) {
ledger_sync =
user_sync_->CreateLedgerSync(name_as_string, encryption_service.get());
}
auto result = ledger_managers_.emplace(
std::piecewise_construct, std::forward_as_tuple(name_as_string),
std::forward_as_tuple(environment_, std::move(name_as_string),
std::move(encryption_service),
std::move(ledger_storage), std::move(ledger_sync),
disk_cleanup_manager_.get()));
FXL_DCHECK(result.second);
return &(result.first->second);
}
void LedgerRepositoryImpl::GetLedger(
fidl::VectorPtr<uint8_t> ledger_name,
fidl::InterfaceRequest<Ledger> ledger_request, GetLedgerCallback callback) {
TRACE_DURATION("ledger", "repository_get_ledger");
if (ledger_name->empty()) {
callback(Status::INVALID_ARGUMENT);
return;
}
LedgerManager* ledger_manager =
GetLedgerManager(ledger_name, CreateIfMissing::YES);
FXL_DCHECK(ledger_manager);
ledger_manager->BindLedger(std::move(ledger_request));
callback(Status::OK);
}
void LedgerRepositoryImpl::Duplicate(
fidl::InterfaceRequest<ledger_internal::LedgerRepository> request,
DuplicateCallback callback) {
BindRepository(std::move(request));
callback(Status::OK);
}
void LedgerRepositoryImpl::SetSyncStateWatcher(
fidl::InterfaceHandle<SyncWatcher> watcher,
SetSyncStateWatcherCallback callback) {
watchers_->AddSyncWatcher(std::move(watcher));
callback(Status::OK);
}
void LedgerRepositoryImpl::CheckEmpty() {
if (!on_empty_callback_)
return;
if (ledger_managers_.empty() && bindings_.size() == 0 &&
ledger_repository_debug_bindings_.size() == 0 &&
disk_cleanup_manager_->IsEmpty()) {
on_empty_callback_();
}
}
void LedgerRepositoryImpl::GetLedgerRepositoryDebug(
fidl::InterfaceRequest<ledger_internal::LedgerRepositoryDebug> request,
GetLedgerRepositoryDebugCallback callback) {
ledger_repository_debug_bindings_.AddBinding(this, std::move(request));
callback(Status::OK);
}
void LedgerRepositoryImpl::DiskCleanUp(DiskCleanUpCallback callback) {
if (clean_up_in_progress_) {
callback(Status::ILLEGAL_STATE);
return;
}
clean_up_in_progress_ = true;
disk_cleanup_manager_->TryCleanUp(
[this, callback = std::move(callback)](Status status) {
FXL_DCHECK(clean_up_in_progress_);
clean_up_in_progress_ = false;
callback(status);
});
}
void LedgerRepositoryImpl::GetInstancesList(GetInstancesListCallback callback) {
fidl::VectorPtr<fidl::VectorPtr<uint8_t>> result =
fidl::VectorPtr<fidl::VectorPtr<uint8_t>>::New(0);
for (const auto& key_value : ledger_managers_) {
result.push_back(convert::ToArray(key_value.first));
}
callback(std::move(result));
}
void LedgerRepositoryImpl::GetLedgerDebug(
fidl::VectorPtr<uint8_t> ledger_name,
fidl::InterfaceRequest<ledger_internal::LedgerDebug> request,
GetLedgerDebugCallback callback) {
auto it = ledger_managers_.find(ledger_name);
if (it == ledger_managers_.end()) {
callback(Status::KEY_NOT_FOUND);
} else {
it->second.BindLedgerDebug(std::move(request));
callback(Status::OK);
}
}
} // namespace ledger