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