Add Message struct and implementation

Add a Message struct representing a single rpc message that has
a field for the called method and the data as well as the length
indicator and a crc32 checksum. The struct implements a way of
serializing the message into bytes and constructing it from bytes
with support for serde.

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/1/head
trivernis 4 years ago
commit fd23240633
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

3
.gitignore vendored

@ -0,0 +1,3 @@
/target
Cargo.lock
.idea

@ -0,0 +1,14 @@
[package]
name = "msgrpc"
version = "0.1.0"
authors = ["trivernis <trivernis@protonmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rmp = "0.8.9"
rmp-serde = "0.14.4"
crc = "1.8.1"
serde = "1.0.115"
byteorder = "1.3.4"

@ -0,0 +1,23 @@
pub mod message;
#[cfg(test)]
mod tests {
use crate::message::Message;
#[test]
fn it_creates_and_serializes_messages() {
let message = Message::new([0x01, 0x00, 0x10, 0x00], vec![0x00, 0x11, 0xFF, 0x00]);
assert_eq!(message.to_bytes(), vec![0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x10, 0x00, 0x00, 0x11, 0xFF, 0x00, 0x96, 0xA9, 0xB2, 0x2E])
}
#[test]
fn it_deserializes_messages() {
let bytes = vec![0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x10, 0x00, 0x00, 0x11, 0xFF, 0x00, 0x96, 0xA9, 0xB2, 0x2E];
let message = Message::from_bytes(&bytes);
let mut other_message = Message::new([0x01, 0x00, 0x10, 0x00], vec![0x00, 0x11, 0xFF, 0x00]);
other_message.crc = Some( 0x96A9B22E );
assert_eq!(message, Ok(other_message))
}
}

@ -0,0 +1,90 @@
use serde::Serialize;
use rmp_serde::Serializer;
use byteorder::{BigEndian, ByteOrder};
use crc::crc32;
use std::convert::TryInto;
#[derive(Clone, Debug, PartialOrd, PartialEq)]
pub enum DeserializeError {
LengthError,
ChecksumError,
}
#[derive(Clone, Debug, PartialOrd, PartialEq)]
pub struct Message {
length: u32,
method: [u8; 4],
data: Vec<u8>,
pub crc: Option<u32>,
}
impl Message {
/// Creates a new message
pub fn new(method: [u8; 4], data: Vec<u8>) -> Self {
Self {
length: (12 + data.len()) as u32,
method,
data,
crc: None,
}
}
/// Creates a new message with data being a serializable type
pub fn new_with_serialize(method: [u8; 4], data: impl Serialize) -> Self {
let mut buf = Vec::new();
data.serialize(&mut Serializer::new(&mut buf)).unwrap();
Self {
method,
length: (12 + buf.len()) as u32,
data: buf,
crc: None,
}
}
/// Deserializes a vector of bytes into the message
pub fn from_bytes(bytes: &Vec<u8>) -> Result<Self, DeserializeError> {
if bytes.len() < 4 {
return Err(DeserializeError::LengthError)
}
let length = BigEndian::read_u32(&bytes[0..4]);
if bytes.len() != length as usize {
return Err(DeserializeError::LengthError)
}
let crc = BigEndian::read_u32(&bytes[(length as usize - 4)..(length as usize)]);
let calc_crc = crc32::checksum_ieee(&bytes[0..(length as usize - 4)]);
if calc_crc != crc {
return Err(DeserializeError::ChecksumError)
}
let method: [u8; 4] = bytes[4..8].try_into().unwrap();
let data = bytes[8..(length as usize - 4)].to_vec();
Ok(Self {
length,
method,
data,
crc: Some(crc)
})
}
/// Returns the serialized bytes version
pub fn to_bytes(&self) -> Vec<u8> {
let mut data = Vec::new();
let mut length_raw = [0u8; 4];
BigEndian::write_u32(&mut length_raw, self.length);
data.append(&mut length_raw.to_vec());
data.append(&mut self.method.clone().to_vec());
data.append(&mut self.data.clone());
let crc_sum = crc32::checksum_ieee(&data);
let mut checksum_raw = [0u8; 4];
BigEndian::write_u32(&mut checksum_raw, crc_sum);
data.append(&mut checksum_raw.to_vec());
data
}
}
Loading…
Cancel
Save