use crate::messaging::{DstLocation, Error, MessageId, MsgKind, Result};
use bincode::{
config::{BigEndian, FixintEncoding, WithOtherEndian, WithOtherIntEncoding},
Options,
};
use bytes::Bytes;
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use std::{io::Write, mem::size_of};
const MESSAGING_PROTO_VERSION: u16 = 1u16;
#[derive(Debug, PartialEq, Clone)]
pub struct WireMsgHeader {
version: u16,
pub msg_envelope: MsgEnvelope,
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct MsgEnvelope {
pub msg_id: MessageId,
pub msg_kind: MsgKind,
pub dst_location: DstLocation,
}
#[derive(Debug, Deserialize, Serialize)]
struct HeaderMeta {
header_len: u16,
version: u16,
}
impl HeaderMeta {
const SIZE: usize = size_of::<Self>();
fn header_len(&self) -> usize {
self.header_len.into()
}
}
lazy_static! {
static ref BINCODE_OPTIONS: WithOtherIntEncoding<
WithOtherEndian<bincode::DefaultOptions, BigEndian>,
FixintEncoding,
> = {
bincode::DefaultOptions::new()
.with_big_endian()
.with_fixint_encoding()
};
}
impl WireMsgHeader {
pub fn new(msg_id: MessageId, msg_kind: MsgKind, dst_location: DstLocation) -> Self {
Self {
version: MESSAGING_PROTO_VERSION,
msg_envelope: MsgEnvelope {
msg_id,
msg_kind,
dst_location,
},
}
}
pub fn from(mut bytes: Bytes) -> Result<(Self, Bytes)> {
let bytes_len = bytes.len();
let meta: HeaderMeta = BINCODE_OPTIONS
.allow_trailing_bytes()
.deserialize(&bytes)
.map_err(|err| Error::FailedToParse(format!("invalid message header: {}", err)))?;
if meta.header_len() > bytes_len {
return Err(Error::FailedToParse(format!(
"not enough bytes received ({}) to deserialize wire message header",
bytes_len
)));
}
if meta.version != MESSAGING_PROTO_VERSION {
return Err(Error::UnsupportedVersion(meta.version));
}
let msg_envelope_bytes = &bytes[HeaderMeta::SIZE..meta.header_len()];
let msg_envelope: MsgEnvelope =
rmp_serde::from_slice(msg_envelope_bytes).map_err(|err| {
Error::FailedToParse(format!(
"source authority couldn't be deserialized from the header: {}",
err
))
})?;
let header = Self {
version: meta.version,
msg_envelope,
};
let payload_bytes = bytes.split_off(meta.header_len());
Ok((header, payload_bytes))
}
pub fn write<'a>(&self, mut buffer: &'a mut [u8]) -> Result<(&'a mut [u8], u16)> {
let msg_envelope_vec = rmp_serde::to_vec_named(&self.msg_envelope).map_err(|err| {
Error::Serialisation(format!(
"could not serialize message envelope with Msgpack: {}",
err
))
})?;
let meta = HeaderMeta {
header_len: (HeaderMeta::SIZE + msg_envelope_vec.len()) as u16,
version: self.version,
};
BINCODE_OPTIONS
.serialize_into(&mut buffer, &meta)
.map_err(|err| {
Error::Serialisation(format!(
"header metadata couldn't be serialized into the header: {}",
err
))
})?;
buffer.write_all(&msg_envelope_vec).map_err(|err| {
Error::Serialisation(format!(
"message envelope couldn't be serialized into the header: {}",
err
))
})?;
Ok((buffer, meta.header_len))
}
pub fn max_size() -> u16 {
(HeaderMeta::SIZE + size_of::<MsgEnvelope>()) as u16
}
}