use async_trait::async_trait;
use bytes::Bytes;
use cratefield_core::{HttpClient, HttpError};
use worker::send::IntoSendFuture;
use worker::{Fetch, Headers, Method, Request as WorkerRequest, RequestInit};
pub struct FetchClient;
#[async_trait]
impl HttpClient for FetchClient {
async fn send(
&self,
request: http::Request<Bytes>,
) -> Result<http::Response<Bytes>, HttpError> {
let (parts, body) = request.into_parts();
let mut init = RequestInit::new();
init.method = Method::from(parts.method.as_str().to_string());
let headers = Headers::new();
for (name, value) in &parts.headers {
let _ = headers.set(name.as_str(), value.to_str().unwrap_or_default());
}
init.headers = headers;
if !body.is_empty() {
let body_text = String::from_utf8(body.to_vec())
.map_err(|err| HttpError::Transport(err.to_string()))?;
init.with_body(Some(worker::wasm_bindgen::JsValue::from_str(&body_text)));
}
let worker_request = WorkerRequest::new_with_init(&parts.uri.to_string(), &init)
.map_err(|err| HttpError::Transport(err.to_string()))?;
let mut response = Fetch::Request(worker_request)
.send()
.into_send()
.await
.map_err(|err| HttpError::Transport(err.to_string()))?;
let mut builder = http::Response::builder().status(response.status_code());
let response_headers = response.headers();
if let Some(headers) = builder.headers_mut() {
for (name, value) in response_headers {
if let (Ok(name), Ok(value)) = (
http::HeaderName::try_from(name.as_str()),
http::HeaderValue::try_from(value.as_str()),
) {
headers.insert(name, value);
}
}
}
let bytes = response
.bytes()
.into_send()
.await
.map_err(|err| HttpError::Transport(err.to_string()))?;
builder
.body(Bytes::from(bytes))
.map_err(|err| HttpError::Transport(err.to_string()))
}
}