///|
/// Decoding helpers for the `App` records the CLI and the daemon exchange.
///
/// The daemon answering a request may have been built from a different pm3
/// than the client: it writes the fields its own build knew about, so a
/// record written before a field existed simply lacks it. Failing on that
/// would turn one missing key into "the daemon manages nothing", so missing
/// fields are backfilled from a default record before decoding. Fields this
/// build does not know are ignored by the decoder, which keeps the other
/// direction — a new daemon answering an older client — working too.
///|
/// Fill in the fields a record written by another pm3 build did not have.
pub fn with_app_defaults(json : Json) -> Json {
match json {
Json::Object(members) =>
match @json.to_json(App::new("", "", [])) {
Json::Object(defaults) =>
for key, value in defaults {
if !members.contains(key) {
members.set(key, value)
}
}
_ => ()
}
_ => ()
}
json
}
///|
/// Decode a JSON list of `App` records as one daemon reported them. `None`
/// means the payload is not a list of apps this build can read, so a caller
/// can report a real error instead of showing an empty process list.
pub fn app_records_from_json(json : Json) -> Array[App]? {
match json {
Json::Array(items) => {
let apps : Array[App] = []
for item in items {
let app : App = @json.from_json(with_app_defaults(item)) catch {
_ => return None
}
apps.push(app)
}
Some(apps)
}
_ => None
}
}