| // Copyright 2018 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. |
| |
| #pragma once |
| |
| #include <fuchsia/ledger/cpp/fidl.h> |
| #include <lib/fit/bridge.h> |
| #include <lib/fit/promise.h> |
| |
| #include "peridot/lib/fidl/array_to_string.h" // for to_string(), to_array() |
| |
| namespace modular { |
| |
| // These wrapper functions wrap fuchsia.ledger APIs such that they return |
| // a fit::promise<> representing the result of the call. They are useful to |
| // incorporate into tasks themselves expressed as fit::promises. |
| // |
| // The wrapper classes act as namespaces for static methods. For a given api |
| // (such as fuchsia.ledger.Page), the wrapper class is called PagePromise, and |
| // each method has the same signature as that in fuchsia::ledger::Page, with the |
| // addition that the first parameter is always a fuchsia::ledger::Page* and the |
| // last parameter (the result callback) is omitted. |
| // |
| // Note that these wrapper methods IMMEDIATELY call the underlying FIDL |
| // function (meaning that a message is dispatched immediately on the underlying |
| // channel). The returned promise will block until a response message is |
| // received. |
| // |
| // EXAMPLE |
| // |
| // auto p = fit::make_promise([snapshot = page_snapshot_ptr.get()] () { |
| // return PageSnapshotPromise::GetInline(snapshot, key); |
| // }).and_then([] (const std::vector<uint8_t> bytes) { |
| // // Decode and use |bytes|. |
| // }); |
| |
| // fit::promise wrapper functions for fuchsia.ledger.Page. |
| class PagePromise { |
| public: |
| static fit::promise<> StartTransaction(fuchsia::ledger::Page* page) { |
| fit::bridge<> bridge; |
| page->StartTransaction([completer = std::move(bridge.completer)]( |
| fuchsia::ledger::Status status) mutable { |
| if (status == fuchsia::ledger::Status::OK) { |
| completer.complete_ok(); |
| } else { |
| completer.complete_error(); |
| } |
| }); |
| return bridge.consumer.promise(); |
| } |
| |
| static fit::promise<> Commit(fuchsia::ledger::Page* page) { |
| fit::bridge<> bridge; |
| page->Commit([completer = std::move(bridge.completer)]( |
| fuchsia::ledger::Status status) mutable { |
| if (status == fuchsia::ledger::Status::OK) { |
| completer.complete_ok(); |
| } else { |
| completer.complete_error(); |
| } |
| }); |
| return bridge.consumer.promise(); |
| } |
| |
| static fit::promise<> Rollback(fuchsia::ledger::Page* page) { |
| fit::bridge<> bridge; |
| page->Commit([completer = std::move(bridge.completer)]( |
| fuchsia::ledger::Status status) mutable { |
| if (status == fuchsia::ledger::Status::OK) { |
| completer.complete_ok(); |
| } else { |
| completer.complete_error(); |
| } |
| }); |
| return bridge.consumer.promise(); |
| } |
| |
| static fit::promise<> GetSnapshot( |
| fuchsia::ledger::Page* page, |
| fidl::InterfaceRequest<fuchsia::ledger::PageSnapshot> request) { |
| fit::bridge<> bridge; |
| page->GetSnapshot(std::move(request), |
| fidl::VectorPtr<uint8_t>::New(0) /* key_prefix */, |
| nullptr /* watcher */, |
| [completer = std::move(bridge.completer)]( |
| fuchsia::ledger::Status status) mutable { |
| if (status == fuchsia::ledger::Status::OK) { |
| completer.complete_ok(); |
| } else { |
| completer.complete_error(); |
| } |
| }); |
| return bridge.consumer.promise(); |
| } |
| |
| static fit::promise<> Put(fuchsia::ledger::Page* page, std::string key, |
| std::vector<uint8_t> value) { |
| fit::bridge<> bridge; |
| page->Put(to_array(key), fidl::VectorPtr<uint8_t>(std::move(value)), |
| [completer = std::move(bridge.completer)]( |
| fuchsia::ledger::Status status) mutable { |
| if (status == fuchsia::ledger::Status::OK) { |
| completer.complete_ok(); |
| } else { |
| completer.complete_error(); |
| } |
| }); |
| return bridge.consumer.promise(); |
| } |
| }; |
| |
| // fit::promise wrapper functions for fuchsia.ledger.Page. |
| // |
| // These methods match the signatures in fuchsia.ledger.Page with the exception |
| // that the first parameter is always a fuchsia::ledger::Page*. |
| class PageSnapshotPromise { |
| public: |
| // fit::promise wrapper function for PageSnapshot.GetInline(). |
| // |
| // Falls back to PageSnapshot::Get() if the value is too large. |
| // TODO(thatguy): Implement the fallback. |
| static fit::promise<std::unique_ptr<std::vector<uint8_t>>> GetInline( |
| fuchsia::ledger::PageSnapshot* snapshot, std::string key) { |
| fit::bridge<std::unique_ptr<std::vector<uint8_t>>> bridge; |
| snapshot->GetInline( |
| to_array(key), [completer = std::move(bridge.completer)]( |
| fuchsia::ledger::Status status, |
| fuchsia::ledger::InlinedValuePtr value) mutable { |
| switch (status) { |
| case fuchsia::ledger::Status::OK: |
| case fuchsia::ledger::Status::KEY_NOT_FOUND: |
| if (value) { |
| // Convert the result to a unique_ptr instead of a VectorPtr. |
| auto ret = |
| std::make_unique<std::vector<uint8_t>>(value->value); |
| completer.complete_ok(std::move(ret)); |
| } else { |
| completer.complete_ok(nullptr); |
| } |
| break; |
| case fuchsia::ledger::Status::VALUE_TOO_LARGE: |
| // TODO(thatguy): Handle a too-large value. |
| FXL_LOG(FATAL) << "TODO: fallback to PageSnapshot_Get()."; |
| default: |
| FXL_LOG(ERROR) << "PageSnapshotPromise::GetInline() failed with " |
| << fidl::ToUnderlying(status); |
| completer.complete_error(); |
| } |
| }); |
| return bridge.consumer.promise(); |
| } |
| }; |
| |
| } // namespace modular |