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 {
45 let mut b = [0u8; 8];
46 ferogram_crypto::fill_random(&mut b);
47 i64::from_le_bytes(b)
48}
49
50pub fn jitter_delay(base_ms: u64) -> Duration {
54 let mut b = [0u8; 2];
56 ferogram_crypto::fill_random(&mut b);
57 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)
60}
61
62pub fn tl_read_bytes(data: &[u8]) -> Option<Vec<u8>> {
67 if data.is_empty() {
68 return Some(vec![]);
69 }
70 let (len, start) = if data[0] < 254 {
71 (data[0] as usize, 1)
72 } else if data.len() >= 4 {
73 (
74 data[1] as usize | (data[2] as usize) << 8 | (data[3] as usize) << 16,
75 4,
76 )
77 } else {
78 return None;
79 };
80 if data.len() < start + len {
81 return None;
82 }
83 Some(data[start..start + len].to_vec())
84}
85
86pub fn tl_read_string(data: &[u8]) -> Option<String> {
89 tl_read_bytes(data).map(|b| String::from_utf8_lossy(&b).into_owned())
90}
91
92pub fn gz_inflate(data: &[u8]) -> Result<Vec<u8>, ConnectError> {
96 use std::io::Read;
97 let mut out = Vec::new();
98 if flate2::read::GzDecoder::new(data)
99 .read_to_end(&mut out)
100 .is_ok()
101 && !out.is_empty()
102 {
103 return Ok(out);
104 }
105 out.clear();
106 flate2::read::ZlibDecoder::new(data)
107 .read_to_end(&mut out)
108 .map_err(|_| ConnectError::other("decompression failed"))?;
109 Ok(out)
110}
111
112pub fn maybe_gz_decompress(body: Vec<u8>) -> Result<Vec<u8>, ConnectError> {
115 const ID_GZIP_PACKED_LOCAL: u32 = 0x3072cfa1;
116 if body.len() >= 4 && u32::from_le_bytes(body[0..4].try_into().unwrap()) == ID_GZIP_PACKED_LOCAL
117 {
118 let bytes = tl_read_bytes(&body[4..]).unwrap_or_default();
119 gz_inflate(&bytes)
120 } else {
121 Ok(body)
122 }
123}
124
125pub fn tl_write_bytes(data: &[u8]) -> Vec<u8> {
127 let len = data.len();
128 let mut out = Vec::with_capacity(4 + len);
129 if len < 254 {
130 out.push(len as u8);
131 out.extend_from_slice(data);
132 let pad = (4 - (1 + len) % 4) % 4;
133 out.extend(std::iter::repeat_n(0u8, pad));
134 } else {
135 out.push(0xfe);
136 out.extend_from_slice(&(len as u32).to_le_bytes()[..3]);
137 out.extend_from_slice(data);
138 let pad = (4 - (4 + len) % 4) % 4;
139 out.extend(std::iter::repeat_n(0u8, pad));
140 }
141 out
142}
143
144pub fn gz_pack_body(data: &[u8]) -> Vec<u8> {
146 use std::io::Write;
147 let mut enc = flate2::write::ZlibEncoder::new(Vec::new(), flate2::Compression::default());
148 let _ = enc.write_all(data);
149 let compressed = enc.finish().unwrap_or_default();
150 let mut out = Vec::with_capacity(4 + 4 + compressed.len());
151 out.extend_from_slice(&ID_GZIP_PACKED.to_le_bytes());
152 out.extend(tl_write_bytes(&compressed));
153 out
154}
155
156pub fn maybe_gz_pack(data: &[u8]) -> Vec<u8> {
159 if data.len() <= COMPRESSION_THRESHOLD {
160 return data.to_vec();
161 }
162 let packed = gz_pack_body(data);
163 if packed.len() < data.len() {
164 packed
165 } else {
166 data.to_vec()
167 }
168}
169
170pub fn build_msgs_ack_body(msg_ids: &[i64]) -> Vec<u8> {
174 let mut out = Vec::with_capacity(4 + 4 + 4 + msg_ids.len() * 8);
177 out.extend_from_slice(&ID_MSGS_ACK.to_le_bytes());
178 out.extend_from_slice(&0x1cb5c415_u32.to_le_bytes()); out.extend_from_slice(&(msg_ids.len() as u32).to_le_bytes());
180 for &id in msg_ids {
181 out.extend_from_slice(&id.to_le_bytes());
182 }
183 out
184}
185
186pub fn build_container_body(messages: &[(i64, i32, &[u8])]) -> Vec<u8> {
192 let total_body: usize = messages.iter().map(|(_, _, b)| 16 + b.len()).sum();
193 let mut out = Vec::with_capacity(8 + total_body);
194 out.extend_from_slice(&ID_MSG_CONTAINER.to_le_bytes());
195 out.extend_from_slice(&(messages.len() as u32).to_le_bytes());
196 for &(msg_id, seqno, body) in messages {
197 out.extend_from_slice(&msg_id.to_le_bytes());
198 out.extend_from_slice(&seqno.to_le_bytes());
199 out.extend_from_slice(&(body.len() as u32).to_le_bytes());
200 out.extend_from_slice(body);
201 }
202 out
203}