conclave_room_serialize/
lib.rs

1/*----------------------------------------------------------------------------------------------------------
2 *  Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/piot/conclave-room-serialize-rs
3 *  Licensed under the MIT License. See LICENSE in the project root for license information.
4 *--------------------------------------------------------------------------------------------------------*/
5use 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, // Term
103            0xF5, 0xE6, 0x0E, 0x32, 0xE9, 0xE4, 0x7F, 0x08 // Knowledge
104        ];
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}