diff options
Diffstat (limited to 'src/output.rs')
| -rw-r--r-- | src/output.rs | 59 |
1 files changed, 42 insertions, 17 deletions
diff --git a/src/output.rs b/src/output.rs index e2c91ec..0a8a536 100644 --- a/src/output.rs +++ b/src/output.rs @@ -116,6 +116,26 @@ pub enum IdentityReport { }, } +impl From<crate::controller::IdentityStatus> for IdentityReport { + fn from(status: crate::controller::IdentityStatus) -> Self { + use crate::controller::IdentityStatus as S; + match status { + S::NotCreated => Self::NotCreated, + S::Created { + fabric_id, + controller_node_id, + } => Self::Created { + fabric_id: fabric_id.to_string(), + controller_node_id: controller_node_id.to_string(), + }, + S::Unreadable => Self::Unreadable, + S::Inconsistent(reason) => Self::Inconsistent { + reason: reason.to_string(), + }, + } + } +} + #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct DstTransition { @@ -174,7 +194,12 @@ impl Output { pub fn print_json(&self) { match serde_json::to_string_pretty(self) { Ok(body) => println!("{body}"), - Err(error) => println!("{{\"error\": \"serialize output: {error}\"}}"), + // Build the fallback with the serializer too, so the error text + // is escaped and stdout stays valid JSON even here. + Err(error) => println!( + "{}", + serde_json::json!({ "error": format!("serialize output: {error}") }) + ), } } @@ -198,6 +223,17 @@ fn display_instant(at: Option<Timestamp>) -> String { at.map_or_else(|| "never".into(), |at| at.to_string()) } +/// The device's vendor and product names joined for display, or `None` when +/// neither is known; each caller supplies its own fallback text. +fn device_name(vendor: Option<&str>, product: Option<&str>) -> Option<String> { + let joined = [vendor, product] + .into_iter() + .flatten() + .collect::<Vec<_>>() + .join(" "); + (!joined.is_empty()).then_some(joined) +} + fn render_status(report: &StatusReport) { println!( "Configuration: loaded from {}", @@ -271,19 +307,11 @@ fn render_status(report: &StatusReport) { report.matter_time_now_microseconds ); for node in &report.nodes { - let name = [node.vendor_name.as_deref(), node.product_name.as_deref()] - .into_iter() - .flatten() - .collect::<Vec<_>>() - .join(" "); + let name = device_name(node.vendor_name.as_deref(), node.product_name.as_deref()); println!( "Node {}: {}", node.node_id, - if name.is_empty() { - "(no cached device info)" - } else { - &name - } + name.as_deref().unwrap_or("(no cached device info)") ); println!( " Last connection: {}", @@ -399,14 +427,11 @@ fn render_commissioned(outcome: &CommissionOutcome) { println!(" Fabric ID: {}", outcome.fabric_id); println!( " Device: {}", - [ + device_name( outcome.vendor_name.as_deref(), outcome.product_name.as_deref() - ] - .into_iter() - .flatten() - .collect::<Vec<_>>() - .join(" ") + ) + .unwrap_or_default() ); println!(); println!("The device remains paired with its primary ecosystem; this controller"); |
