use super::funejson::Value; // Worst last. Maintenance ranks below every real problem: an outage elsewhere // during planned work is still the headline. const RANK: [&str; 5] = ["operational", "maintenance", "degraded", "partial-outage", "major-outage"]; const HEADLINE: [&str; 5] = [ "All systems operational", "Scheduled maintenance", "Degraded performance", "Partial outage", "Major outage", ]; /// The banner for a whole status page: the worst component state wins. /// /// # Panics /// Panics on no components, an empty or duplicate name, or an unknown state. pub fn status_page(components: &[Component]) -> StatusSummary { if components.is_empty() { panic!("components must not be empty"); } let mut seen: Vec<&str> = Vec::new(); let mut worst = 0usize; let mut affected: Vec = Vec::new(); for c in components { if c.name.is_empty() { panic!("component name must not be empty"); } if seen.contains(&c.name.as_str()) { panic!("duplicate component name: {}", c.name); } seen.push(&c.name); let rank = match RANK.iter().position(|r| *r == c.state) { Some(r) => r, None => panic!("unknown component state: {}", c.state), }; if rank > worst { worst = rank; } if rank > 0 { affected.push(c.name.clone()); } } StatusSummary { state: RANK[worst].to_string(), headline: HEADLINE[worst].to_string(), affected, } } /// A `Component` from its JSON form, for adapters of capabilities built on this one. pub fn component_from_value(v: &Value) -> Component { Component { name: v.get("name").as_str().to_string(), state: v.get("state").as_str().to_string() } } pub fn status_summary_to_value(s: &StatusSummary) -> Value { Value::obj(vec![ ("state", Value::str(&s.state)), ("headline", Value::str(&s.headline)), ("affected", Value::Arr(s.affected.iter().map(|a| Value::str(a)).collect())), ]) } pub fn fune_vector(args: &[Value]) -> Value { let components: Vec = args[0].as_arr().iter().map(component_from_value).collect(); status_summary_to_value(&status_page(&components)) }