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
commit
fd23240633
@ -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…
Reference in New Issue