use crate::session::{BubbleState, ClientRequest};
use bytes::{BufMut, BytesMut};
use std::io;
use tokio_util::codec::{Decoder, Encoder};
pub struct BubbleCodec;
impl Decoder for BubbleCodec {
type Item = ClientRequest;
type Error = io::Error;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
let end = src.search_message_end()?;
if end == 0 {
return Ok(None);
}
let buf = src.split_to(end);
Ok(Some(serde_json::from_slice::<ClientRequest>(&buf)?))
}
}
impl Encoder<BubbleState> for BubbleCodec {
type Error = io::Error;
fn encode(&mut self, msg: BubbleState, dst: &mut BytesMut) -> Result<(), Self::Error> {
let mut msg = serde_json::to_string(&msg).unwrap();
msg.push_str("\r\n");
dst.put(msg.as_bytes());
Ok(())
}
}
trait MessageEnd {
fn search_message_end(&self) -> io::Result<usize>;
}
impl MessageEnd for BytesMut {
fn search_message_end(&self) -> io::Result<usize> {
for (mut pos, byte) in self.iter().enumerate() {
if byte != &('\r' as u8) {
continue;
}
pos += 1;
return if self.len() <= pos {
Ok(0)
} else if self[pos] != '\n' as u8 {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"bad bytes in the client JSON request",
))
} else {
Ok(pos)
};
}
Ok(0)
}
}