blob: ae1ae21cc28ea2fd773d2d345e6f0c200a7e687e [file] [log] [blame]
// Copyright 2021 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.
// ============================================================================
// This is an accompanying example code for the C++ client tutorial. Head over
// there for the full walk-through:
// https://fuchsia.dev/fuchsia-src/development/languages/fidl/tutorials/cpp/basics/client
// ============================================================================
// [START includes]
#include <fidl/fuchsia.examples/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/syslog/cpp/macros.h>
// [END includes]
int main(int argc, const char** argv) {
// [START connect]
// Connect to the |fuchsia.examples/Echo| protocol inside the component's
// namespace. This can fail so it's wrapped in a |zx::result| and it must be
// checked for errors.
zx::result client_end = component::Connect<fuchsia_examples::Echo>();
if (!client_end.is_ok()) {
FX_LOGS(ERROR) << "Synchronous error when connecting to the |Echo| protocol: "
<< client_end.status_string();
return -1;
}
// [END connect]
// [START async-loop]
// As in the server, the code sets up an async loop so that the client can
// listen for incoming responses from the server without blocking.
async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
async_dispatcher_t* dispatcher = loop.dispatcher();
// [END async-loop]
// [START event-handler]
// Define the event handler implementation for the client.
//
// The event handler delegate should be an object that implements the
// |fidl::AsyncEventHandler<Echo>| virtual class, which has methods
// corresponding to the events offered by the protocol. By default those
// methods are no-ops.
// [START event-handler-short]
class EventHandler : public fidl::AsyncEventHandler<fuchsia_examples::Echo> {
public:
void OnString(fidl::Event<::fuchsia_examples::Echo::OnString>& event) override {
FX_LOGS(INFO) << "(Natural types) got event: " << event.response();
loop_.Quit();
}
// [END event-handler-short]
// One may also override the |on_fidl_error| method, which is called
// when the client encounters an error and is going to teardown.
void on_fidl_error(fidl::UnbindInfo error) override { FX_LOGS(ERROR) << error; }
explicit EventHandler(async::Loop& loop) : loop_(loop) {}
private:
async::Loop& loop_;
};
// Create an instance of the event handler.
EventHandler event_handler{loop};
// [END event-handler]
// [START init-client]
// Create a client to the Echo protocol, passing our |event_handler| created
// earlier. The |event_handler| must live for at least as long as the
// |client|. The |client| holds a reference to the |event_handler| so it is a
// bug for the |event_handler| to be destroyed before the |client|.
fidl::Client client(std::move(*client_end), dispatcher, &event_handler);
// [END init-client]
// Make an EchoString call with natural types, building the request object inline.
// [START two_way_natural_result]
client->EchoString({"hello"}).ThenExactlyOnce(
[&](fidl::Result<fuchsia_examples::Echo::EchoString>& result) {
// Check if the FIDL call succeeded or not.
if (!result.is_ok()) {
// If the call failed, log the error, and crash the program.
// Production code should do more graceful error handling depending
// on the situation.
FX_LOGS(ERROR) << "EchoString failed: " << result.error_value();
ZX_PANIC("%s", result.error_value().FormatDescription().c_str());
}
// Dereference (->) the result object to access the response payload.
FX_LOGS(INFO) << "(Natural types) got response: " << result->response();
loop.Quit();
});
// Run the dispatch loop, until we receive a reply, in which case the callback
// above will quit the loop, breaking us out of the |Run| function.
loop.Run();
loop.ResetQuit();
// [END two_way_natural_result]
// Make an EchoString call with natural types, using named arguments in the request object.
// [START two_way_designated_natural_result]
client->EchoString({{.value = "hello"}})
.ThenExactlyOnce(
// [END two_way_designated_natural_result]
[&](fidl::Result<fuchsia_examples::Echo::EchoString>& result) {
if (!result.is_ok()) {
FX_LOGS(ERROR) << "EchoString failed: " << result.error_value();
ZX_PANIC("%s", result.error_value().FormatDescription().c_str());
}
FX_LOGS(INFO) << "(Natural types) got response: " << result->response();
loop.Quit();
});
loop.Run();
loop.ResetQuit();
// [START one_way_natural]
// [START one_way_natural_first_line]
// Make a SendString one way call with natural types.
fit::result<::fidl::Error> result = client->SendString({"hello"});
// [END one_way_natural_first_line]
if (!result.is_ok()) {
FX_LOGS(ERROR) << "SendString failed: " << result.error_value();
ZX_PANIC("%s", result.error_value().FormatDescription().c_str());
}
// [END one_way_natural]
loop.Run();
loop.ResetQuit();
// [START two_way_wire_result]
// [START two_way_wire_result_first_line]
client.wire()->EchoString("hello").ThenExactlyOnce(
// [END two_way_wire_result_first_line]
[&](fidl::WireUnownedResult<fuchsia_examples::Echo::EchoString>& result) {
if (!result.ok()) {
FX_LOGS(ERROR) << "EchoString failed: " << result.error();
ZX_PANIC("%s", result.error().FormatDescription().c_str());
return;
}
fidl::WireResponse<fuchsia_examples::Echo::EchoString>& response = result.value();
std::string reply(response.response.data(), response.response.size());
FX_LOGS(INFO) << "(Wire types) got response: " << reply;
loop.Quit();
});
// [END two_way_wire_result]
loop.Run();
loop.ResetQuit();
// [START one_way_wire]
// [START one_way_wire_first_line]
fidl::Status wire_status = client.wire()->SendString("hello");
// [END one_way_wire_first_line]
if (!wire_status.ok()) {
FX_LOGS(ERROR) << "SendString failed: " << result.error_value();
ZX_PANIC("%s", result.error_value().FormatDescription().c_str());
}
// [END one_way_wire]
loop.Run();
loop.ResetQuit();
return 0;
}