use super::funejson::Value; /// One status for a target probed from several places. Down needs a quorum, /// so one location with a broken route cannot page anyone; a down vote below /// the quorum still counts as degraded, because something is wrong somewhere. /// /// # Panics /// Panics on an empty list, a quorum outside 1..=len, or an unknown status. pub fn aggregate_status(statuses: &[String], down_quorum: i64) -> String { if statuses.is_empty() { panic!("statuses must not be empty"); } if down_quorum < 1 || down_quorum > statuses.len() as i64 { panic!("downQuorum must be 1 to {}, received {}", statuses.len(), down_quorum); } let mut down = 0i64; let mut degraded = 0i64; for s in statuses { match s.as_str() { "down" => down += 1, "degraded" => degraded += 1, "up" => {} other => panic!("unknown check status: {}", other), } } if down >= down_quorum { return "down".to_string(); } if down > 0 || degraded > 0 { "degraded".to_string() } else { "up".to_string() } } /// A `Check` from its JSON form, for adapters of capabilities built on this one. pub fn check_from_value(v: &Value) -> Check { Check { at: v.get("at").as_i64(), status: v.get("status").as_str().to_string() } } pub fn checks_from_value(v: &Value) -> Vec { v.as_arr().iter().map(check_from_value).collect() } pub fn check_to_value(c: &Check) -> Value { Value::obj(vec![("at", Value::Int(c.at)), ("status", Value::str(&c.status))]) } pub fn fune_vector(args: &[Value]) -> Value { let statuses: Vec = args[0].as_arr().iter().map(|s| s.as_str().to_string()).collect(); Value::str(&aggregate_status(&statuses, args[1].as_i64())) }