use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use bytes::{Buf, Bytes};
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use crate::models::streams::async_read::AsyncReadByteStream;
pub struct H2RecvRead {
recv: h2::RecvStream,
leftover: Bytes,
}
impl H2RecvRead {
pub fn new(recv: h2::RecvStream) -> Self {
Self {
recv,
leftover: Bytes::new(),
}
}
}
impl AsyncRead for H2RecvRead {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<io::Result<()>> {
loop {
if !self.leftover.is_empty() {
let n = self.leftover.len().min(buf.remaining());
buf.put_slice(&self.leftover[..n]);
self.leftover.advance(n);
return Poll::Ready(Ok(()));
}
match Pin::new(&mut self.recv).poll_data(cx) {
Poll::Ready(Some(Ok(data))) => {
let _ = self.recv.flow_control().release_capacity(data.len());
self.leftover = data;
}
Poll::Ready(Some(Err(e))) => return Poll::Ready(Err(io::Error::other(e))),
Poll::Ready(None) => return Poll::Ready(Ok(())),
Poll::Pending => return Poll::Pending,
}
}
}
}
pub struct H2SendWrite {
send: h2::SendStream<Bytes>,
finished: bool,
}
impl H2SendWrite {
pub fn new(send: h2::SendStream<Bytes>) -> Self {
Self {
send,
finished: false,
}
}
}
impl AsyncWrite for H2SendWrite {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
let me = self.get_mut();
if buf.is_empty() {
return Poll::Ready(Ok(0));
}
me.send.reserve_capacity(buf.len());
let granted = match me.send.poll_capacity(cx) {
Poll::Ready(Some(Ok(n))) => n,
Poll::Ready(Some(Err(e))) => return Poll::Ready(Err(io::Error::other(e))),
Poll::Ready(None) => {
return Poll::Ready(Err(io::Error::new(
io::ErrorKind::BrokenPipe,
"h2 send stream closed before capacity available",
)));
}
Poll::Pending => return Poll::Pending,
};
if granted == 0 {
return Poll::Pending;
}
let to_send = granted.min(buf.len());
let chunk = Bytes::copy_from_slice(&buf[..to_send]);
me.send.send_data(chunk, false).map_err(io::Error::other)?;
Poll::Ready(Ok(to_send))
}
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
let me = self.get_mut();
if !me.finished {
me.finished = true;
me.send
.send_data(Bytes::new(), true)
.map_err(io::Error::other)?;
}
Poll::Ready(Ok(()))
}
}
pub type HttpByteStream = AsyncReadByteStream<H2RecvRead>;