blob: 633dcf1457367922c03f73f618661b7cd70ce6ab [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.
use {
anyhow::{Context, Result},
component_hub::{io::Directory, select::find_components},
fidl::endpoints::ProtocolMarker,
fidl_fuchsia_developer_remotecontrol as fremotecontrol, fidl_fuchsia_driver_development as fdd,
fidl_fuchsia_io as fio,
fuchsia_zircon_status::Status,
};
/// Combines pagination results into a single vector.
pub async fn get_device_info(
service: &fdd::DriverDevelopmentProxy,
device_filter: &[String],
) -> Result<Vec<fdd::DeviceInfo>> {
let (iterator, iterator_server) =
fidl::endpoints::create_proxy::<fdd::DeviceInfoIteratorMarker>()?;
service
.get_device_info(&mut device_filter.iter().map(String::as_str), iterator_server)
.context("FIDL call to get device info failed")?;
let mut info_result = Vec::new();
loop {
let mut device_info =
iterator.get_next().await.context("FIDL call to get device info failed")?;
if device_info.len() == 0 {
break;
}
info_result.append(&mut device_info)
}
Ok(info_result)
}
/// Combines pagination results into a single vector.
pub async fn get_driver_info(
service: &fdd::DriverDevelopmentProxy,
driver_filter: &[String],
) -> Result<Vec<fdd::DriverInfo>> {
let (iterator, iterator_server) =
fidl::endpoints::create_proxy::<fdd::DriverInfoIteratorMarker>()?;
service
.get_driver_info(&mut driver_filter.iter().map(String::as_str), iterator_server)
.context("FIDL call to get driver info failed")?;
let mut info_result = Vec::new();
loop {
let mut driver_info =
iterator.get_next().await.context("FIDL call to get driver info failed")?;
if driver_info.len() == 0 {
break;
}
info_result.append(&mut driver_info)
}
Ok(info_result)
}
pub async fn remotecontrol_connect<S: ProtocolMarker>(
remote_control: &fremotecontrol::RemoteControlProxy,
selector: &str,
) -> Result<S::Proxy, anyhow::Error> {
let (proxy, server_end) = fidl::endpoints::create_proxy::<S>()
.with_context(|| format!("failed to create proxy to {}", S::NAME))?;
let _: fremotecontrol::ServiceMatch = remote_control
.connect(selectors::parse_selector(selector)?, server_end.into_channel())
.await?
.map_err(|e| {
anyhow::anyhow!("failed to connect to {} as {}: {:?}", S::NAME, selector, e)
})?;
Ok(proxy)
}
async fn find_components_with_capability(
remote_proxy: &fremotecontrol::RemoteControlProxy,
capability: &str,
) -> Result<Vec<String>> {
let (root, dir_server) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>()
.context("creating hub root proxy")?;
remote_proxy
.open_hub(dir_server)
.await?
.map_err(|i| Status::ok(i).unwrap_err())
.context("opening hub")?;
let hub_dir = Directory::from_proxy(root);
Ok(find_components(capability.to_string(), hub_dir)
.await?
.iter()
.map(|c| c.to_string().split_off(1))
.collect())
}
/// Find the components that expose a given capability, and let the user
/// request which component they would like to connect to.
pub async fn user_choose_selector(
remote_control: &fremotecontrol::RemoteControlProxy,
capability: &str,
) -> Result<String> {
let capabilities = find_components_with_capability(&remote_control, capability).await?;
println!("Please choose which component to connect to:");
for (i, component) in capabilities.iter().enumerate() {
println!(" {}: {}", i, component)
}
let mut line_editor = rustyline::Editor::<()>::new();
loop {
let line = line_editor.readline("$ ")?;
let choice = line.trim().parse::<usize>();
if choice.is_err() {
println!("Error: please choose a value.");
continue;
}
let choice = choice.unwrap();
if choice >= capabilities.len() {
println!("Error: please choose a correct value.");
continue;
}
// TODO(fxbug.dev/85516): We have to replace ':' with '*' because they are parsed
// incorrectly in a selector.
return Ok(capabilities[choice].replace(":", "*") + ":expose:" + capability);
}
}