1use std::time::Duration;
14
15use crate::error::ConnectError;
16
17pub fn crc32_ieee(data: &[u8]) -> u32 {
19 const POLY: u32 = 0xedb88320;
20 let mut crc: u32 = 0xffffffff;
21 for &byte in data {
22 let mut b = byte as u32;
23 for _ in 0..8 {
24 let mix = (crc ^ b) & 1;
25 crc >>= 1;
26 if mix != 0 {
27 crc ^= POLY;
28 }
29 b >>= 1;
30 }
31 }
32 crc ^ 0xffffffff
33}
34
35pub const COMPRESSION_THRESHOLD: usize = 512;
37
38const ID_GZIP_PACKED: u32 = 0x3072cfa1;
39const ID_MSGS_ACK: u32 = 0x62d6b459;
40const ID_MSG_CONTAINER: u32 = 0x73f1f8dc;
41
42pub fn random_i64() -> i64 {
43 let mut b = [0u8; 8];
44 getrandom::getrandom(&mut b).expect("getrandom");
45 i64::from_le_bytes(b)
46}
47
48pub fn jitter_delay(base_ms: u64) -> Duration {
52 let mut b = [0u8; 2];
54 getrandom::getrandom(&mut b).unwrap_or(());
55 let rand_frac = u16::from_le_bytes(b) as f64 / 65535.0; let factor = 0.80 + rand_frac * 0.40; Duration::from_millis((base_ms as f64 * factor) as u64)
58}
59
60pub fn tl_read_bytes(data: &[u8]) -> Option<Vec<u8>> {
61 if data.is_empty() {
62 return Some(vec![]);
63 }
64 let (len, start) = if data[0] < 254 {
65 (data[0] as usize, 1)
66 } else if data.len() >= 4 {
67 (
68 data[1] as usize | (data[2] as usize) << 8 | (data[3] as usize) << 16,
69 4,
70 )
71 } else {
72 return None;
73 };
74 if data.len() < start + len {
75 return None;
76 }
77 Some(data[start..start + len].to_vec())
78}
79
80pub fn tl_read_string(data: &[u8]) -> Option<String> {
81 tl_read_bytes(data).map(|b| String::from_utf8_lossy(&b).into_owned())
82}
83
84pub fn gz_inflate(data: &[u8]) -> Result<Vec<u8>, ConnectError> {
85 use std::io::Read;
86 let mut out = Vec::new();
87 if flate2::read::GzDecoder::new(data)
88 .read_to_end(&mut out)
89 .is_ok()
90 && !out.is_empty()
91 {
92 return Ok(out);
93 }
94 out.clear();
95 flate2::read::ZlibDecoder::new(data)
96 .read_to_end(&mut out)
97 .map_err(|_| ConnectError::other("decompression failed"))?;
98 Ok(out)
99}
100
101pub fn maybe_gz_decompress(body: Vec<u8>) -> Result<Vec<u8>, ConnectError> {
102 const ID_GZIP_PACKED_LOCAL: u32 = 0x3072cfa1;
103 if body.len() >= 4 && u32::from_le_bytes(body[0..4].try_into().unwrap()) == ID_GZIP_PACKED_LOCAL
104 {
105 let bytes = tl_read_bytes(&body[4..]).unwrap_or_default();
106 gz_inflate(&bytes)
107 } else {
108 Ok(body)
109 }
110}
111
112pub fn tl_write_bytes(data: &[u8]) -> Vec<u8> {
114 let len = data.len();
115 let mut out = Vec::with_capacity(4 + len);
116 if len < 254 {
117 out.push(len as u8);
118 out.extend_from_slice(data);
119 let pad = (4 - (1 + len) % 4) % 4;
120 out.extend(std::iter::repeat_n(0u8, pad));
121 } else {
122 out.push(0xfe);
123 out.extend_from_slice(&(len as u32).to_le_bytes()[..3]);
124 out.extend_from_slice(data);
125 let pad = (4 - (4 + len) % 4) % 4;
126 out.extend(std::iter::repeat_n(0u8, pad));
127 }
128 out
129}
130
131pub fn gz_pack_body(data: &[u8]) -> Vec<u8> {
133 use std::io::Write;
134 let mut enc = flate2::write::ZlibEncoder::new(Vec::new(), flate2::Compression::default());
135 let _ = enc.write_all(data);
136 let compressed = enc.finish().unwrap_or_default();
137 let mut out = Vec::with_capacity(4 + 4 + compressed.len());
138 out.extend_from_slice(&ID_GZIP_PACKED.to_le_bytes());
139 out.extend(tl_write_bytes(&compressed));
140 out
141}
142
143pub fn maybe_gz_pack(data: &[u8]) -> Vec<u8> {
146 if data.len() <= COMPRESSION_THRESHOLD {
147 return data.to_vec();
148 }
149 let packed = gz_pack_body(data);
150 if packed.len() < data.len() {
151 packed
152 } else {
153 data.to_vec()
154 }
155}
156
157pub fn build_msgs_ack_body(msg_ids: &[i64]) -> Vec<u8> {
161 let mut out = Vec::with_capacity(4 + 4 + 4 + msg_ids.len() * 8);
164 out.extend_from_slice(&ID_MSGS_ACK.to_le_bytes());
165 out.extend_from_slice(&0x1cb5c415_u32.to_le_bytes()); out.extend_from_slice(&(msg_ids.len() as u32).to_le_bytes());
167 for &id in msg_ids {
168 out.extend_from_slice(&id.to_le_bytes());
169 }
170 out
171}
172
173pub fn build_container_body(messages: &[(i64, i32, &[u8])]) -> Vec<u8> {
179 let total_body: usize = messages.iter().map(|(_, _, b)| 16 + b.len()).sum();
180 let mut out = Vec::with_capacity(8 + total_body);
181 out.extend_from_slice(&ID_MSG_CONTAINER.to_le_bytes());
182 out.extend_from_slice(&(messages.len() as u32).to_le_bytes());
183 for &(msg_id, seqno, body) in messages {
184 out.extend_from_slice(&msg_id.to_le_bytes());
185 out.extend_from_slice(&seqno.to_le_bytes());
186 out.extend_from_slice(&(body.len() as u32).to_le_bytes());
187 out.extend_from_slice(body);
188 }
189 out
190}