blob: 8c1d7b7427c15112e245b1a72ecfff5ff19fa843 [file] [log] [blame]
// Copyright 2020 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 {
crate::io::Directory,
futures::future::{BoxFuture, FutureExt},
};
static SPACER: &str = " ";
static UNKNOWN: &str = "UNKNOWN";
/// Used as a helper function to traverse <realm id>/r/, <realm id>/c/,
/// <component instance id>/c/, following through into their id subdirectories.
async fn open_id_directories(id_dir: Directory) -> Vec<Directory> {
let mut realms = vec![];
for id in id_dir.entries().await {
assert!(id.chars().all(char::is_numeric));
let realm = id_dir.open_dir(&id).await;
realms.push(realm);
}
realms
}
fn visit_child_realms(child_realms_dir: Directory) -> BoxFuture<'static, Vec<V1Realm>> {
async move {
let mut child_realms = vec![];
// visit all entries within <realm id>/r/
for realm_name in child_realms_dir.entries().await {
// visit <realm id>/r/<child realm name>/<child realm id>/
let id_dir = child_realms_dir.open_dir(&realm_name).await;
for realm_dir in open_id_directories(id_dir).await.drain(..) {
child_realms.push(V1Realm::create(realm_dir).await);
}
}
child_realms
}
.boxed()
}
/// Traverses a directory of named components, and recurses into each component directory.
/// Each component visited is added to the |child_components| vector.
fn visit_child_components(child_components_dir: Directory) -> BoxFuture<'static, Vec<V1Component>> {
async move {
let mut child_components = vec![];
for component_name in child_components_dir.entries().await {
// Visits */c/<component name>/<component instance id>.
let id_dir = child_components_dir.open_dir(&component_name).await;
for component_dir in open_id_directories(id_dir).await.drain(..) {
child_components.push(V1Component::create(component_dir).await);
}
}
child_components
}
.boxed()
}
async fn get_capabilities(capability_dir: Directory) -> Vec<String> {
let mut entries = capability_dir.entries().await;
for (index, name) in entries.iter().enumerate() {
if name == "svc" {
entries.remove(index);
let svc_dir = capability_dir.open_dir("svc").await;
let mut svc_entries = svc_dir.entries().await;
entries.append(&mut svc_entries);
break;
}
}
entries.sort_unstable();
entries
}
#[derive(Debug, Eq, PartialEq)]
pub struct V1Realm {
name: String,
job_id: u32,
child_realms: Vec<V1Realm>,
child_components: Vec<V1Component>,
}
impl V1Realm {
pub async fn create(realm_dir: Directory) -> V1Realm {
let name = realm_dir.read_file("name").await;
let job_id = realm_dir.read_file("job-id").await.parse::<u32>().unwrap();
let child_realms_dir = realm_dir.open_dir("r").await;
let child_components_dir = realm_dir.open_dir("c").await;
V1Realm {
name,
job_id,
child_realms: visit_child_realms(child_realms_dir).await,
child_components: visit_child_components(child_components_dir).await,
}
}
pub fn print_tree_recursive(&self, level: usize) {
let space = SPACER.repeat(level - 1);
println!("{}{} (realm)", space, self.name);
for child in &self.child_components {
child.print_tree_recursive(level + 1);
}
for child in &self.child_realms {
child.print_tree_recursive(level + 1);
}
}
pub fn print_details_recursive(&self, moniker_prefix: &str, filter: &str) {
let moniker = format!("{}{}", moniker_prefix, self.name);
// Print information about realms if there is no filter
if filter.is_empty() || self.name.contains(filter) {
println!("Moniker: {}", moniker);
println!("Job ID: {}", self.job_id);
println!("Type: v1 realm");
println!("");
}
// Recurse on child components
let moniker_prefix = format!("{}/", moniker);
for child in &self.child_components {
child.print_details_recursive(&moniker_prefix, filter);
}
// Recurse on child realms
for child in &self.child_realms {
child.print_details_recursive(&moniker_prefix, filter);
}
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct V1Component {
job_id: u32,
name: String,
url: String,
merkleroot: Option<String>,
incoming_capabilities: Vec<String>,
outgoing_capabilities: Option<Vec<String>>,
child_components: Vec<V1Component>,
}
impl V1Component {
async fn create(component_dir: Directory) -> V1Component {
let job_id = component_dir.read_file("job-id").await.parse::<u32>().unwrap();
let url = component_dir.read_file("url").await;
let name = component_dir.read_file("name").await;
let in_dir = component_dir.open_dir("in").await;
let merkleroot = if in_dir.exists("pkg").await {
let pkg_dir = in_dir.open_dir("pkg").await;
if pkg_dir.exists("meta").await {
Some(pkg_dir.read_file("meta").await)
} else {
None
}
} else {
None
};
let child_components = if component_dir.exists("c").await {
let child_components_dir = component_dir.open_dir("c").await;
visit_child_components(child_components_dir).await
} else {
vec![]
};
let incoming_capabilities = get_capabilities(in_dir).await;
let outgoing_capabilities = if component_dir.exists("out").await {
if let Some(out_dir) = component_dir.open_dir_timeout("out").await {
Some(get_capabilities(out_dir).await)
} else {
// The directory exists, but it couldn't be opened.
// This is probably because it isn't being served.
None
}
} else {
// The directory doesn't exist. This is probably because
// there is no runtime on the component.
None
};
V1Component {
job_id,
name,
url,
merkleroot,
incoming_capabilities,
outgoing_capabilities,
child_components,
}
}
fn print_tree_recursive(&self, level: usize) {
let space = SPACER.repeat(level - 1);
println!("{}{}", space, self.name);
for child in &self.child_components {
child.print_tree_recursive(level + 1);
}
}
fn print_details_recursive(&self, moniker_prefix: &str, filter: &str) {
let moniker = format!("{}{}", moniker_prefix, self.name);
let unknown_merkle = UNKNOWN.to_string();
let merkle = self.merkleroot.as_ref().unwrap_or(&unknown_merkle);
if filter.is_empty() || self.url.contains(filter) || self.name.contains(filter) {
println!("Moniker: {}", moniker);
println!("URL: {}", self.url);
println!("Job ID: {}", self.job_id);
println!("Merkle Root: {}", merkle);
println!("Type: v1 component");
println!("Incoming Capabilities ({}):", self.incoming_capabilities.len());
for capability in &self.incoming_capabilities {
println!("{}{}", SPACER, capability);
}
if let Some(outgoing_capabilities) = &self.outgoing_capabilities {
println!("Outgoing Capabilities ({}):", outgoing_capabilities.len());
for capability in outgoing_capabilities {
println!("{}{}", SPACER, capability);
}
}
println!("");
}
// Recurse on children
let moniker_prefix = format!("{}/", moniker);
for child in &self.child_components {
child.print_details_recursive(&moniker_prefix, filter);
}
}
}