cheetah_game_realtime_protocol/codec/
mod.rs

1use 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	///
68	/// Преобразуем Frame в набор байт для отправки через сеть
69	///
70	#[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}