|
@@ -1,55 +1,25 @@
|
|
use mail_parser::{Message};
|
|
use mail_parser::{Message};
|
|
-use std::collections::{HashMap, HashSet};
|
|
|
|
use std::error::Error;
|
|
use std::error::Error;
|
|
-use std::path::{Path, PathBuf};
|
|
|
|
|
|
+use std::path::{PathBuf};
|
|
use models::*;
|
|
use models::*;
|
|
use std::ffi::{OsStr, OsString};
|
|
use std::ffi::{OsStr, OsString};
|
|
-use std::{fs, thread};
|
|
|
|
-use std::fs::{create_dir_all, File, OpenOptions};
|
|
|
|
|
|
+use std::{fs};
|
|
|
|
+use std::fs::{create_dir_all, File};
|
|
use std::future::Future;
|
|
use std::future::Future;
|
|
-use std::io::{BufReader, Write};
|
|
|
|
-use std::net::SocketAddr;
|
|
|
|
-use std::time::{Duration, Instant};
|
|
|
|
|
|
+use std::io::{Write};
|
|
|
|
+use std::time::{Instant};
|
|
use anyhow::anyhow;
|
|
use anyhow::anyhow;
|
|
use serde::{Deserialize, Serialize};
|
|
use serde::{Deserialize, Serialize};
|
|
-use crate::indexes::{Indexes, SerializableMessage, SerializableThread};
|
|
|
|
|
|
+use crate::indexes::{Indexes};
|
|
use config::{Config, INSTANCE};
|
|
use config::{Config, INSTANCE};
|
|
-use crate::server::{get_email, get_folders, get_sorted_threads_by_date, get_thread_messages};
|
|
|
|
|
|
+use crate::server::{run_api};
|
|
use mailparse::parse_mail;
|
|
use mailparse::parse_mail;
|
|
use regex::Regex;
|
|
use regex::Regex;
|
|
use crate::templates::util::parse_email;
|
|
use crate::templates::util::parse_email;
|
|
-use crate::util::{compress_and_save_file, read_and_decompress_file};
|
|
|
|
|
|
+use crate::util::{compress_and_save_file};
|
|
use crate::imap::{delete_folder, rename_folder, create_folder, check_for_updates};
|
|
use crate::imap::{delete_folder, rename_folder, create_folder, check_for_updates};
|
|
use crate::js::email_scripts;
|
|
use crate::js::email_scripts;
|
|
-use tokio::runtime::Runtime;
|
|
|
|
-
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-use axum::extract::Query;
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-use axum::{Json, Router};
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-use axum::http::{Method, StatusCode};
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-use axum::response::{IntoResponse, Response};
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-use axum::routing::{get, post};
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-use tower_http::cors::{Any, CorsLayer};
|
|
|
|
-
|
|
|
|
-#[cfg(target_os = "wasi")]
|
|
|
|
-use bytecodec::DecodeExt;
|
|
|
|
-#[cfg(target_os = "wasi")]
|
|
|
|
-use httpcodec::{HttpVersion, ReasonPhrase, Request, RequestDecoder, Response, StatusCode, Header};
|
|
|
|
-#[cfg(target_os = "wasi")]
|
|
|
|
-use lettre::message::{Mailbox, Message as LettreMessage, MultiPart, SinglePart};
|
|
|
|
-use tokio::task;
|
|
|
|
-use tokio::time::sleep;
|
|
|
|
-#[cfg(target_os = "wasi")]
|
|
|
|
-use wasmedge_wasi_socket::{Shutdown, TcpListener, TcpStream};
|
|
|
|
-#[cfg(target_os = "wasi")]
|
|
|
|
-use crate::server_wasi::{handle_client};
|
|
|
|
-#[cfg(target_os = "wasi")]
|
|
|
|
-use crate::smtp_client::{send_email};
|
|
|
|
|
|
+use warp::Filter;
|
|
|
|
|
|
mod smtp_client;
|
|
mod smtp_client;
|
|
|
|
|
|
@@ -61,7 +31,6 @@ mod util;
|
|
mod indexes;
|
|
mod indexes;
|
|
mod imap;
|
|
mod imap;
|
|
mod server;
|
|
mod server;
|
|
-mod server_wasi;
|
|
|
|
mod js;
|
|
mod js;
|
|
|
|
|
|
pub fn append_ext(ext: impl AsRef<OsStr>, path: &PathBuf) -> PathBuf {
|
|
pub fn append_ext(ext: impl AsRef<OsStr>, path: &PathBuf) -> PathBuf {
|
|
@@ -403,24 +372,16 @@ async fn main() -> anyhow::Result<()> {
|
|
|
|
|
|
|
|
|
|
// looking for updates
|
|
// looking for updates
|
|
- let imap_update_handler = imap::check_for_updates("INBOX".to_string()).await;
|
|
|
|
-
|
|
|
|
|
|
+ if let Err(e) = check_for_updates("INBOX".to_string()).await {
|
|
|
|
+ eprintln!("Failed to monitor mailbox: {:?}", e);
|
|
|
|
+ }
|
|
|
|
|
|
let duration = start.elapsed();
|
|
let duration = start.elapsed();
|
|
println!("Duration {:?}", duration);
|
|
println!("Duration {:?}", duration);
|
|
|
|
|
|
|
|
|
|
// API
|
|
// API
|
|
- println!("Server is running on {}", Config::global().api_port);
|
|
|
|
- let listener = TcpListener::bind(format!("{}:{}", Config::global().api_addr, Config::global().api_port), false)?;
|
|
|
|
- loop {
|
|
|
|
- let (stream, _) = listener.accept(false)?;
|
|
|
|
- task::spawn(async move {
|
|
|
|
- if let Err(e) = handle_client(stream).await {
|
|
|
|
- eprintln!("Error handling client: {:?}", e);
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
|
|
+ run_api().await;
|
|
|
|
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
@@ -454,158 +415,14 @@ async fn main() {
|
|
|
|
|
|
// delete_email("lqo7m8r2.1js7w080jvr2o@express.medallia.com".to_string()).await.expect("Unable to delete an email");
|
|
// delete_email("lqo7m8r2.1js7w080jvr2o@express.medallia.com".to_string()).await.expect("Unable to delete an email");
|
|
|
|
|
|
-
|
|
|
|
- // looking for updates
|
|
|
|
- // let imap_update_handle = tokio::spawn(async move {
|
|
|
|
- // if let Err(e) = check_for_updates("INBOX".to_string()).await {
|
|
|
|
- // eprintln!("Failed to monitor mailbox: {:?}", e);
|
|
|
|
- // }
|
|
|
|
- // });
|
|
|
|
|
|
+
|
|
if let Err(e) = check_for_updates("INBOX".to_string()).await {
|
|
if let Err(e) = check_for_updates("INBOX".to_string()).await {
|
|
eprintln!("Failed to monitor mailbox: {:?}", e);
|
|
eprintln!("Failed to monitor mailbox: {:?}", e);
|
|
}
|
|
}
|
|
|
|
|
|
- // imap::create_folder("testFolder".to_string()).await.unwrap();
|
|
|
|
- // imap::rename_folder("testFolder".to_string(), "newTestFolder".to_string()).await.unwrap();
|
|
|
|
- // imap::delete_folder("newTestFolder".to_string()).await.unwrap();
|
|
|
|
-
|
|
|
|
let duration = start.elapsed();
|
|
let duration = start.elapsed();
|
|
println!("Duration {:?}", duration);
|
|
println!("Duration {:?}", duration);
|
|
|
|
|
|
// API
|
|
// API
|
|
- // Define the CORS layer
|
|
|
|
- let handle = thread::spawn(|| {
|
|
|
|
- let cors = CorsLayer::new()
|
|
|
|
- .allow_origin(Any)
|
|
|
|
- .allow_methods(vec![Method::GET, Method::POST])
|
|
|
|
- .allow_headers(Any);
|
|
|
|
-
|
|
|
|
- let app = Router::new()
|
|
|
|
- .route("/folders", get(get_folders_handle))
|
|
|
|
- .route("/sorted_threads_by_date", get(sorted_threads_by_date_handle))
|
|
|
|
- .route("/get_thread_messages", get(get_thread_messages_handle))
|
|
|
|
- .route("/email", get(get_email_handle))
|
|
|
|
- .route("/create_folder", post(create_folder_handle))
|
|
|
|
- .route("/rename_folder", post(rename_folder_handle))
|
|
|
|
- .route("/delete_folder", post(delete_folder_handle))
|
|
|
|
- .layer(cors);
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- let rt = Runtime::new().unwrap();
|
|
|
|
- // Use the runtime to block on the async task
|
|
|
|
- rt.block_on(async {
|
|
|
|
- let listener = tokio::net::TcpListener::bind(format!("{}:{}", Config::global().api_addr, Config::global().api_port)).await.unwrap();
|
|
|
|
- println!("Server is running on {}", Config::global().api_port);
|
|
|
|
- axum::serve(listener, app).await.unwrap();
|
|
|
|
- });
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- handle.join().unwrap();
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#[derive(Deserialize)]
|
|
|
|
-#[derive(Serialize)]
|
|
|
|
-struct ErrorResponse {
|
|
|
|
- error: String,
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-#[derive(Deserialize)]
|
|
|
|
-struct GetSortedThreadsByDateQuery {
|
|
|
|
- folder: String,
|
|
|
|
-}
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-async fn sorted_threads_by_date_handle(Query(params): Query<GetSortedThreadsByDateQuery>) -> Json<Vec<(String, Vec<u32>)>> {
|
|
|
|
- let result: Vec<(String, Vec<u32>)> = serde_json::from_str(&*get_sorted_threads_by_date(params.folder).await).unwrap();
|
|
|
|
- Json(result)
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-async fn get_folders_handle() -> Json<Vec<String>> {
|
|
|
|
- let result: Vec<String> = serde_json::from_str(&*get_folders().await).unwrap();
|
|
|
|
- Json(result)
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-#[derive(Deserialize)]
|
|
|
|
-struct GetEmailQuery {
|
|
|
|
- id: String,
|
|
|
|
-}
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-async fn get_email_handle(Query(params): Query<GetEmailQuery>) -> Response {
|
|
|
|
- let result: String = get_email(params.id).await;
|
|
|
|
- result.into_response()
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-#[derive(Deserialize)]
|
|
|
|
-struct GetThreadMessagesQuery {
|
|
|
|
- id: u32,
|
|
|
|
-}
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-async fn get_thread_messages_handle(Query(params): Query<GetThreadMessagesQuery>) -> Json<Vec<SerializableMessage>> {
|
|
|
|
- let result: Vec<SerializableMessage> = serde_json::from_str(&*get_thread_messages(params.id).await).unwrap();
|
|
|
|
- Json(result)
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-#[derive(Deserialize)]
|
|
|
|
-struct CreateFolderRequest {
|
|
|
|
- name: String,
|
|
|
|
-}
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-async fn create_folder_handle(Json(data): Json<CreateFolderRequest>) -> impl IntoResponse {
|
|
|
|
- match create_folder_lar(data.name.clone()).await {
|
|
|
|
- Ok(_) => {
|
|
|
|
- (StatusCode::OK, "OK").into_response()
|
|
|
|
- }
|
|
|
|
- Err(_) => {
|
|
|
|
- let error_response = ErrorResponse {
|
|
|
|
- error: format!("Cannot create folder {}", data.name),
|
|
|
|
- };
|
|
|
|
- (StatusCode::BAD_REQUEST, Json(error_response)).into_response()
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-#[derive(Deserialize)]
|
|
|
|
-struct DeleteFolderRequest {
|
|
|
|
- name: String,
|
|
|
|
-}
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-async fn delete_folder_handle(Json(data): Json<DeleteFolderRequest>) -> impl IntoResponse {
|
|
|
|
- match delete_folder_lar(data.name.clone()).await {
|
|
|
|
- Ok(_) => {
|
|
|
|
- (StatusCode::OK, "OK").into_response()
|
|
|
|
- }
|
|
|
|
- Err(_) => {
|
|
|
|
- let error_response = ErrorResponse {
|
|
|
|
- error: format!("Cannot delete folder {}", data.name),
|
|
|
|
- };
|
|
|
|
- (StatusCode::BAD_REQUEST, Json(error_response)).into_response()
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-#[derive(Deserialize)]
|
|
|
|
-struct RenameFolderRequest {
|
|
|
|
- old_name: String,
|
|
|
|
- new_name: String
|
|
|
|
-}
|
|
|
|
-#[cfg(not(target_os = "wasi"))]
|
|
|
|
-async fn rename_folder_handle(Json(data): Json<RenameFolderRequest>) -> impl IntoResponse {
|
|
|
|
- match rename_folder_lar(data.old_name.clone(), data.new_name.clone()).await {
|
|
|
|
- Ok(_) => {
|
|
|
|
- (StatusCode::OK, "OK").into_response()
|
|
|
|
- }
|
|
|
|
- Err(_) => {
|
|
|
|
- let error_response = ErrorResponse {
|
|
|
|
- error: format!("Cannot rename folder from {} to {}", data.old_name, data.new_name),
|
|
|
|
- };
|
|
|
|
- (StatusCode::BAD_REQUEST, Json(error_response)).into_response()
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ run_api().await;
|
|
}
|
|
}
|