3
2

3 Коміти bd252a9a68 ... ba9b6da1f4

Автор SHA1 Опис Дата
  Yurii Sokolovskyi ba9b6da1f4 converting emails in parallel with downloading 1 тиждень тому
  Yurii Sokolovskyi 11e4354e13 mailbox folder creating in the output directory moved to the email conversion 1 тиждень тому
  Yurii Sokolovskyi 0b825c6684 API works in parallel with downloading emails 1 тиждень тому
2 змінених файлів з 58 додано та 49 видалено
  1. 31 12
      src/imap.rs
  2. 27 37
      src/main.rs

+ 31 - 12
src/imap.rs

@@ -1,7 +1,7 @@
 use std::collections::{HashMap, HashSet};
 use std::{io};
 use std::convert::TryFrom;
-use std::fs::File;
+use std::fs::{create_dir_all, File};
 use std::future::Future;
 use std::path::{PathBuf};
 use std::io::{BufReader, BufWriter, ErrorKind, Read, Write};
@@ -29,6 +29,7 @@ use async_imap::extensions::idle::IdleResponse::NewData;
 use async_imap_wasi::{Client, Session};
 #[cfg(target_os = "wasi")]
 use async_imap_wasi::extensions::idle::IdleResponse::NewData;
+use crate::indexes::Indexes;
 
 /// create TLS connect with the IMAP server
 pub async fn connect_to_imap() -> anyhow::Result<Client<TlsStream<TcpStream>>>{
@@ -104,14 +105,17 @@ pub async fn list_imap_folders(session: &mut Session<TlsStream<TcpStream>>) -> a
 
 /// download all emails from one mailbox 
 pub async fn fetch_and_store_emails(session: &mut Session<TlsStream<TcpStream>>, list: String) -> anyhow::Result<Vec<(u32, PathBuf)>> {
+    let out_dir_name = Config::global().out_dir.clone().join(list.clone());
+    if !out_dir_name.exists() { create_dir_all(out_dir_name).ok(); }
+    
     session.select(list.clone()).await?;
 
     // Create directories for maildir
-    std::fs::create_dir_all(Config::global().maildir.clone().join(list.clone()).join("new"))
+    create_dir_all(Config::global().maildir.clone().join(list.clone()).join("new"))
         .expect(&*("Unable to create 'new' directory in ".to_owned() + &*list.clone()));
-    std::fs::create_dir_all(Config::global().maildir.clone().join(list.clone()).join("cur"))
+    create_dir_all(Config::global().maildir.clone().join(list.clone()).join("cur"))
         .expect(&*("Unable to create 'cur' directory in ".to_owned() + &*list.clone()));
-    std::fs::create_dir_all(Config::global().maildir.clone().join(list.clone()).join("tmp"))
+    create_dir_all(Config::global().maildir.clone().join(list.clone()).join("tmp"))
         .expect(&*("Unable to create 'tmp' directory in ".to_owned() + &*list.clone()));
 
     let uids_path = Config::global().maildir.clone().join(".uids.json");
@@ -144,7 +148,21 @@ pub async fn fetch_and_store_emails(session: &mut Session<TlsStream<TcpStream>>,
             if let Some(body) = msg.body() {
                 let mail_file = store(Config::global().maildir.clone().join(list.clone()), uid.clone().to_string(), "new".to_string(), body, "");
                 match mail_file {
-                    Ok(file) => stored_paths.push((uid.to_string().parse().unwrap(), file)),
+                    Ok(file) => {
+                        // TODO convert and persist html
+                        // persist to the maildir
+                        stored_paths.push((uid.to_string().parse().unwrap(), file.clone()));
+                        
+                        // persist to the output dir
+                        match add_email(file.clone(), uid.clone()){
+                            Ok(_) => {}
+                            Err(_) => {println!("Error adding email from {:?}", file.clone())}
+                        };
+                        
+                        // TODO adjust indexes
+                        Indexes::persist_threads().expect("Unable to persist threads");
+                        Indexes::persist_indexes(vec![list.clone()]).expect("Unable to persist indexes");
+                    },
                     Err(e) => eprintln!("Failed to store email: {}", e),
                 }
             } else {
@@ -317,13 +335,14 @@ pub async fn check_for_updates(mailbox: String) -> anyhow::Result<()> {
                 // TODO add more cases like delete, move...
                 NewData(data) => {
                     // TODO do not update all emails (IMAP returns * {number} RECENT) and do it only for one mailbox
-                    let new_paths = download_email_from_imap().await.expect("Cannot download new emails");
-                    for (uid, path) in new_paths.clone() {
-                        match add_email(path.clone(), uid.clone()){
-                            Ok(_) => {}
-                            Err(_) => {println!("Error adding email from {:?}", path.clone())}
-                        };
-                    }
+                    // TODO CHANGE IT!!!
+                    // let new_paths = download_email_from_imap().await.expect("Cannot download new emails");
+                    // for (uid, path) in new_paths.clone() {
+                    //     match add_email(path.clone(), uid.clone()){
+                    //         Ok(_) => {}
+                    //         Err(_) => {println!("Error adding email from {:?}", path.clone())}
+                    //     };
+                    // }
                 }
                 reason => {
                     println!("IDLE failed {:?}", reason);

+ 27 - 37
src/main.rs

@@ -330,52 +330,35 @@ async fn run(){
     // parse args from CLI
     parse_args();
 
-    // downloading new emails
-    let new_paths = imap::download_email_from_imap().await.expect("Cannot download new emails");
+    // API
+    let api_task = tokio::spawn(async move {
+        run_api().await
+    });
     
-    let mut lists: Vec<String> = Vec::new();
-
-    for mail_list in std::fs::read_dir(Config::global().maildir.clone())
-        .expect("could not read maildir")
-        .filter_map(|m| m.ok())
-    {
-        let dir_name = mail_list.file_name().into_string().unwrap();
-        
-        if dir_name.starts_with('.') || ["cur", "new", "tmp"].contains(&dir_name.as_str()) {
-            continue; 
-        }
-        
-        lists.push(dir_name.clone());
-        let out_dir_name = Config::global().out_dir.clone().join(dir_name);
-        if !out_dir_name.exists() { create_dir_all(out_dir_name).ok(); }
-    }
+    // downloading new emails
+    imap::download_email_from_imap().await.expect("Cannot download new emails");
     
+    // Uncomment to convert to HTML without downloading
     // let mut uid = 1; // fake uid for tests
     // for entry in std::fs::read_dir(Config::global().maildir.clone().join("INBOX").join("new")).expect("could not read maildir").filter_map(|m| m.ok()){
-    for (uid, path) in new_paths.clone() {
-        // let path = entry.path();
-
-        match add_email(path.clone(), uid.clone()){
-            Ok(_) => {}
-            Err(_) => {println!("Error adding email from {:?}", path.clone())}
-        };
-        
-        // uid += 1;
-    }
+    //     let path = entry.path();
+    // 
+    //     match add_email(path.clone(), uid.clone()){
+    //         Ok(_) => {}
+    //         Err(_) => {println!("Error adding email from {:?}", path.clone())}
+    //     };
+    //     
+    //     uid += 1;
+    // }
 
-    let threads_indexes_path = Config::global().out_dir.clone().join("threads.json");
-    if !threads_indexes_path.exists() {
-        Indexes::persist_threads().expect("Unable to persist threads");
-        Indexes::persist_indexes(lists).expect("Unable to persist indexes");    
-    }
 
     // monitor updates in INBOX
     if let Err(e) = check_for_updates("INBOX".to_string()).await {
         eprintln!("Failed to monitor mailbox: {:?}", e);
     }
-
-    // API
-    run_api().await;
+    
+    // dont stop the program while API is running
+    api_task.await.expect("Error while running API");
 }
 
 /// Entry point for a wasi env
@@ -407,13 +390,16 @@ async fn main() -> anyhow::Result<()> {
     
     // delete_email("Sent".to_string(), 4).await;
     
+    println!("{:?}", Instant::now() - start);
     Ok(())
 }
 
 /// Entry point for a not wasi env
 #[cfg(not(target_os = "wasi"))]
 #[tokio::main]
-async fn main() {
+async fn main() -> anyhow::Result<()>{
+    let start = Instant::now();
+    
     run().await;
     
     // let email = LettreMessage::builder()
@@ -436,4 +422,8 @@ async fn main() {
 
     
     // delete_email("[email protected]".to_string()).await.expect("Unable to delete an email");
+
+    println!("{:?}", Instant::now() - start);
+    
+    Ok(())
 }