use crate::error::{ClientError, StreamError};
use std::{fmt::Debug, io, mem};
use tokio::{io::Interest, net::tcp::OwnedReadHalf};
#[derive(Debug)]
struct NoopDecoder;
impl StreamDecoder for NoopDecoder {}
pub(crate) trait StreamDecoder: Send + Sync + Debug {
fn decode(&self, buffer: &mut Vec<u8>) -> Result<Option<Vec<u8>>, ClientError> {
if buffer.is_empty() {
return Ok(None);
}
Ok(Some(mem::take(buffer)))
}
}
#[derive(Debug)]
pub(crate) struct StreamReader {
decoder: Box<dyn StreamDecoder>,
read_stream: OwnedReadHalf,
buffer: Vec<u8>,
}
impl StreamReader {
pub(crate) fn new(read_stream: OwnedReadHalf) -> Self {
Self {
read_stream,
decoder: Box::new(NoopDecoder),
buffer: Vec::with_capacity(65535),
}
}
pub(crate) fn with_decoder(self, decoder: Box<dyn StreamDecoder>) -> Self {
Self {
decoder,
read_stream: self.read_stream,
buffer: self.buffer,
}
}
pub(crate) async fn read_next_message(&mut self) -> Result<Vec<u8>, ClientError> {
if let Ok(Some(decoded)) = self.decoder.decode(&mut self.buffer) {
tracing::trace!("Read {} bytes: {decoded:?}", decoded.len());
return Ok(decoded);
}
loop {
let ready = self
.read_stream
.ready(Interest::READABLE)
.await
.map_err(|e| StreamError::Read { source: e })?;
if ready.is_readable() {
match self.read_stream.try_read_buf(&mut self.buffer) {
Ok(0) => {
return Err(StreamError::Read {
source: io::Error::new(
io::ErrorKind::UnexpectedEof,
"connection closed by remote",
),
}
.into());
}
Ok(_) => {
if let Ok(Some(decoded)) = self.decoder.decode(&mut self.buffer) {
tracing::trace!("Read {} bytes: {:?}", decoded.len(), decoded);
return Ok(decoded);
}
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {}
Err(e) => return Err(StreamError::Read { source: e }.into()),
}
}
}
}
}