| // 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(llcpp::fuchsia::shell::Shell::SyncClient* 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().ok()) { |
| std::string msg = "Invalid command: "; |
| msg.append(command->parse_error().msg); |
| err_callback(msg); |
| 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)); |
| } |
| bool done = false; |
| context_id_ += 1; |
| llcpp::fuchsia::shell::Shell::ResultOf::CreateExecutionContext create_result = |
| client_->CreateExecutionContext(context_id_); |
| if (!create_result.ok()) { |
| return Err(create_result.status(), create_result.error()); |
| } |
| |
| // TODO: Make sure that add_result is small enough to fit in a single FIDL message. Otherwise, |
| // split it. |
| llcpp::fuchsia::shell::Shell::ResultOf::AddNodes add_result = |
| client_->AddNodes(context_id_, command->nodes().DefsAsVectorView()); |
| if (!add_result.ok()) { |
| return Err(add_result.status(), add_result.error()); |
| } |
| |
| llcpp::fuchsia::shell::Shell::ResultOf::ExecuteExecutionContext execute_result = |
| client_->ExecuteExecutionContext(context_id_); |
| if (!execute_result.ok()) { |
| return Err(execute_result.status(), execute_result.error()); |
| } |
| |
| llcpp::fuchsia::shell::Shell::EventHandlers handlers; |
| handlers.on_text_result = |
| [&out_callback](llcpp::fuchsia::shell::Shell::OnTextResultResponse* message) { |
| out_callback(message->result.data()); |
| return ZX_OK; |
| }; |
| handlers.on_execution_done = |
| [&done](llcpp::fuchsia::shell::Shell::OnExecutionDoneResponse* message) { |
| done = true; |
| return ZX_OK; |
| }; |
| handlers.on_error = [&err_callback](llcpp::fuchsia::shell::Shell::OnErrorResponse* message) { |
| err_callback(message->error_message.data()); |
| return ZX_OK; |
| }; |
| handlers.on_result = [&err_callback, |
| &out_callback](llcpp::fuchsia::shell::Shell::OnResultResponse* message) { |
| if (message->partial_result) { |
| err_callback("Result too large: partial results not supported"); |
| return ZX_OK; |
| } |
| std::stringstream ss; |
| shell::common::DeserializeResult deserialize; |
| deserialize.Deserialize(message->nodes)->Dump(ss); |
| out_callback(ss.str()); |
| return ZX_OK; |
| }; |
| while (!done) { |
| ::fidl::Result result = client_->HandleEvents(handlers); |
| 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 |