use std::collections::HashMap;
use anyhow::{Context, Result};
use axum::body::Body;
use base64::Engine;
use bytes::Bytes;
pub async fn encode_request(
req: axum::http::Request<Body>,
max_body_size: usize,
) -> Result<serde_json::Value> {
let (parts, body) = req.into_parts();
let body_bytes = axum::body::to_bytes(body, max_body_size)
.await
.context("read request body")?;
let headers: HashMap<String, String> = parts
.headers
.iter()
.filter_map(|(k, v)| Some((k.to_string(), v.to_str().ok()?.to_string())))
.collect();
let (body_value, body_encoding) = match String::from_utf8(body_bytes.to_vec()) {
Ok(s) => (s, None),
Err(e) => {
let encoded = base64::engine::general_purpose::STANDARD.encode(e.into_bytes());
(encoded, Some("base64"))
}
};
let mut payload = serde_json::json!({
"method": parts.method.to_string(),
"uri": parts.uri.to_string(),
"headers": headers,
"body": body_value,
});
if let Some(enc) = body_encoding {
payload["body_encoding"] = serde_json::json!(enc);
}
Ok(payload)
}
pub fn decode_response(value: serde_json::Value) -> Result<axum::http::Response<Body>> {
let status = value.get("status").and_then(|v| v.as_u64()).unwrap_or(200) as u16;
let body_str = value.get("body").and_then(|v| v.as_str()).unwrap_or("");
let body_encoding = value.get("body_encoding").and_then(|v| v.as_str());
let body_bytes = if body_encoding == Some("base64") {
base64::engine::general_purpose::STANDARD
.decode(body_str)
.context("decode base64 response body")?
} else {
body_str.as_bytes().to_vec()
};
let mut builder = axum::http::Response::builder().status(status);
if let Some(headers) = value.get("headers").and_then(|v| v.as_object()) {
for (k, v) in headers {
if let Some(v_str) = v.as_str() {
builder = builder.header(k.as_str(), v_str);
}
}
}
builder
.body(Body::from(Bytes::from(body_bytes)))
.context("build response")
}