use crate::Body;
use bytes::Bytes;
use deno_core::*;
use deno_error::JsErrorBox;
use http_body_util::BodyExt;
use std::borrow::Cow;
use std::rc::Rc;
pub struct HttpBodyResource {
state: Rc<AsyncRefCell<ReadState>>,
cancel: Rc<CancelHandle>,
}
struct ReadState {
body: Body,
unread: Bytes,
}
impl HttpBodyResource {
pub fn new(body: Body) -> Self {
Self {
state: Rc::new(AsyncRefCell::new(ReadState {
body,
unread: Bytes::new(),
})),
cancel: CancelHandle::new_rc(),
}
}
}
impl Resource for HttpBodyResource {
fn name(&self) -> Cow<'_, str> {
"httpBody".into()
}
fn close(self: Rc<Self>) {
self.cancel.cancel();
}
fn read(self: Rc<Self>, limit: usize) -> AsyncResult<BufView> {
let cancel = self.cancel.clone();
Box::pin(
async move {
if limit == 0 {
return Ok(BufView::empty());
}
let mut state = self.state.borrow_mut().await;
while state.unread.is_empty() {
match state.body.frame().await {
Some(Ok(frame)) => {
state.unread = frame.into_data().map_err(|_| {
JsErrorBox::generic("Failed to get bytes from frame")
})?;
}
Some(Err(e)) => {
return Err(JsErrorBox::generic(format!("Stream error: {}", e)));
}
None => return Ok(BufView::empty()),
}
}
let take = limit.min(state.unread.len());
Ok(BufView::from(state.unread.split_to(take)))
}
.try_or_cancel(cancel),
)
}
}