use anyhow::{anyhow, Result};
#[cfg(feature = "json")]
use serde::de::DeserializeOwned;
use std::collections::HashMap;
use wasi::http::types::{IncomingBody, IncomingResponse};
use wasi::io::streams::{InputStream, StreamError};
pub struct Response {
status: u16,
headers: HashMap<String, String>,
input_stream: InputStream,
_incoming_body: IncomingBody,
}
impl Response {
pub(crate) fn new(incoming_response: IncomingResponse) -> Result<Self> {
let status = incoming_response.status();
let mut headers: HashMap<String, String> = HashMap::new();
let headers_handle = incoming_response.headers();
for (key, value) in headers_handle.entries() {
headers.insert(key, String::from_utf8(value)?);
}
drop(headers_handle);
let incoming_body = incoming_response.consume().unwrap();
drop(incoming_response);
let input_stream = incoming_body.stream().unwrap();
Ok(Self {
status,
headers,
input_stream,
_incoming_body: incoming_body,
})
}
pub fn status(&self) -> u16 {
self.status
}
pub fn headers(&self) -> &HashMap<String, String> {
&self.headers
}
pub fn chunk(&self, len: u64) -> Result<Option<Vec<u8>>> {
match self.input_stream.blocking_read(len) {
Ok(c) => Ok(Some(c)),
Err(StreamError::Closed) => Ok(None),
Err(e) => Err(anyhow!("input_stream read failed: {e:?}"))?,
}
}
pub fn body(self) -> Result<Vec<u8>> {
let mut body = Vec::new();
while let Some(mut chunk) = self.chunk(1024 * 1024)? {
body.append(&mut chunk);
}
Ok(body)
}
#[cfg(feature = "json")]
#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
pub fn json<T: DeserializeOwned>(self) -> Result<T> {
Ok(serde_json::from_slice(self.body()?.as_ref())?)
}
}