plabble_codec/codec/request/
request_body.rs

1use crate::{
2    abstractions::{
3        Serializable,
4        SerializationError::{self, InvalidFormat, MissingInfo},
5        SerializationInfo, KEY_SIZE, TYPE_APPEND, TYPE_CONNECT, TYPE_CREATE, TYPE_PUT,
6        TYPE_REQUEST, TYPE_SUBSCRIBE, TYPE_UNSUBSCRIBE, TYPE_WIPE,
7    },
8    codec::{
9        common::{assert_len, dyn_int, SlotBody, SlotRange},
10        ptp_packet::PtpBody,
11    },
12};
13
14/// The body of a request packet
15///
16/// # Variants
17///
18/// * `CONNECT` - connect to a server
19/// * `CREATE` - create a new bucket
20/// * `PUT` - put one or multiple items in a bucket
21/// * `APPEND` - append one or multiple items to a bucket
22/// * `WIPE` - wipe or delete a bucket
23/// * `REQUEST` - request one or multiple items from a bucket
24/// * `SUBSCRIBE` - subscribe to a bucket
25/// * `UNSUBSCRIBE` - unsubscribe from a bucket
26#[derive(Debug)]
27pub enum RequestBody {
28    CONNECT {
29        protocol_version: u8,
30        pub_key: [u8; KEY_SIZE],
31    },
32    CREATE(SlotRange),
33    PUT {
34        slots: SlotBody,
35    },
36    APPEND {
37        items: Vec<Vec<u8>>,
38    },
39    WIPE(SlotRange),
40    REQUEST(SlotRange),
41    SUBSCRIBE(SlotRange),
42    UNSUBSCRIBE,
43}
44
45impl PtpBody for RequestBody {
46    fn packet_type(&self) -> u8 {
47        match self {
48            RequestBody::CONNECT { .. } => TYPE_CONNECT,
49            RequestBody::CREATE(_) => TYPE_CREATE,
50            RequestBody::PUT { .. } => TYPE_PUT,
51            RequestBody::APPEND { .. } => TYPE_APPEND,
52            RequestBody::WIPE(_) => TYPE_WIPE,
53            RequestBody::REQUEST(_) => TYPE_REQUEST,
54            RequestBody::SUBSCRIBE(_) => TYPE_SUBSCRIBE,
55            RequestBody::UNSUBSCRIBE => TYPE_UNSUBSCRIBE,
56        }
57    }
58}
59
60impl Serializable for RequestBody {
61    fn size(&self) -> usize {
62        match self {
63            RequestBody::CONNECT { .. } => 1 + KEY_SIZE,
64            RequestBody::PUT { slots } => slots.size(),
65            RequestBody::APPEND { items } => items
66                .iter()
67                .map(|s| s.len() + dyn_int::encoded_size(s.len() as u128))
68                .sum::<usize>(),
69            RequestBody::CREATE(sr)
70            | RequestBody::WIPE(sr)
71            | RequestBody::REQUEST(sr)
72            | RequestBody::SUBSCRIBE(sr) => sr.size(),
73            RequestBody::UNSUBSCRIBE => 0,
74        }
75    }
76
77    fn get_bytes(&self) -> Vec<u8> {
78        let mut buff = Vec::new();
79        match self {
80            RequestBody::CONNECT {
81                protocol_version,
82                pub_key,
83            } => {
84                buff.push(*protocol_version);
85                buff.extend_from_slice(pub_key);
86            }
87            RequestBody::PUT { slots } => {
88                buff = slots.get_bytes();
89            }
90            RequestBody::APPEND { items } => {
91                for data in items.iter() {
92                    buff.append(&mut dyn_int::encode(data.len() as u128));
93                    buff.extend_from_slice(data)
94                }
95            }
96            RequestBody::CREATE(sr)
97            | RequestBody::WIPE(sr)
98            | RequestBody::REQUEST(sr)
99            | RequestBody::SUBSCRIBE(sr) => {
100                buff = sr.get_bytes(); // or buff.append(&mut sr.get_bytes())
101            }
102            _ => (),
103        };
104
105        buff
106    }
107
108    fn from_bytes(data: &[u8], info: Option<SerializationInfo>) -> Result<Self, SerializationError>
109    where
110        Self: Sized,
111    {
112        if let Some(SerializationInfo::PacketType(packet_type)) = info {
113            match packet_type {
114                TYPE_CONNECT => {
115                    assert_len(data, 1 + KEY_SIZE)?;
116                    let protocol_version = data[0];
117                    let pub_key: [u8; KEY_SIZE] = data[1..]
118                        .try_into()
119                        .expect("Failed to copy pub_key from slice");
120                    Ok(RequestBody::CONNECT {
121                        protocol_version,
122                        pub_key,
123                    })
124                }
125                TYPE_CREATE => Ok(RequestBody::CREATE(SlotRange::from_bytes(data, None)?)),
126                TYPE_PUT => Ok(RequestBody::PUT {
127                    slots: SlotBody::from_bytes(data, None)?,
128                }),
129                TYPE_APPEND => {
130                    let mut items = Vec::new();
131                    let mut bytes_read = 0;
132                    while bytes_read != data.len() {
133                        assert_len(data, bytes_read + 1)?;
134                        let (data_len, read) = dyn_int::read_from_slice(&data[bytes_read..])?;
135                        bytes_read += read;
136                        assert_len(data, bytes_read + data_len as usize)?;
137                        let data = data[bytes_read..(bytes_read + data_len as usize)].to_vec();
138                        bytes_read += data_len as usize;
139                        items.push(data);
140                    }
141                    Ok(RequestBody::APPEND { items })
142                }
143                TYPE_WIPE => Ok(RequestBody::WIPE(SlotRange::from_bytes(data, None)?)),
144                TYPE_REQUEST => Ok(RequestBody::REQUEST(SlotRange::from_bytes(data, None)?)),
145                TYPE_SUBSCRIBE => Ok(RequestBody::SUBSCRIBE(SlotRange::from_bytes(data, None)?)),
146                TYPE_UNSUBSCRIBE => Ok(RequestBody::UNSUBSCRIBE),
147                _ => Err(InvalidFormat(format!(
148                    "Packet type {} is not supported",
149                    packet_type
150                ))),
151            }
152        } else {
153            Err(MissingInfo(String::from(
154                "Missing info paramter of PacketType",
155            )))
156        }
157    }
158}
159
160#[cfg(test)]
161mod parse_test {
162    use std::vec;
163
164    use super::*;
165    use crate::abstractions::{Serializable, SerializationError::InvalidFormat};
166
167    /*
168        Parsing packets
169    */
170
171    #[test]
172    fn can_parse_connect_req() {
173        let data = &[
174            0x77u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
175            23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
176        ];
177        let connect = RequestBody::from_bytes(data, Some(SerializationInfo::PacketType(0)));
178
179        match connect {
180            Ok(RequestBody::CONNECT {
181                protocol_version,
182                pub_key,
183            }) => {
184                assert_eq!(0x77, protocol_version);
185                assert_eq!(&data[1..33], pub_key);
186                assert_eq!(data.len(), connect.unwrap().size());
187            }
188            Err(e) => panic!("Error: {:?}", e),
189            _ => panic!("Not a connect"),
190        }
191    }
192
193    #[test]
194    fn can_parse_put_req() {
195        let data = &[
196            0, 5u8, 0xA, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 2u8, 0x5, 1, 2, 3, 4, 5,
197        ];
198        let put = RequestBody::from_bytes(data, Some(SerializationInfo::PacketType(2))).unwrap();
199        assert_eq!(21, put.size());
200        if let RequestBody::PUT { slots } = put {
201            assert_eq!(2, slots.len());
202            assert!(slots.keys().any(|x| *x == 5));
203            assert!(slots.keys().any(|x| *x == 2));
204            assert_eq!(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10], slots[&5]);
205            assert_eq!(vec![1, 2, 3, 4, 5], slots[&2]);
206        } else {
207            panic!("Not a put request");
208        }
209    }
210
211    #[test]
212    fn can_parse_append_req() {
213        let data = &[10u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 5u8, 1, 2, 3, 4, 5];
214        let append = RequestBody::from_bytes(data, Some(SerializationInfo::PacketType(3))).unwrap();
215        assert_eq!(17, append.size());
216        if let RequestBody::APPEND { items } = append {
217            assert_eq!(2, items.len());
218            assert_eq!(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10], items[0]);
219            assert_eq!(vec![1, 2, 3, 4, 5], items[1]);
220        } else {
221            panic!("Not an append request");
222        }
223    }
224
225    #[test]
226    fn can_parse_slot_range_0_slots_req() {
227        let data: &[u8] = &[];
228        if let RequestBody::REQUEST(sr) =
229            RequestBody::from_bytes(data, Some(SerializationInfo::PacketType(5))).unwrap()
230        {
231            assert_eq!(None, sr.from);
232            assert_eq!(None, sr.to);
233        } else {
234            panic!("Not a request");
235        }
236    }
237
238    #[test]
239    fn can_parse_slot_range_1_slot_req() {
240        let data: &[u8] = &[0, 15];
241        if let RequestBody::WIPE(sr) =
242            RequestBody::from_bytes(data, Some(SerializationInfo::PacketType(4))).unwrap()
243        {
244            assert_eq!(Some(15), sr.from);
245            assert_eq!(None, sr.to);
246        } else {
247            panic!("Not a wipe request");
248        }
249    }
250
251    #[test]
252    fn can_parse_slot_range_2_slots_req() {
253        let data: &[u8] = &[0, 15, 255, 255];
254        let body = RequestBody::from_bytes(data, Some(SerializationInfo::PacketType(6))).unwrap();
255        assert_eq!(4, body.size());
256        if let RequestBody::SUBSCRIBE(sr) = body {
257            assert_eq!(Some(15), sr.from);
258            assert_eq!(Some(u16::MAX), sr.to);
259        } else {
260            panic!("Not a subscribe request");
261        }
262    }
263
264    #[test]
265    fn cant_parse_unknown_packet_type() {
266        let data = &[0u8, 0];
267        let packet_type = 8;
268        let error = RequestBody::from_bytes(data, Some(SerializationInfo::PacketType(packet_type)))
269            .unwrap_err();
270        assert_eq!(
271            InvalidFormat(String::from("Packet type 8 is not supported")),
272            error
273        );
274    }
275}
276
277#[cfg(test)]
278mod serialize_test {
279    use std::collections::HashMap;
280
281    use crate::abstractions::Serializable;
282
283    use super::*;
284    /*
285        Serializing packets
286    */
287
288    #[test]
289    fn can_serialize_connect_req() {
290        let connect = RequestBody::CONNECT {
291            protocol_version: 5,
292            pub_key: [
293                1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
294                23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
295            ],
296        };
297        let expected = vec![
298            5, 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
299            24, 25, 26, 27, 28, 29, 30, 31, 32,
300        ];
301        let serialized = connect.get_bytes();
302        assert_eq!(expected, serialized);
303    }
304
305    #[test]
306    fn can_serialize_put_req() {
307        let mut slots = HashMap::new();
308        slots.insert(25, vec![1, 2, 3, 4, 5]);
309        slots.insert(6, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
310        let put = RequestBody::PUT { slots }.get_bytes();
311        assert_eq!(
312            put,
313            vec![0, 6, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 25, 5, 1, 2, 3, 4, 5],
314        );
315    }
316
317    #[test]
318    fn can_serialize_create_req() {
319        let create = RequestBody::CREATE(SlotRange {
320            from: Some(5),
321            to: None,
322        })
323        .get_bytes();
324        assert_eq!(vec![0, 5], create);
325    }
326
327    #[test]
328    fn can_serialize_create_req_2() {
329        let create = RequestBody::CREATE(SlotRange {
330            from: Some(5),
331            to: Some(u16::MAX - 256),
332        })
333        .get_bytes();
334        assert_eq!(vec![0, 5, 254, 255], create);
335    }
336
337    #[test]
338    fn can_serialize_append_req() {
339        let items = vec![vec![1, 2, 3, 4, 5], vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]];
340        let append = RequestBody::APPEND { items }.get_bytes();
341        assert_eq!(
342            vec![5, 1, 2, 3, 4, 5, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
343            append
344        );
345    }
346}