blob: b4fda66c50e1becd9734656907249e3a89f7b201 [file] [log] [blame]
// Copyright 2022 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 <fidl/fuchsia.driver.framework/cpp/fidl.h>
#include <fidl/fuchsia.runtime.test/cpp/driver/fidl.h>
#include <fidl/fuchsia.runtime.test/cpp/fidl.h>
#include <lib/async/cpp/executor.h>
#include <lib/driver/component/cpp/driver_base.h>
#include <lib/driver/component/cpp/driver_export.h>
#include <lib/driver/incoming/cpp/namespace.h>
#include <lib/driver/logging/cpp/logger.h>
#include <lib/fdf/cpp/arena.h>
#include <lib/fdf/cpp/channel.h>
#include <lib/fdf/cpp/protocol.h>
#include <lib/fpromise/bridge.h>
#include <lib/fpromise/scope.h>
#include "src/lib/fidl/contrib/fpromise/client.h"
namespace fdf {
using namespace fuchsia_driver_framework;
} // namespace fdf
namespace ft = fuchsia_runtime_test;
using fpromise::error;
using fpromise::ok;
using fpromise::promise;
using fpromise::result;
namespace {
class LeafDriver : public fdf::DriverBase {
public:
LeafDriver(fdf::DriverStartArgs start_args, fdf::UnownedSynchronizedDispatcher driver_dispatcher)
: DriverBase("leaf", std::move(start_args), std::move(driver_dispatcher)),
executor_(dispatcher()),
node_(fidl::WireSharedClient(std::move(node()), dispatcher())) {}
zx::result<> Start() override {
auto setter_client = incoming()->Connect<ft::Service::Setter>();
if (setter_client.is_error()) {
return setter_client.take_error();
}
setter_.Bind(*std::move(setter_client), driver_dispatcher()->get());
auto getter_client = incoming()->Connect<ft::Service::Getter>();
if (getter_client.is_error()) {
return getter_client.take_error();
}
getter_.Bind(*std::move(getter_client), driver_dispatcher()->get());
auto waiter_client = incoming()->Connect<ft::Waiter>();
if (waiter_client.is_error()) {
return waiter_client.take_error();
}
waiter_.Bind(*std::move(waiter_client), dispatcher());
auto task = CallSetter()
.and_then(fit::bind_member(this, &LeafDriver::CallGetter))
.and_then(fit::bind_member(this, &LeafDriver::CallAck))
.or_else(fit::bind_member(this, &LeafDriver::UnbindNode))
.wrap_with(scope_);
executor_.schedule_task(std::move(task));
return zx::ok();
}
private:
// Magic number that we will set and retrieve from our parent via driver runtime protocols.
static constexpr const uint32_t kMagic = 123456;
fpromise::promise<void, zx_status_t> CallSetter() {
fdf::Arena arena('TEST');
ft::WrappedValue wrapped_value;
wrapped_value.value() = kMagic;
auto arg = fidl::ToWire(arena, wrapped_value);
fpromise::bridge<void, zx_status_t> bridge;
auto callback = [completer = std::move(bridge.completer)](
fdf::WireUnownedResult<ft::Setter::Set>& result) mutable {
if (!result.ok()) {
completer.complete_error(result.status());
return;
}
completer.complete_ok();
};
setter_.buffer(arena)->Set(arg).ThenExactlyOnce(std::move(callback));
return bridge.consumer.promise();
}
fpromise::promise<void, zx_status_t> CallGetter() {
return fidl_fpromise::as_promise(getter_->Get())
.then([&](fpromise::result<ft::GetterGetResponse, fidl::ErrorsIn<ft::Getter::Get>>& result)
-> fpromise::promise<void, zx_status_t> {
if (result.is_error()) {
zx_status_t status = result.error().is_domain_error()
? result.error().domain_error()
: result.error().framework_error().status();
return fpromise::make_error_promise(status);
}
if (result.value() != kMagic) {
return fpromise::make_error_promise(ZX_ERR_BAD_STATE);
}
return fpromise::make_result_promise<void, zx_status_t>(fpromise::ok());
});
}
result<void, zx_status_t> CallAck() {
[[maybe_unused]] auto result = waiter_->Ack();
return ok();
}
result<> UnbindNode(const zx_status_t& status) {
FDF_LOG(ERROR, "Failed to start leaf driver: %s", zx_status_get_string(status));
node_.AsyncTeardown();
return ok();
}
async::Executor executor_;
fidl::WireSharedClient<fdf::Node> node_;
// This is specifically a |WireClient| so we can test using |fdf::Arena|.
fdf::WireClient<ft::Setter> setter_;
fdf::Client<ft::Getter> getter_;
fidl::Client<ft::Waiter> waiter_;
// NOTE: Must be the last member.
fpromise::scope scope_;
};
} // namespace
FUCHSIA_DRIVER_EXPORT(LeafDriver);