use bytes::Buf; use std::fmt; use std::io::Cursor; use std::num::TryFromIntError; use std::string::FromUtf8Error; use tracing::{debug, error, info}; #[derive(Clone, Debug)] pub enum Frame {} #[derive(Debug)] pub enum Error { Incomplete, Other(crate::Error), } impl Frame { pub fn check(src: &mut Cursor<&[u8]>) -> Result<(), Error> { match get_u8(src)? { // Error: msg: str 0x10 => { let n = get_length(src)?; skip(src, n as usize) } // Plate: plate: str, timestamp: u32 0x20 => { // Read length character of the plate string let n = get_length(src)?; // Skip the string to get to the timestamp skip(src, n)?; // check if valid timestamp get_u32(src)?; Ok(()) } // Ticket (just Server -> Client) // 0x21 => { // Ok(()) // } // Want Heartbeat: interval: u32 0x40 => { unimplemented!() } // Heartbeat (just Server -> Client) // 0x41 => { // Ok(()) // } // IAmCamera: road: u16, mile: u16, limit: u16 0x80 => { unimplemented!() } // IAmDispatcher: numroads: u8, numroads: [u16] 0x81 => { unimplemented!() } actual => Err(format!("protocol error; invalid frame type byte `{}`", actual).into()), } } pub fn parse(src: &mut Cursor<&[u8]>) -> Result { unimplemented!() } } fn peek_u8(src: &mut Cursor<&[u8]>) -> Result { if !src.has_remaining() { return Err(Error::Incomplete); } Ok(src.chunk()[0]) } fn get_str<'a>(src: &mut Cursor<&'a [u8]>, len: usize) -> Result<&'a str, Error> { if src.remaining() < len { return Err(Error::Incomplete); } let position = src.position() as usize; let slice = &src.get_ref()[position..position + len]; let message = std::str::from_utf8(slice).map_err(|_| "protocol error; invalid frame format".into()); src.advance(len); message } fn skip(src: &mut Cursor<&[u8]>, n: usize) -> Result<(), Error> { if src.remaining() < n { return Err(Error::Incomplete); } src.advance(n); Ok(()) } fn get_u8(src: &mut Cursor<&[u8]>) -> Result { if !src.has_remaining() { error!("Incomplete frame"); return Err(Error::Incomplete); } info!("get_u8: current cursor position: {:?}", src.position()); Ok(src.get_u8()) } fn get_u32(src: &mut Cursor<&[u8]>) -> Result { if !src.has_remaining() { error!("Incomplete frame"); return Err(Error::Incomplete); } info!("get_u32: current cursor position: {:?}", src.position()); Ok(src.get_u32()) } // Same as get_u8, but the current cursor points to the byte of the length of a message string. fn get_length(src: &mut Cursor<&[u8]>) -> Result { if !src.has_remaining() { error!("Incomplete frame"); return Err(Error::Incomplete); } info!("get_length: current cursor position: {:?}", src.position()); Ok(src.get_u8() as usize) } fn get_line<'a>(src: &mut Cursor<&'a [u8]>) -> Result<&'a [u8], Error> { unimplemented!() } impl From for Error { fn from(src: String) -> Error { Error::Other(src.into()) } } impl From<&str> for Error { fn from(src: &str) -> Error { src.to_string().into() } } impl From for Error { fn from(_src: FromUtf8Error) -> Error { "protocol error; invalid frame format".into() } } impl From for Error { fn from(_src: TryFromIntError) -> Error { "protocol error; invalid frame format".into() } } impl std::error::Error for Error {} impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { Error::Incomplete => "stream ended early".fmt(fmt), Error::Other(err) => err.fmt(fmt), } } }