use bytes::Buf;
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use crate::error::{EncodeError, FrameError};
use crate::frame::{FrameDecoder, FrameEncoder};
use crate::packet::{Packet, PacketSet, RawPacket};
const READ_CHUNK: usize = 16 * 1024;
#[derive(Debug)]
pub struct FramedReader<R> {
inner: R,
decoder: FrameDecoder,
}
impl<R: AsyncRead + Unpin> FramedReader<R> {
pub fn new(inner: R) -> Self {
FramedReader {
inner,
decoder: FrameDecoder::new(),
}
}
pub fn decoder(&mut self) -> &mut FrameDecoder {
&mut self.decoder
}
pub fn get_mut(&mut self) -> &mut R {
&mut self.inner
}
pub async fn read_packet(&mut self) -> Result<Option<RawPacket>, FrameError> {
loop {
if let Some(p) = self.decoder.next_packet()? {
return Ok(Some(p));
}
let want = self.decoder.needed().unwrap_or(0).max(READ_CHUNK);
let buf = self.decoder.buffer_mut();
buf.reserve(want);
let old = buf.len();
let n = self.inner.read_buf(buf).await?;
if n == 0 {
if self.decoder.buffered() == 0 {
return Ok(None);
}
return Err(FrameError::Io(std::io::ErrorKind::UnexpectedEof.into()));
}
self.decoder.commit(old);
}
}
}
#[derive(Debug)]
pub struct FramedWriter<W> {
inner: W,
encoder: FrameEncoder,
}
impl<W: AsyncWrite + Unpin> FramedWriter<W> {
pub fn new(inner: W) -> Self {
FramedWriter {
inner,
encoder: FrameEncoder::new(),
}
}
pub fn encoder(&mut self) -> &mut FrameEncoder {
&mut self.encoder
}
pub fn get_mut(&mut self) -> &mut W {
&mut self.inner
}
pub fn queue<P: Packet>(&mut self, p: &P) -> Result<(), EncodeError> {
self.encoder.write_packet(p)
}
pub fn queue_set<S: PacketSet>(&mut self, p: &S) -> Result<(), EncodeError> {
self.encoder.write_set(p)
}
pub fn queue_raw(&mut self, p: &RawPacket) -> Result<(), EncodeError> {
self.encoder.write_raw(p)
}
pub async fn flush(&mut self) -> std::io::Result<()> {
let out = self.encoder.out_mut();
while out.has_remaining() {
let n = self.inner.write_buf(out).await?;
if n == 0 {
return Err(std::io::ErrorKind::WriteZero.into());
}
}
self.inner.flush().await
}
pub async fn send<P: Packet>(&mut self, p: &P) -> Result<(), FrameError> {
self.queue(p)
.map_err(|e| FrameError::Io(std::io::Error::other(e)))?;
self.flush().await?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use bytes::Bytes;
#[tokio::test]
async fn duplex_roundtrip() {
let (a, b) = tokio::io::duplex(64);
let mut w = FramedWriter::new(a);
let mut r = FramedReader::new(b);
let key = [5u8; 16];
w.encoder().set_compression(32);
w.encoder().enable_encryption(&key);
r.decoder().set_compression(32);
r.decoder().enable_encryption(&key);
let packets: Vec<RawPacket> = (0..20)
.map(|i| RawPacket::new(i, Bytes::from(vec![i as u8; (i * 13) as usize])))
.collect();
let send = packets.clone();
let writer = tokio::spawn(async move {
for p in &send {
w.queue_raw(p).unwrap();
}
w.flush().await.unwrap();
drop(w);
});
let mut got = Vec::new();
while let Some(p) = r.read_packet().await.unwrap() {
got.push(p);
}
writer.await.unwrap();
assert_eq!(got, packets);
}
}