pub(crate) mod transport;
mod xml;
use ciborium::Value as CborValue;
use indexmap::IndexMap;
use serde_json::Value as JsonValue;
use vantage_core::{Result, error};
use vantage_types::Record;
use crate::account::AwsAccount;
use crate::condition::AwsCondition;
use crate::dispatch::{OperationDescriptor, json_to_cbor, lookup_path};
pub(crate) use transport::restxml_call;
pub(crate) async fn execute(
account: &AwsAccount,
op: &OperationDescriptor<'_>,
resolved: &[AwsCondition],
) -> Result<JsonValue> {
let (method, path, query) = transport::build_request(op.target, resolved)?;
let body = restxml_call(account, op.service, &method, &path, &query).await?;
xml::parse_xml_response(&body)
}
pub(crate) fn parse_records(
op: &OperationDescriptor<'_>,
resp: JsonValue,
id_field: Option<&str>,
) -> Result<IndexMap<String, Record<CborValue>>> {
let array = match lookup_path(&resp, op.array_key) {
Some(JsonValue::Array(a)) => a.clone(),
Some(JsonValue::Object(_)) => vec![lookup_path(&resp, op.array_key).unwrap().clone()],
Some(JsonValue::String(s)) if s.is_empty() => Vec::new(),
Some(other) => {
return Err(error!(
"AWS REST-XML response array key has unexpected shape",
array_key = op.array_key,
got = format!("{:?}", other),
body = format!("{}", resp)
));
}
None => Vec::new(),
};
let scalar_field = id_field.unwrap_or("value");
let mut out = IndexMap::with_capacity(array.len());
for (idx, item) in array.into_iter().enumerate() {
let obj = match item {
JsonValue::Object(map) => map,
JsonValue::String(_) | JsonValue::Number(_) => {
let mut m = serde_json::Map::new();
m.insert(scalar_field.to_string(), item);
m
}
other => {
return Err(error!(
"AWS REST-XML response array entry is not an object or scalar",
index = idx,
got = format!("{:?}", other)
));
}
};
let id = id_field
.and_then(|f| obj.get(f))
.and_then(|v| match v {
JsonValue::String(s) => Some(s.clone()),
JsonValue::Number(n) => Some(n.to_string()),
_ => None,
})
.unwrap_or_else(|| idx.to_string());
let record: Record<CborValue> =
obj.into_iter().map(|(k, v)| (k, json_to_cbor(v))).collect();
out.insert(id, record);
}
Ok(out)
}