| // Copyright 2019 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 "src/developer/shell/console/executor.h" |
| |
| #include <lib/fdio/spawn.h> |
| #include <lib/zx/process.h> |
| #include <zircon/compiler.h> |
| #include <zircon/status.h> |
| |
| #include <iostream> |
| #include <map> |
| #include <memory> |
| #include <vector> |
| |
| #include "src/developer/shell/common/result.h" |
| |
| namespace shell::console { |
| |
| Executor::Executor(fidl::WireSyncClient<fuchsia_shell::Shell>* client) |
| : context_id_(0), client_(client) {} |
| |
| Executor::~Executor() = default; |
| |
| Err Executor::Execute(std::unique_ptr<Command> command, |
| fit::function<void(const std::string&)> out_callback, |
| fit::function<void(const std::string&)> err_callback, |
| fit::callback<void()> done_callback) { |
| if (!command->parse_error().empty()) { |
| err_callback("Parse:\n" + command->parse_error()); |
| return Err(ZX_ERR_NEXT, zx_status_get_string(ZX_ERR_NEXT)); |
| } |
| if (command->nodes().empty()) { |
| return Err(ZX_ERR_NEXT, zx_status_get_string(ZX_ERR_NEXT)); |
| } |
| context_id_ += 1; |
| fidl::WireResult<fuchsia_shell::Shell::CreateExecutionContext> create_result = |
| (*client_)->CreateExecutionContext(context_id_); |
| if (!create_result.ok()) { |
| return Err(create_result.status(), create_result.FormatDescription()); |
| } |
| |
| // TODO: Make sure that add_result is small enough to fit in a single FIDL message. Otherwise, |
| // split it. |
| fidl::WireResult<fuchsia_shell::Shell::AddNodes> add_result = |
| (*client_)->AddNodes(context_id_, command->nodes().DefsAsVectorView()); |
| if (!add_result.ok()) { |
| return Err(add_result.status(), add_result.FormatDescription()); |
| } |
| |
| fidl::WireResult<fuchsia_shell::Shell::ExecuteExecutionContext> execute_result = |
| (*client_)->ExecuteExecutionContext(context_id_); |
| if (!execute_result.ok()) { |
| return Err(execute_result.status(), execute_result.FormatDescription()); |
| } |
| |
| class EventHandler : public fidl::WireSyncEventHandler<fuchsia_shell::Shell> { |
| public: |
| EventHandler(fit::function<void(const std::string&)>& out_callback, |
| fit::function<void(const std::string&)>& err_callback) |
| : out_callback_(out_callback), err_callback_(err_callback) {} |
| |
| bool done() const { return done_; } |
| |
| void OnTextResult(fidl::WireEvent<fuchsia_shell::Shell::OnTextResult>* event) override { |
| out_callback_(event->result.data()); |
| } |
| |
| void OnDumpDone(fidl::WireEvent<fuchsia_shell::Shell::OnDumpDone>* event) override {} |
| |
| void OnExecutionDone(fidl::WireEvent<fuchsia_shell::Shell::OnExecutionDone>* event) override { |
| done_ = true; |
| } |
| |
| void OnError(fidl::WireEvent<fuchsia_shell::Shell::OnError>* event) override { |
| err_callback_(event->error_message.data()); |
| } |
| |
| void OnResult(fidl::WireEvent<fuchsia_shell::Shell::OnResult>* event) override { |
| if (event->partial_result) { |
| err_callback_("Result too large: partial results not supported"); |
| } else { |
| std::stringstream ss; |
| shell::common::DeserializeResult deserialize; |
| deserialize.Deserialize(event->nodes)->Dump(ss); |
| out_callback_(ss.str()); |
| } |
| } |
| |
| private: |
| fit::function<void(const std::string&)>& out_callback_; |
| fit::function<void(const std::string&)>& err_callback_; |
| bool done_ = false; |
| }; |
| |
| EventHandler event_handler(out_callback, err_callback); |
| while (!event_handler.done()) { |
| ::fidl::Status result = client_->HandleOneEvent(event_handler); |
| if (!result.ok()) { |
| return Err(result.status(), result.status_string()); |
| } |
| } |
| if (done_callback != nullptr) { |
| done_callback(); |
| } |
| |
| return Err(ZX_ERR_NEXT, zx_status_get_string(ZX_ERR_NEXT)); |
| } |
| |
| void Executor::KillForegroundTask() { |
| // TODO(fidl-tools-team): What happens when we hit ^C? |
| } |
| |
| } // namespace shell::console |