cheetah_game_realtime_protocol/codec/
mod.rs1use std::io::Cursor;
2
3use byteorder::{ReadBytesExt, WriteBytesExt};
4use chacha20poly1305::aead;
5use thiserror::Error;
6
7use crate::codec::cipher::Cipher;
8use crate::codec::variable_int::{VariableIntReader, VariableIntWriter};
9use crate::frame::headers::Headers;
10use crate::frame::segment::Segment;
11use crate::frame::Frame;
12
13pub mod cipher;
14pub mod compress;
15pub mod headers;
16pub mod segment;
17pub mod variable_int;
18
19#[derive(Error, Debug)]
20pub enum DecodeError {
21 #[error("Cipher factory error")]
22 CipherFactoryError(),
23 #[error("DecryptedError {0}")]
24 DecryptedError(aead::Error),
25 #[error("DecompressError {0}")]
26 DecompressError(#[from] snap::Error),
27 #[error("Io error {0}")]
28 Io(#[from] std::io::Error),
29 #[error("HeaplessError")]
30 HeaplessError,
31}
32
33#[derive(Error, Debug)]
34pub enum EncodeError {
35 #[error("EncryptedError {0}")]
36 EncryptedError(aead::Error),
37 #[error("CompressError {0}")]
38 CompressError(#[from] snap::Error),
39 #[error("Io error {0}")]
40 Io(#[from] std::io::Error),
41}
42
43impl Frame {
44 pub fn decode<'a, F>(data: &'a [u8], chiper_factory: F) -> Result<Frame, DecodeError>
45 where
46 F: FnOnce(&Headers) -> Option<Cipher<'a>>,
47 {
48 let mut cursor = Cursor::new(data);
49 let connection_id = cursor.read_variable_u64()?;
50 let frame_id = cursor.read_variable_u64()?;
51 let reliability = cursor.read_u8()? == 1;
52 let headers = Headers::decode_headers(&mut cursor)?;
53
54 let cipher = chiper_factory(&headers).ok_or_else(DecodeError::CipherFactoryError)?;
55 let segment = Segment::decode(cursor, cipher, frame_id)?;
56 let frame = Frame {
57 connection_id,
58 frame_id,
59 headers,
60 reliability,
61 segment,
62 };
63
64 Ok(frame)
65 }
66
67 #[allow(clippy::cast_possible_truncation)]
71 pub fn encode(&self, cipher: &mut Cipher<'_>, out: &mut [u8]) -> Result<usize, EncodeError> {
72 let mut frame_cursor = Cursor::new(out);
73 frame_cursor.write_variable_u64(self.connection_id).map_err(EncodeError::Io)?;
74 frame_cursor.write_variable_u64(self.frame_id).map_err(EncodeError::Io)?;
75 frame_cursor.write_u8(u8::from(self.reliability)).map_err(EncodeError::Io)?;
76 self.headers.encode_headers(&mut frame_cursor).map_err(EncodeError::Io)?;
77 self.segment.encode(&mut frame_cursor, cipher, self.frame_id)?;
78 Ok(frame_cursor.position() as usize)
79 }
80}
81
82#[cfg(test)]
83pub mod tests {
84 use crate::codec::cipher::Cipher;
85 use crate::frame::headers::Header;
86 use crate::frame::segment::Segment;
87 use crate::frame::Frame;
88 use crate::reliable::ack::header::AckHeader;
89
90 const PRIVATE_KEY: &[u8] = &[
91 0x29, 0xfa, 0x35, 0x60, 0x88, 0x45, 0xc6, 0xf9, 0xd8, 0xfe, 0x65, 0xe3, 0x22, 0x0e, 0x5b, 0x05, 0x03, 0x4a, 0xa0, 0x9f, 0x9e, 0x27, 0xad, 0x0f, 0x6c, 0x90, 0xa5, 0x73, 0xa8, 0x10, 0xe4, 0x94,
92 ];
93
94 #[test]
95 fn should_encode_decode_frame() {
96 let mut frame = Frame::new(100, 55, true, Segment::default_with_body(&[1, 2, 3, 4, 6]));
97 let key = PRIVATE_KEY.into();
98 let mut cipher = Cipher::new(&key);
99 frame.headers.add(Header::Ack(AckHeader::default()));
100 frame.headers.add(Header::Ack(AckHeader::default()));
101
102 let mut buffer = [0; 1024];
103 let size = frame.encode(&mut cipher, &mut buffer).unwrap();
104 let buffer = &buffer[0..size];
105 let decoded_frame = Frame::decode(buffer, |_| Some(cipher.clone())).unwrap();
106
107 assert_eq!(decoded_frame, decoded_frame);
108 }
109}