瀏覽代碼

compress emails with tar.gz

Yurii Sokolovskyi 3 月之前
父節點
當前提交
4cbccb7fae
共有 4 個文件被更改,包括 91 次插入16 次删除
  1. 2 0
      Cargo.toml
  2. 15 7
      src/main.rs
  3. 19 9
      src/server.rs
  4. 55 0
      src/util.rs

+ 2 - 0
Cargo.toml

@@ -33,6 +33,8 @@ serde = { version = "1.0.201", features = ["derive"] }
 pathdiff = "0.2.1"
 base64 = "0.22.1"
 lettre = {version = "0.11.7", default-features = false, features = ["builder"]}
+tar = "0.4"
+flate2 = "1.0"
 
 [target.'cfg(target_os = "wasi")'.dependencies]
 tokio_wasi = {version = "1.25.2", features = ["full", "rt", "rt-multi-thread", "macros", "time"] }

+ 15 - 7
src/main.rs

@@ -45,6 +45,7 @@ use wasmedge_wasi_socket::{Shutdown, TcpListener, TcpStream};
 use crate::server_wasi::{handle_client};
 #[cfg(target_os = "wasi")]
 use crate::smtp_client::{send_email};
+use crate::util::{compress_and_save_file, read_and_decompress_file};
 
 mod smtp_client;
 
@@ -177,11 +178,17 @@ fn persist_email(msg: &Message, uid: u32, list: String, original_path: PathBuf)
     };
     message.set_path(relative_path.display().to_string());
     if Config::global().include_html {
-        let html = append_ext("html", &message_dir.join(message.hash.clone()));
-        let mut file = File::create(html)?;
+        // let html = append_ext("html", &message_dir.join(message.hash.clone()));
+        // let mut file = File::create(html)?;
+        // let data = message_to_html(message.clone());
+        // file.write_all(data.as_bytes())?;
+        // file.flush()?;
+
         let data = message_to_html(message.clone());
-        file.write_all(data.as_bytes())?;
-        file.flush()?;
+        match compress_and_save_file(message_dir.clone(), message.hash.clone(), data.as_bytes()){
+            Ok(_) => {}
+            Err(_) => {println!("Error while compressing or saving {}", message.hash.clone())}
+        };
     }
 
     // xml
@@ -367,6 +374,7 @@ async fn main() -> anyhow::Result<()> {
 async fn main() {
     run().await;
     
+    
     // let email = LettreMessage::builder()
     //     .from("sokolovskiiyura@outlook.com".parse().unwrap())
     //     .to("sokolovskiiyura@gmail.com".parse().unwrap())
@@ -390,9 +398,9 @@ async fn main() {
 
 
     // looking for updates
-    let imap_update_handle = tokio::spawn(async move {
-        imap::check_for_updates("INBOX".to_string()).await.expect("TODO: panic message");
-    });
+    // let imap_update_handle = tokio::spawn(async move {
+    //     imap::check_for_updates("INBOX".to_string()).await.expect("TODO: panic message");
+    // });
     
 
     // imap::create_folder("testFolder".to_string()).await.unwrap();

+ 19 - 9
src/server.rs

@@ -5,7 +5,10 @@ use std::collections::HashMap;
 use std::fs::File;
 use std::io;
 use std::io::{BufReader, Read};
+use std::string::FromUtf8Error;
 use chrono::NaiveDate;
+// use serde_json::Value::String;
+use crate::util::read_and_decompress_file;
 
 pub async fn get_folders() -> String {
     let mut folders: Vec<String> = Vec::new();
@@ -49,16 +52,23 @@ pub async fn get_email(id: String) -> String {
     let abs_path = Config::global().out_dir.clone()
         .join(message.list.clone())
         .join("messages")
-        .join(message.hash.clone() + ".html");
-    let mut file = match File::open(abs_path.clone()) {
-        Ok(content) => {content}
-        Err(_) => {return "".to_string()}
-    };
-    let mut content = String::new();
-    match file.read_to_string(&mut content) {
-        Ok(_) => {}
-        Err(_) => {return String::new()}
+        .join(message.hash.clone() + ".tar.gz");
+    // let mut file = match File::open(abs_path.clone()) {
+    //     Ok(content) => {content}
+    //     Err(_) => {return "".to_string()}
+    // };
+    // let mut content = String::new();
+    // match file.read_to_string(&mut content) {
+    //     Ok(_) => {}
+    //     Err(_) => {return String::new()}
+    // };
+    let mut content = match read_and_decompress_file(abs_path, message.hash.clone()) {
+        Ok(content) => {
+            String::from_utf8_lossy(&content).to_string()
+        }
+        Err(_) => String::new()
     };
+    
     content
 }
 

+ 55 - 0
src/util.rs

@@ -1,4 +1,10 @@
+use std::fs::{create_dir_all, File};
+use std::io::{Cursor, Read, Write};
 use std::path::PathBuf;
+use flate2::Compression;
+use flate2::read::GzDecoder;
+use flate2::write::GzEncoder;
+use tar::{Archive, Builder, Header};
 
 // Truncate a string, adding ellpises if it's too long
 pub fn truncate_ellipsis(s: &str, n: usize) -> String {
@@ -26,3 +32,52 @@ pub const EPOCH: mail_parser::DateTime = mail_parser::DateTime {
     tz_hour: 0,
     tz_minute: 0,
 };
+
+pub fn compress_and_save_file(dir_path: PathBuf, file_name: String, content: &[u8]) -> anyhow::Result<()>{
+    if !dir_path.exists() { create_dir_all(dir_path.clone()).ok(); }
+    
+    let archive_path = dir_path.join(file_name.clone() + ".tar.gz");
+    let tar_gz = File::create(archive_path)?;
+    let enc = GzEncoder::new(tar_gz, Compression::default());
+    let mut tar = Builder::new(enc);
+
+    let mut header = Header::new_gnu();
+    header.set_path(&file_name)?;
+    header.set_size(content.len() as u64);
+    header.set_cksum();
+
+    let cursor = Cursor::new(content);
+
+    tar.append(&header, cursor)?;
+
+    let enc = tar.into_inner()?;
+    enc.finish()?;
+    Ok(())
+}
+
+pub fn read_and_decompress_file(archive_path: PathBuf, file_name: String) -> anyhow::Result<Vec<u8>> {
+    // Open the compressed archive file
+    let tar_gz = File::open(&archive_path)?;
+
+    // Create a GzDecoder to decompress the archive
+    let dec = GzDecoder::new(tar_gz);
+
+    // Create a tar archive for reading files from the decompressed stream
+    let mut archive = Archive::new(dec);
+
+    // Iterate over the entries in the archive
+    for entry in archive.entries()? {
+        let mut entry = entry?;
+
+        // Check if this entry is the file we're looking for
+        if entry.path()?.file_name().map_or(false, |name| name.to_owned().to_str().unwrap() == file_name) {
+            // Read the file's content into a buffer
+            let mut content = Vec::new();
+            entry.read_to_end(&mut content)?;
+
+            return Ok(content);
+        }
+    }
+
+    Err(anyhow::anyhow!("File {} not found in the archive", file_name))
+}