DevelopmentNodeEnvironment_MicrosoftVSCodeDependency_22NodeVersion_Bundle_Clean_Debug_ElectronProfile_EsbuildCompiler_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)]
293mod tests {
294
295 use super::*;
296
297 fn create_test_message(id:u32) -> TauriIPCMessage {
298 TauriIPCMessage::new(
299 format!("test_channel_{}", id),
300 serde_json::json!({
301 "id": id,
302 "data": "test data that should compress well when repeated many times across multiple messages".repeat(10)
303 }),
304 Some("test_sender".to_string()),
305 )
306 }
307
308 #[test]
309 fn test_compressor_creation() {
310 let compressor = MessageCompressor::new(6, 10);
311
312 assert_eq!(compressor.compression_level(), 6);
313
314 assert_eq!(compressor.batch_size(), 10);
315 }
316
317 #[test]
318 fn test_default_compressor() {
319 let compressor = MessageCompressor::default();
320
321 assert_eq!(compressor.compression_level(), 6);
322
323 assert_eq!(compressor.batch_size(), 10);
324 }
325
326 #[test]
327 fn test_fast_compressor() {
328 let compressor = MessageCompressor::fast();
329
330 assert_eq!(compressor.compression_level(), 3);
331
332 assert_eq!(compressor.batch_size(), 5);
333 }
334
335 #[test]
336 fn test_max_compressor() {
337 let compressor = MessageCompressor::max();
338
339 assert_eq!(compressor.compression_level(), 9);
340
341 assert_eq!(compressor.batch_size(), 20);
342 }
343
344 #[test]
345 fn test_should_batch() {
346 let compressor = MessageCompressor::new(6, 10);
347
348 assert!(!compressor.should_batch(5));
349
350 assert!(compressor.should_batch(10));
351
352 assert!(compressor.should_batch(15));
353 }
354
355 #[test]
356 fn test_compress_and_decompress() {
357 let compressor = MessageCompressor::default();
358
359 let original_messages = vec![create_test_message(1), create_test_message(2), create_test_message(3)];
360
361 let compressed = compressor.compress_messages(original_messages.clone()).unwrap();
363
364 assert!(!compressed.is_empty());
365
366 let decompressed = compressor.decompress_messages(&compressed).unwrap();
368
369 assert_eq!(decompressed.len(), original_messages.len());
370
371 for i in 0..original_messages.len() {
373 assert_eq!(decompressed[i].channel, original_messages[i].channel);
374 }
375 }
376
377 #[test]
378 fn test_compression_ratio() {
379 let compressor = MessageCompressor::default();
380
381 let messages:Vec<TauriIPCMessage> = (0..20).map(|i| create_test_message(i)).collect();
383
384 let compressed = compressor.compress_messages(messages.clone()).unwrap();
385
386 let original_data = serde_json::to_vec(&messages).unwrap();
388
389 assert!(compressed.len() < original_data.len());
390 }
391
392 #[test]
393 fn test_empty_messages() {
394 let compressor = MessageCompressor::default();
395
396 let messages = vec![];
397
398 let compressed = compressor.compress_messages(messages).unwrap();
399
400 let decompressed = compressor.decompress_messages(&compressed).unwrap();
401
402 assert!(decompressed.is_empty());
403 }
404
405 #[test]
406 fn test_single_message() {
407 let compressor = MessageCompressor::default();
408
409 let messages = vec![create_test_message(1)];
410
411 let compressed = compressor.compress_messages(messages.clone()).unwrap();
412
413 let decompressed = compressor.decompress_messages(&compressed).unwrap();
414
415 assert_eq!(decompressed.len(), 1);
416
417 assert_eq!(decompressed[0].channel, messages[0].channel);
418 }
419}