conclave_room_serialize/
lib.rs1use std::io::{Cursor, Read};
6
7use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
8use conclave_room;
9use conclave_room::{Knowledge, Term};
10
11use crate::ServerReceiveCommand::PingCommandType;
12
13#[derive(Debug, PartialEq)]
14pub struct PingCommand {
15 pub term: Term,
16 pub knowledge: Knowledge,
17}
18
19impl PingCommand {
20 pub fn to_octets(&self) -> Vec<u8> {
21 let mut writer = vec![];
22
23 writer.write_u16::<BigEndian>(self.term).unwrap();
24 writer.write_u64::<BigEndian>(self.knowledge).unwrap();
25
26 writer
27 }
28
29 pub fn from_cursor(reader: &mut Cursor<&[u8]>) -> Self {
30 Self {
31 term: reader.read_u16::<BigEndian>().unwrap(),
32 knowledge: reader.read_u64::<BigEndian>().unwrap(),
33 }
34 }
35}
36
37#[derive(Debug)]
38enum ServerReceiveCommand {
39 PingCommandType(PingCommand),
40}
41
42impl ServerReceiveCommand {
43 pub fn to_octets(&self) -> Result<Vec<u8>, String> {
44 let command_type_id = match self {
45 PingCommandType(ping_command) => PING_COMMAND_TYPE_ID,
46 _ => return Err(format!("unsupported command {:?}", self)),
47 };
48
49 let mut writer = vec![];
50
51 writer.write_u8(command_type_id).expect("could not write command type id");
52
53 match self {
54 PingCommandType(ping_command) => writer.extend_from_slice(ping_command.to_octets().as_slice()),
55 _ => return Err(format!("unknown command enum {:?}", self)),
56 }
57
58 Ok(writer)
59 }
60
61 pub fn from_octets(input: &[u8]) -> Result<ServerReceiveCommand, String> {
62 let mut rdr = Cursor::new(input);
63 let command_type_id = rdr.read_u8().unwrap();
64 match command_type_id {
65 PING_COMMAND_TYPE_ID => Ok(PingCommandType(PingCommand::from_cursor(&mut rdr))),
66 _ => Err(format!("unknown command 0x{:x}", command_type_id)),
67 }
68 }
69}
70
71const PING_COMMAND_TYPE_ID: u8 = 0x01;
72
73
74#[cfg(test)]
75mod tests {
76 use std::io::Cursor;
77
78 use crate::{PING_COMMAND_TYPE_ID, PingCommand, ServerReceiveCommand};
79 use crate::ServerReceiveCommand::PingCommandType;
80
81 #[test]
82 fn check_serializer() {
83 let ping_command = PingCommand {
84 term: 32,
85 knowledge: 444441,
86 };
87
88 let encoded = ping_command.to_octets();
89 let mut receive_cursor = Cursor::new(encoded.as_slice());
90 let deserialized_ping_command = PingCommand::from_cursor(&mut receive_cursor);
91
92 println!("before {:?}", &ping_command);
93 println!("after {:?}", &deserialized_ping_command);
94 assert_eq!(ping_command, deserialized_ping_command);
95 }
96
97 #[test]
98 fn check_receive_message() {
99 const EXPECTED_KNOWLEDGE_VALUE: u64 = 17718865395771014920;
100
101 let octets = [PING_COMMAND_TYPE_ID,
102 0x00, 0x20, 0xF5, 0xE6, 0x0E, 0x32, 0xE9, 0xE4, 0x7F, 0x08 ];
105
106 let message = &ServerReceiveCommand::from_octets(&octets).unwrap();
107
108 match message {
109 PingCommandType(ping_command) => {
110 println!("received {:?}", &ping_command);
111 assert_eq!(0x20, ping_command.term);
112 assert_eq!(EXPECTED_KNOWLEDGE_VALUE, ping_command.knowledge);
113 let octets_after = message.to_octets().unwrap();
114 assert_eq!(octets, octets_after.as_slice());
115 }
116 _ => assert!(false, "should be ping command")
117 }
118 }
119}