use bytes::{Buf, BufMut, Bytes, BytesMut};
use std::fmt;
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Cmd {
Syn = 0,
Fin = 1,
Psh = 2,
Nop = 3,
Upd = 4,
}
impl From<u8> for Cmd {
fn from(b: u8) -> Self {
match b {
0 => Cmd::Syn,
1 => Cmd::Fin,
2 => Cmd::Psh,
3 => Cmd::Nop,
4 => Cmd::Upd,
_ => Cmd::Nop,
}
}
}
pub const HEADER_SIZE: usize = 8;
pub const UPD_SIZE: usize = 8;
pub const INITIAL_PEER_WINDOW: u32 = 262144;
#[derive(Debug, Clone)]
pub struct Frame {
pub ver: u8,
pub cmd: Cmd,
pub sid: u32,
pub data: Bytes,
}
impl Frame {
pub fn new(ver: u8, cmd: Cmd, sid: u32) -> Self {
Self {
ver,
cmd,
sid,
data: Bytes::new(),
}
}
pub fn encode(&self) -> BytesMut {
let mut buf = BytesMut::with_capacity(HEADER_SIZE + self.data.len());
buf.put_u8(self.ver);
buf.put_u8(self.cmd as u8);
buf.put_u16_le(self.data.len() as u16);
buf.put_u32_le(self.sid);
buf.put_slice(&self.data);
buf
}
pub fn decode_header(buf: &[u8]) -> Option<(u8, Cmd, u16, u32)> {
if buf.len() < HEADER_SIZE {
return None;
}
let mut reader = buf;
let ver = reader.get_u8();
let cmd = Cmd::from(reader.get_u8());
let length = reader.get_u16_le();
let sid = reader.get_u32_le();
Some((ver, cmd, length, sid))
}
}
#[derive(Debug, Clone, Copy)]
pub struct RawHeader {
pub ver: u8,
pub cmd: Cmd,
pub length: u16,
pub sid: u32,
}
impl RawHeader {
pub fn from_bytes(buf: &[u8]) -> Option<Self> {
if buf.len() < HEADER_SIZE {
return None;
}
let mut reader = &buf[..];
Some(Self {
ver: reader.get_u8(),
cmd: Cmd::from(reader.get_u8()),
length: reader.get_u16_le(),
sid: reader.get_u32_le(),
})
}
}
#[derive(Debug, Clone, Copy)]
pub struct UpdHeader {
pub consumed: u32,
pub window: u32,
}
impl UpdHeader {
pub fn from_bytes(buf: &[u8]) -> Option<Self> {
if buf.len() < UPD_SIZE {
return None;
}
let mut reader = &buf[..];
Some(Self {
consumed: reader.get_u32_le(),
window: reader.get_u32_le(),
})
}
pub fn encode(&self) -> Bytes {
let mut buf = BytesMut::with_capacity(UPD_SIZE);
buf.put_u32_le(self.consumed);
buf.put_u32_le(self.window);
buf.freeze()
}
}
impl fmt::Display for Frame {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Version:{} Cmd:{} StreamID:{} Length:{}",
self.ver,
self.cmd as u8,
self.sid,
self.data.len()
)
}
}