blob: 079b0d871ee922ac6de7587cad129f8e9ec4650c [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.
// Fetches diagnostic data.
use {
anyhow::{bail, Error},
diagnostics_reader::{ArchiveReader, DataType},
log::error,
triage::DiagnosticData,
triage::Source,
};
// Selectors for Inspect data must start with this exact string.
const INSPECT_PREFIX: &str = "INSPECT:";
// The capability name for the Inspect reader
const INSPECT_SERVICE_PATH: &str = "/svc/fuchsia.diagnostics.FeedbackArchiveAccessor";
// Durable connection to Archivist
#[derive(Debug)]
pub struct DiagnosticFetcher {
inspect: InspectFetcher,
}
#[derive(Debug)]
pub struct Selectors {
pub(crate) inspect_selectors: Vec<String>,
}
impl DiagnosticFetcher {
pub fn create(selectors: Selectors) -> Result<DiagnosticFetcher, Error> {
Ok(DiagnosticFetcher { inspect: InspectFetcher::create(selectors.inspect_selectors)? })
}
pub async fn get_diagnostics(&mut self) -> Result<Vec<DiagnosticData>, Error> {
let inspect_data = DiagnosticData::new(
"inspect.json".to_string(),
Source::Inspect,
self.inspect.fetch().await?,
)?;
Ok(vec![inspect_data])
}
}
impl Selectors {
pub fn new() -> Selectors {
Selectors { inspect_selectors: Vec::new() }
}
pub fn with_inspect_selectors(mut self, selectors: Vec<String>) -> Self {
self.inspect_selectors.extend(selectors);
self
}
}
struct InspectFetcher {
// If we have no selectors, we don't want to actually fetch anything.
// (Fetching with no selectors fetches all Inspect data.)
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(selectors: Vec<String>) -> Result<InspectFetcher, Error> {
if selectors.len() == 0 {
return Ok(InspectFetcher { reader: None });
}
let proxy = match fuchsia_component::client::connect_to_service_at_path::<
fidl_fuchsia_diagnostics::ArchiveAccessorMarker,
>(INSPECT_SERVICE_PATH)
{
Ok(proxy) => proxy,
Err(e) => bail!("Failed to connect to Inspect reader: {}", e),
};
let reader = ArchiveReader::new().with_archive(proxy);
let get_inspect = |s: String| -> Option<std::string::String> {
if &s[..INSPECT_PREFIX.len()] == INSPECT_PREFIX {
Some(s[INSPECT_PREFIX.len()..].to_string())
} else {
error!("All selectors should begin with 'INSPECT:' - '{}'", s);
None
}
};
let selectors = selectors.into_iter().filter_map(get_inspect);
let reader = reader.retry_if_empty(false).add_selectors(selectors);
Ok(InspectFetcher { reader: Some(reader) })
}
/// This returns a String in JSON format because that's what TriageLib needs.
pub async fn fetch(&mut self) -> Result<String, Error> {
match &self.reader {
None => Ok("[]".to_string()),
Some(reader) => {
// TODO(fxbug.dev/62480): Make TriageLib accept structured data
Ok(reader.snapshot_raw(DataType::Inspect).await?.to_string())
}
}
}
}