blob: 9cdd6816912a74c2e8f79aeb1f40689ceb6aa504 [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/examples.canvas.baseline/cpp/wire.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/syslog/cpp/macros.h>
#include <unistd.h>
#include <charconv>
#include <examples/fidl/new/canvas/baseline/cpp_wire/client/config.h>
// The |EventHandler| is a derived class that we pass into the |fidl::WireClient| to handle incoming
// events asynchronously.
class EventHandler : public fidl::WireAsyncEventHandler<examples_canvas_baseline::Instance> {
public:
// Handler for |OnDrawn| events sent from the server.
void OnDrawn(fidl::WireEvent<examples_canvas_baseline::Instance::OnDrawn>* event) override {
::examples_canvas_baseline::wire::Point top_left = event->top_left;
::examples_canvas_baseline::wire::Point bottom_right = event->bottom_right;
FX_LOGS(INFO) << "OnDrawn event received: top_left: Point { x: " << top_left.x
<< ", y: " << top_left.y << " }, bottom_right: Point { x: " << bottom_right.x
<< ", y: " << bottom_right.y << " }";
loop_.Quit();
}
void on_fidl_error(fidl::UnbindInfo error) override { FX_LOGS(ERROR) << error; }
void handle_unknown_event(
fidl::UnknownEventMetadata<examples_canvas_baseline::Instance> metadata) override {
FX_LOGS(WARNING) << "Received an unknown event with ordinal " << metadata.event_ordinal;
}
explicit EventHandler(async::Loop& loop) : loop_(loop) {}
private:
async::Loop& loop_;
};
// A helper function that takes a coordinate in string form, like "123,-456", and parses it into a
// a struct of the form |{ in64 x; int64 y; }|.
::examples_canvas_baseline::wire::Point ParsePoint(std::string_view input) {
int64_t x = 0;
int64_t y = 0;
size_t index = input.find(',');
if (index != std::string::npos) {
std::from_chars(input.data(), input.data() + index, x);
std::from_chars(input.data() + index + 1, input.data() + input.length(), y);
}
return ::examples_canvas_baseline::wire::Point{.x = x, .y = y};
}
using Line = ::fidl::Array<::examples_canvas_baseline::wire::Point, 2>;
// A helper function that takes a coordinate pair in string form, like "1,2:-3,-4", and parses it
// into an array of 2 |Point| structs.
Line ParseLine(const std::string& action) {
auto input = std::string_view(action);
size_t index = input.find(':');
if (index != std::string::npos) {
return {ParsePoint(input.substr(0, index)), ParsePoint(input.substr(index + 1))};
}
return {};
}
int main(int argc, const char** argv) {
FX_LOGS(INFO) << "Started";
// Retrieve component configuration.
auto conf = config::Config::TakeFromStartupHandle();
// Start up an async loop and dispatcher.
async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
async_dispatcher_t* dispatcher = loop.dispatcher();
// [START connect-protocol]
// Connect to the 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<examples_canvas_baseline::Instance>();
if (!client_end.is_ok()) {
FX_LOGS(ERROR) << "Synchronous error when connecting to the |Instance| protocol: "
<< client_end.status_string();
return -1;
}
// Create an instance of the event handler.
EventHandler event_handler(loop);
// Create an asynchronous client using the newly-established connection.
fidl::WireClient client(std::move(*client_end), dispatcher, &event_handler);
FX_LOGS(INFO) << "Outgoing connection enabled";
// [END connect-protocol]
for (const auto& action : conf.script()) {
// If the next action in the script is to "WAIT", block until an |OnDrawn| event is received
// from the server.
if (action == "WAIT") {
loop.Run();
loop.ResetQuit();
continue;
}
// Draw a line to the canvas by calling the server, using the two points we just parsed
// above as arguments.
Line line = ParseLine(action);
fidl::Status status = client->AddLine(line);
if (!status.ok()) {
// Check that our one-way call was enqueued successfully, and handle the error appropriately.
// In the case of this example, there is nothing we can do to recover here, except to log an
// error and exit the program.
FX_LOGS(ERROR) << "Could not send AddLine request: " << status.status_string();
return -1;
}
FX_LOGS(INFO) << "AddLine request sent: [Point { x: " << line[1].x << ", y: " << line[1].y
<< " }, Point { x: " << line[0].x << ", y: " << line[0].y << " }]";
}
// TODO(https://fxbug.dev/42156498): We need to sleep here to make sure all logs get drained. Once
// the referenced bug has been resolved, we can remove the sleep.
sleep(2);
return 0;
}