Mountain/IPC/Encryption/
MessageCompressor.rs1use std::io::{Read, Write};
36
37use flate2::{Compression, read::GzDecoder, write::GzEncoder};
38
39use super::super::Message::Types::TauriIPCMessage;
40use crate::dev_log;
41
42pub struct MessageCompressor {
108 CompressionLevel:u32,
110
111 BatchSize:usize,
113}
114
115impl MessageCompressor {
116 pub fn new(CompressionLevel:u32, BatchSize:usize) -> Self {
128 dev_log!(
129 "encryption",
130 "[MessageCompressor] Created with level: {}, batch size: {}",
131 CompressionLevel,
132 BatchSize
133 );
134
135 Self { CompressionLevel, BatchSize }
136 }
137
138 pub fn compress_messages(&self, Messages:Vec<TauriIPCMessage>) -> Result<Vec<u8>, String> {
157 dev_log!("encryption", "[MessageCompressor] Compressing {} messages", Messages.len());
158
159 let SerializedMessages =
161 serde_json::to_vec(&Messages).map_err(|e| format!("Failed to serialize messages: {}", e))?;
162
163 let original_size = SerializedMessages.len();
164
165 let mut encoder = GzEncoder::new(Vec::new(), Compression::new(self.CompressionLevel));
167
168 encoder
169 .write_all(&SerializedMessages)
170 .map_err(|e| format!("Failed to compress messages: {}", e))?;
171
172 let compressed_data = encoder.finish().map_err(|e| format!("Failed to finish compression: {}", e))?;
173
174 let compressed_size = compressed_data.len();
175
176 let ratio = if original_size > 0 {
177 (compressed_size as f64 / original_size as f64) * 100.0
178 } else {
179 100.0
180 };
181
182 dev_log!(
183 "encryption",
184 "[MessageCompressor] Compression complete: {} -> {} bytes ({:.1}%)",
185 original_size,
186 compressed_size,
187 ratio
188 );
189
190 Ok(compressed_data)
191 }
192
193 pub fn decompress_messages(&self, CompressedData:&[u8]) -> Result<Vec<TauriIPCMessage>, String> {
211 dev_log!("encryption", "[MessageCompressor] Decompressing {} bytes", CompressedData.len());
212
213 let compressed_size = CompressedData.len();
214
215 let mut decoder = GzDecoder::new(CompressedData);
217
218 let mut DecompressedData = Vec::new();
219
220 decoder
221 .read_to_end(&mut DecompressedData)
222 .map_err(|e| format!("Failed to decompress data: {}", e))?;
223
224 let decompressed_size = DecompressedData.len();
225
226 let messages:Vec<TauriIPCMessage> =
228 serde_json::from_slice(&DecompressedData).map_err(|e| format!("Failed to deserialize messages: {}", e))?;
229
230 dev_log!(
231 "encryption",
232 "[MessageCompressor] Decompression complete: {} -> {} bytes, {} messages",
233 compressed_size,
234 decompressed_size,
235 messages.len()
236 );
237
238 Ok(messages)
239 }
240
241 pub fn should_batch(&self, MessagesCount:usize) -> bool {
263 let should_batch = MessagesCount >= self.BatchSize;
264
265 dev_log!(
266 "encryption",
267 "[MessageCompressor] Batch check: {} >= {} = {}",
268 MessagesCount,
269 self.BatchSize,
270 should_batch
271 );
272
273 should_batch
274 }
275
276 pub fn compression_level(&self) -> u32 { self.CompressionLevel }
278
279 pub fn batch_size(&self) -> usize { self.BatchSize }
281
282 pub fn default() -> Self { Self::new(6, 10) }
284
285 pub fn fast() -> Self { Self::new(3, 5) }
287
288 pub fn max() -> Self { Self::new(9, 20) }
290}
291
292#[cfg(test)]
293#[allow(unused_imports)]
294mod tests {
295
296 use super::*;
297
298 fn create_test_message(id:u32) -> TauriIPCMessage {
299 TauriIPCMessage::new(
300 format!("test_channel_{}", id),
301 serde_json::json!({
302 "id": id,
303 "data": "test data that should compress well when repeated many times across multiple messages".repeat(10)
304 }),
305 Some("test_sender".to_string()),
306 )
307 }
308
309 #[test]
310 fn test_compressor_creation() {
311 let compressor = MessageCompressor::new(6, 10);
312
313 assert_eq!(compressor.compression_level(), 6);
314
315 assert_eq!(compressor.batch_size(), 10);
316 }
317
318 #[test]
319 fn test_default_compressor() {
320 let compressor = MessageCompressor::default();
321
322 assert_eq!(compressor.compression_level(), 6);
323
324 assert_eq!(compressor.batch_size(), 10);
325 }
326
327 #[test]
328 fn test_fast_compressor() {
329 let compressor = MessageCompressor::fast();
330
331 assert_eq!(compressor.compression_level(), 3);
332
333 assert_eq!(compressor.batch_size(), 5);
334 }
335
336 #[test]
337 fn test_max_compressor() {
338 let compressor = MessageCompressor::max();
339
340 assert_eq!(compressor.compression_level(), 9);
341
342 assert_eq!(compressor.batch_size(), 20);
343 }
344
345 #[test]
346 fn test_should_batch() {
347 let compressor = MessageCompressor::new(6, 10);
348
349 assert!(!compressor.should_batch(5));
350
351 assert!(compressor.should_batch(10));
352
353 assert!(compressor.should_batch(15));
354 }
355
356 #[test]
357 fn test_compress_and_decompress() {
358 let compressor = MessageCompressor::default();
359
360 let original_messages = vec![create_test_message(1), create_test_message(2), create_test_message(3)];
361
362 let compressed = compressor.compress_messages(original_messages.clone()).unwrap();
364
365 assert!(!compressed.is_empty());
366
367 let decompressed = compressor.decompress_messages(&compressed).unwrap();
369
370 assert_eq!(decompressed.len(), original_messages.len());
371
372 for i in 0..original_messages.len() {
374 assert_eq!(decompressed[i].channel, original_messages[i].channel);
375 }
376 }
377
378 #[test]
379 fn test_compression_ratio() {
380 let compressor = MessageCompressor::default();
381
382 let messages:Vec<TauriIPCMessage> = (0..20).map(|i| create_test_message(i)).collect();
384
385 let compressed = compressor.compress_messages(messages.clone()).unwrap();
386
387 let original_data = serde_json::to_vec(&messages).unwrap();
389
390 assert!(compressed.len() < original_data.len());
391 }
392
393 #[test]
394 fn test_empty_messages() {
395 let compressor = MessageCompressor::default();
396
397 let messages = vec![];
398
399 let compressed = compressor.compress_messages(messages).unwrap();
400
401 let decompressed = compressor.decompress_messages(&compressed).unwrap();
402
403 assert!(decompressed.is_empty());
404 }
405
406 #[test]
407 fn test_single_message() {
408 let compressor = MessageCompressor::default();
409
410 let messages = vec![create_test_message(1)];
411
412 let compressed = compressor.compress_messages(messages.clone()).unwrap();
413
414 let decompressed = compressor.decompress_messages(&compressed).unwrap();
415
416 assert_eq!(decompressed.len(), 1);
417
418 assert_eq!(decompressed[0].channel, messages[0].channel);
419 }
420}