blob: 27bac7eb8a5803b45b3d9e84478369a5967c0687 [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/examples/todo_cpp/todo.h"
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <algorithm>
#include <iostream>
#include <lib/async/cpp/task.h>
#include <lib/async/default.h>
#include <fuchsia/cpp/ledger_internal.h>
#include "lib/app/cpp/connect.h"
#include "lib/fsl/tasks/message_loop.h"
#include "lib/fsl/vmo/strings.h"
#include "lib/fxl/functional/make_copyable.h"
#include "lib/fxl/logging.h"
#include "lib/fxl/strings/string_printf.h"
#include "lib/fxl/time/time_delta.h"
namespace todo {
namespace {
const double kMeanListSize = 7.0;
const double kListSizeStdDev = 2.0;
const int kMinDelaySeconds = 1;
const int kMaxDelaySeconds = 5;
std::string ToString(const mem::Buffer& vmo) {
std::string ret;
if (!fsl::StringFromVmo(vmo, &ret)) {
FXL_DCHECK(false);
}
return ret;
}
fidl::VectorPtr<uint8_t> ToArray(const std::string& val) {
auto ret = fidl::VectorPtr<uint8_t>::New(val.size());
memcpy(ret->data(), val.data(), val.size());
return ret;
}
Key MakeKey() {
return ToArray(fxl::StringPrintf("%120ld-%u", time(nullptr), rand()));
}
std::function<void(ledger::Status)> HandleResponse(std::string description) {
return [description](ledger::Status status) {
if (status != ledger::Status::OK) {
FXL_LOG(ERROR) << description << " failed";
fsl::MessageLoop::GetCurrent()->PostQuitTask();
}
};
}
void GetEntries(
ledger::PageSnapshotPtr snapshot,
std::vector<ledger::Entry> entries,
fidl::VectorPtr<uint8_t> token,
std::function<void(ledger::Status, std::vector<ledger::Entry>)> callback) {
ledger::PageSnapshot* snapshot_ptr = snapshot.get();
snapshot_ptr->GetEntries(
nullptr, std::move(token), fxl::MakeCopyable([
snapshot = std::move(snapshot), entries = std::move(entries),
callback = std::move(callback)
](ledger::Status status, auto new_entries, auto next_token) mutable {
if (status != ledger::Status::OK &&
status != ledger::Status::PARTIAL_RESULT) {
callback(status, {});
return;
}
for (size_t i = 0; i < new_entries->size(); ++i) {
entries.push_back(std::move(new_entries->at(i)));
}
if (status == ledger::Status::OK) {
callback(ledger::Status::OK, std::move(entries));
return;
}
GetEntries(std::move(snapshot), std::move(entries),
std::move(next_token), std::move(callback));
}));
}
void GetEntries(
ledger::PageSnapshotPtr snapshot,
std::function<void(ledger::Status, std::vector<ledger::Entry>)> callback) {
GetEntries(std::move(snapshot), {}, nullptr, std::move(callback));
}
} // namespace
TodoApp::TodoApp()
: rng_(time(nullptr)),
size_distribution_(kMeanListSize, kListSizeStdDev),
delay_distribution_(kMinDelaySeconds, kMaxDelaySeconds),
generator_(&rng_),
context_(component::ApplicationContext::CreateFromStartupInfo()),
module_binding_(this),
page_watcher_binding_(this) {
context_->outgoing_services()->AddService<modular::Module>(
[this](fidl::InterfaceRequest<modular::Module> request) {
FXL_DCHECK(!module_binding_.is_bound());
module_binding_.Bind(std::move(request));
});
}
void TodoApp::Initialize(
fidl::InterfaceHandle<modular::ModuleContext> module_context,
fidl::InterfaceRequest<component::ServiceProvider> /*outgoing_services*/) {
module_context_.Bind(std::move(module_context));
module_context_->GetComponentContext(component_context_.NewRequest());
component_context_->GetLedger(ledger_.NewRequest(),
HandleResponse("GetLedger"));
ledger_->GetRootPage(page_.NewRequest(), HandleResponse("GetRootPage"));
ledger::PageSnapshotPtr snapshot;
page_->GetSnapshot(snapshot.NewRequest(), nullptr,
page_watcher_binding_.NewBinding(),
HandleResponse("Watch"));
List(std::move(snapshot));
async::PostTask(async_get_default(), [this] { Act(); });
}
void TodoApp::Terminate() {
fsl::MessageLoop::GetCurrent()->QuitNow();
}
void TodoApp::OnChange(ledger::PageChange /*page_change*/,
ledger::ResultState result_state,
OnChangeCallback callback) {
if (result_state != ledger::ResultState::PARTIAL_STARTED &&
result_state != ledger::ResultState::COMPLETED) {
// Only request the entries list once, on the first OnChange call.
callback(nullptr);
return;
}
ledger::PageSnapshotPtr snapshot;
callback(snapshot.NewRequest());
List(std::move(snapshot));
}
void TodoApp::List(ledger::PageSnapshotPtr snapshot) {
GetEntries(std::move(snapshot), [](ledger::Status status, auto entries) {
if (status != ledger::Status::OK) {
FXL_LOG(ERROR) << "GetEntries failed";
fsl::MessageLoop::GetCurrent()->PostQuitTask();
return;
}
std::cout << "--- To Do ---" << std::endl;
for (auto& entry : entries) {
std::cout << (entry.value ? ToString(*entry.value) : "<empty>")
<< std::endl;
}
std::cout << "---" << std::endl;
});
}
void TodoApp::GetKeys(std::function<void(fidl::VectorPtr<Key>)> callback) {
ledger::PageSnapshotPtr snapshot;
page_->GetSnapshot(snapshot.NewRequest(), nullptr, nullptr,
HandleResponse("GetSnapshot"));
ledger::PageSnapshot* snapshot_ptr = snapshot.get();
snapshot_ptr->GetKeys(nullptr, nullptr, fxl::MakeCopyable([
snapshot = std::move(snapshot), callback
](ledger::Status status, auto keys, auto next_token) {
callback(std::move(keys));
}));
}
void TodoApp::AddNew() {
page_->Put(MakeKey(), ToArray(generator_.Generate()), HandleResponse("Put"));
}
void TodoApp::DeleteOne(fidl::VectorPtr<Key> keys) {
FXL_DCHECK(keys->size());
std::uniform_int_distribution<> distribution(0, keys->size() - 1);
page_->Delete(std::move(keys->at(distribution(rng_))),
HandleResponse("Delete"));
}
void TodoApp::Act() {
GetKeys([this](fidl::VectorPtr<Key> keys) {
size_t target_size = std::round(size_distribution_(rng_));
if (keys->size() > std::max(static_cast<size_t>(0), target_size)) {
DeleteOne(std::move(keys));
} else {
AddNew();
}
});
zx::duration delay = zx::sec(delay_distribution_(rng_));
async::PostDelayedTask(async_get_default(), [this] { Act(); }, delay);
}
} // namespace todo
int main(int /*argc*/, const char** /*argv*/) {
fsl::MessageLoop loop;
todo::TodoApp app;
loop.Run();
return 0;
}