use anyhow::{bail, Error};
use diagnostics_reader::{ArchiveReader, Inspect, RetryConfig};
use tracing::*;
const INSPECT_PREFIX: &str = "INSPECT:";
pub struct InspectFetcher {
reader: Option<ArchiveReader>,
}
impl std::fmt::Debug for InspectFetcher {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("InspectFetcher").field("reader", &"opaque-ArchiveReader").finish()
}
}
impl InspectFetcher {
pub fn create(service_path: &str, selectors: Vec<String>) -> Result<InspectFetcher, Error> {
if selectors.is_empty() {
return Ok(InspectFetcher { reader: None });
}
let proxy = match fuchsia_component::client::connect_to_protocol_at_path::<
fidl_fuchsia_diagnostics::ArchiveAccessorMarker,
>(service_path)
{
Ok(proxy) => proxy,
Err(e) => bail!("Failed to connect to Inspect reader: {}", e),
};
let mut reader = ArchiveReader::new();
reader
.with_archive(proxy)
.retry(RetryConfig::never())
.add_selectors(Self::process_selectors(selectors)?.into_iter());
Ok(InspectFetcher { reader: Some(reader) })
}
pub async fn fetch(&mut self) -> Result<String, Error> {
match &self.reader {
None => Ok("[]".to_string()),
Some(reader) => {
Ok(reader.snapshot_raw::<Inspect, serde_json::Value>().await?.to_string())
}
}
}
fn process_selectors(selectors: Vec<String>) -> Result<Vec<String>, Error> {
let get_inspect = |s: String| -> Option<std::string::String> {
if &s[..INSPECT_PREFIX.len()] == INSPECT_PREFIX {
Some(s[INSPECT_PREFIX.len()..].to_string())
} else {
warn!("All selectors should begin with 'INSPECT:' - '{}'", s);
None
}
};
Ok(selectors.into_iter().filter_map(get_inspect).collect())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[fuchsia::test]
async fn test_selector_acceptance() {
let empty_vec = vec![];
let ok_selectors =
vec!["INSPECT:moniker:path:leaf".to_string(), "INSPECT:name:nodes:item".to_string()];
let ok_processed = vec!["moniker:path:leaf".to_string(), "name:nodes:item".to_string()];
let bad_selector = vec![
"INSPECT:moniker:path:leaf".to_string(),
"FOO:moniker:path:leaf".to_string(),
"INSPECT:name:nodes:item".to_string(),
];
assert_eq!(InspectFetcher::process_selectors(empty_vec).unwrap(), Vec::<String>::new());
assert_eq!(InspectFetcher::process_selectors(ok_selectors).unwrap(), ok_processed);
assert_eq!(InspectFetcher::process_selectors(bad_selector).unwrap(), ok_processed);
}
}