use bytes::{Buf, BufMut, Bytes};
use std::io;
use tdf::{serialize_vec, TdfSerialize};
use tokio_util::codec::{Decoder, Encoder};
#[repr(u8)]
pub enum FrameType {
Request = 0x0,
Response = 0x1,
Notify = 0x2,
Error = 0x3,
}
impl From<u8> for FrameType {
fn from(value: u8) -> Self {
match value {
0x1 => FrameType::Response,
0x2 => FrameType::Notify,
0x3 => FrameType::Error,
_ => FrameType::Request,
}
}
}
pub struct FrameHeader {
pub length: usize,
pub component: u16,
pub command: u16,
pub error: u16,
pub ty: FrameType,
pub options: u8,
pub seq: u16,
}
pub struct Frame {
pub header: FrameHeader,
pub contents: Bytes,
}
impl Frame {
pub fn response_raw(header: &FrameHeader, contents: Bytes) -> Frame {
Frame {
header: FrameHeader {
length: contents.len(),
component: header.component,
command: header.command,
error: 0,
ty: FrameType::Response,
options: 0,
seq: header.seq,
},
contents,
}
}
#[inline]
pub fn response<V>(header: &FrameHeader, value: V) -> Frame
where
V: TdfSerialize,
{
Self::response_raw(header, Bytes::from(serialize_vec(&value)))
}
pub fn response_empty(header: &FrameHeader) -> Frame {
Self::response_raw(header, Bytes::new())
}
}
#[derive(Default)]
pub struct FireCodec {
current_frame: Option<FrameHeader>,
}
impl FireCodec {
const MIN_HEADER_SIZE: usize = 12;
}
impl Decoder for FireCodec {
type Error = io::Error;
type Item = Frame;
fn decode(&mut self, src: &mut bytes::BytesMut) -> Result<Option<Self::Item>, Self::Error> {
let current_frame = if let Some(current_frame) = self.current_frame.as_mut() {
current_frame
} else {
if src.len() < Self::MIN_HEADER_SIZE {
return Ok(None);
}
let length: usize = src.get_u16() as usize;
let component: u16 = src.get_u16();
let command: u16 = src.get_u16();
let error: u16 = src.get_u16();
let ty: FrameType = FrameType::from(src.get_u8() >> 4);
let options: u8 = src.get_u8() >> 4;
let seq: u16 = src.get_u16();
let header = FrameHeader {
length,
component,
command,
error,
ty,
options,
seq,
};
self.current_frame.insert(header)
};
if src.len() < current_frame.length {
return Ok(None);
}
let header = self.current_frame.take().expect("Missing current frame");
let buffer = src.split_to(header.length);
Ok(Some(Frame {
header,
contents: buffer.freeze(),
}))
}
}
impl Encoder<Frame> for FireCodec {
type Error = io::Error;
fn encode(&mut self, item: Frame, dst: &mut bytes::BytesMut) -> Result<(), Self::Error> {
let header = item.header;
dst.put_u16(header.length as u16);
dst.put_u16(header.component);
dst.put_u16(header.command);
dst.put_u16(header.error);
dst.put_u8((header.ty as u8) << 4);
dst.put_u8(header.options << 4);
dst.put_u16(header.seq);
dst.extend_from_slice(&item.contents);
Ok(())
}
}