use anyhow::Result;
use serde::{Deserialize, Serialize};
use crate::constants::tcp::MAX_FRAME_SIZE;
use bincode::{Decode, Encode, config, decode_from_slice, encode_to_vec};
#[inline]
pub fn frame_config() -> impl bincode::config::Config {
config::standard()
.with_fixed_int_encoding()
.with_big_endian()
.with_limit::<MAX_FRAME_SIZE>()
}
pub trait Codec: Serialize + for<'de> Deserialize<'de> + Encode + Decode<()> + Sized {
fn encode(&self) -> Vec<u8> {
encode_to_vec(self, frame_config()).expect("serialize failed")
}
fn decode_with_len(data: &[u8]) -> Result<(Self, usize)> {
let (decoded, len): (Self, usize) = decode_from_slice(data, frame_config())
.map_err(|e| anyhow::anyhow!("decode failed: {}", e))?;
Ok((decoded, len))
}
fn decode(data: &[u8]) -> Result<Self> {
let (decoded, _): (Self, usize) = Self::decode_with_len(data)?;
Ok(decoded)
}
}
pub trait Frame: Codec {
fn payload(&self) -> Option<Vec<u8>>;
fn validate(&self) -> bool {
true
}
fn command(&self) -> Option<&Vec<u8>>;
fn is_flat(&self) -> bool {
true
}
fn sign<F>(&self, signer: F) -> Vec<u8>
where
F: FnOnce(&[u8]) -> Vec<u8>,
{
let raw_bytes = Codec::encode(self); signer(&raw_bytes)
}
fn verify<V>(&self, signature: &[u8], verifier: V) -> bool
where
V: FnOnce(&[u8]) -> bool,
{
verifier(signature)
}
}
pub trait Command: Codec {
fn id(&self) -> u32;
fn validate(&self) -> bool {
true
}
fn data(&self) -> &Vec<u8>;
fn is_trusted(&self) -> bool {
false
}
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, Clone)]
pub struct RawCodec(pub Vec<u8>);
impl Codec for RawCodec {}
impl Frame for RawCodec {
fn payload(&self) -> Option<Vec<u8>> {
Some(self.0.clone())
}
fn command(&self) -> Option<&Vec<u8>> {
Some(&self.0)
}
}
impl Command for RawCodec {
fn id(&self) -> u32 {
u32::from_le_bytes(self.0[0..4].try_into().unwrap_or_default())
}
fn data(&self) -> &Vec<u8> {
&self.0
}
}
pub trait TCPFrame: Frame + Send + Sync + Clone + 'static {}
impl<T: Frame + Send + Sync + Clone + 'static> TCPFrame for T {}
pub trait TCPCommand: Command + Send + Sync + Clone + 'static {}
impl<T: Command + Send + Sync + Clone + 'static> TCPCommand for T {}