| // 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; |
| } |