use serde_json::{Map, Value, json};
use super::rows::decode::rows_of;
use crate::boundary::codec::fields::{bool_of, opt, opt_val, str_of, u64_of};
use crate::doctor::{Report, Row};
use crate::wire::rendezvous::Standing;
pub(super) const KIND: &str = "doctor";
pub(super) fn reply(report: &Report) -> Value {
let mut map = Map::new();
map.insert("ok".to_owned(), json!(true));
map.insert("kind".to_owned(), json!(KIND));
map.insert(
"rows".to_owned(),
Value::Array(report.rows.iter().map(row).collect()),
);
if let Some(s) = &report.rendezvous {
map.insert(
"rendezvous".to_owned(),
json!({ "active": s.active, "published": s.published, "calls": s.calls,
"punched": s.punched, "served": s.served, "accepted": s.accepted,
"last_poll_unix": s.last_poll_unix }),
);
}
Value::Object(map)
}
pub(super) fn report_of(o: &Map<String, Value>) -> Result<Report, String> {
Ok(Report {
rows: rows_of(o, row_of)?,
rendezvous: opt_val(o, "rendezvous", standing_of)?,
})
}
fn row(row: &Row) -> Value {
let mut map = Map::new();
map.insert("check".to_owned(), json!(row.check));
map.insert("ok".to_owned(), json!(row.ok));
map.insert("fact".to_owned(), json!(row.fact));
if let Some(remedy) = &row.remedy {
map.insert("remedy".to_owned(), json!(remedy));
}
Value::Object(map)
}
fn row_of(v: &Value) -> Result<Row, String> {
let o = v.as_object().ok_or("doctor row: not an object")?;
Ok(Row {
check: str_of(o, "check")?,
ok: bool_of(o, "ok")?,
fact: str_of(o, "fact")?,
remedy: opt(o, "remedy", str_of)?,
})
}
fn standing_of(v: &Value) -> Result<Standing, String> {
let s = v.as_object().ok_or("doctor: rendezvous is not an object")?;
Ok(Standing {
active: bool_of(s, "active")?,
published: u64_of(s, "published")?,
calls: u64_of(s, "calls")?,
punched: u64_of(s, "punched")?,
served: u64_of(s, "served")?,
accepted: opt(s, "accepted", u64_of)?.unwrap_or(0),
last_poll_unix: u64_of(s, "last_poll_unix")?,
})
}