From 4644349ebb5b4d0c06fcdc7c7ed0534d60db2e1d Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Mon, 8 May 2023 10:43:22 +0300 Subject: [PATCH] Remove warp --- Cargo.lock | 118 ------------------ archive-http/Cargo.toml | 12 -- archive-http/src/main.rs | 260 ++++++++++++++++++++++----------------- rest-http/Cargo.toml | 1 - rest-http/README.md | 4 +- rest-http/src/main.rs | 71 +---------- 6 files changed, 149 insertions(+), 317 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0ef3b52..2efe9e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -547,12 +547,6 @@ version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - [[package]] name = "bytes" version = "1.4.0" @@ -1798,8 +1792,6 @@ dependencies = [ "percent-encoding", "serde", "serde_json", - "tokio", - "warp", ] [[package]] @@ -1823,7 +1815,6 @@ version = "0.1.1" dependencies = [ "mailpot", "tokio", - "warp", ] [[package]] @@ -1930,16 +1921,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "mime_guess" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "minijinja" version = "0.31.0" @@ -2012,20 +1993,6 @@ dependencies = [ "ws2_32-sys", ] -[[package]] -name = "multiparty" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed1ec6589a6d4a1e0b33b4c0a3f6ee96dfba88ebdb3da51403fd7cf0a24a4b04" -dependencies = [ - "bytes", - "futures-core", - "httparse", - "memchr", - "pin-project-lite", - "try-lock", -] - [[package]] name = "native-tls" version = "0.2.11" @@ -2613,12 +2580,6 @@ dependencies = [ "windows-sys 0.42.0", ] -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "scoped_threadpool" version = "0.1.9" @@ -3080,29 +3041,6 @@ dependencies = [ "syn 2.0.14", ] -[[package]] -name = "tokio-stream" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite", -] - [[package]] name = "tokio-util" version = "0.7.7" @@ -3230,25 +3168,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" -[[package]] -name = "tungstenite" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" -dependencies = [ - "base64 0.13.1", - "byteorder", - "bytes", - "http", - "httparse", - "log", - "rand", - "sha1", - "thiserror", - "url", - "utf-8", -] - [[package]] name = "typenum" version = "1.16.0" @@ -3314,12 +3233,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "uuid" version = "1.3.1" @@ -3378,37 +3291,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "warp" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27e1a710288f0f91a98dd8a74f05b76a10768db245ce183edf64dc1afdc3016c" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "headers", - "http", - "hyper", - "log", - "mime", - "mime_guess", - "multiparty", - "percent-encoding", - "pin-project", - "rustls-pemfile", - "scoped-tls", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-stream", - "tokio-tungstenite", - "tokio-util", - "tower-service", - "tracing", -] - [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" diff --git a/archive-http/Cargo.toml b/archive-http/Cargo.toml index c6c465b..b7ec33e 100644 --- a/archive-http/Cargo.toml +++ b/archive-http/Cargo.toml @@ -14,11 +14,6 @@ default-run = "mpot-archives" [[bin]] name = "mpot-archives" path = "src/main.rs" -required-features = ["warp"] - -[[bin]] -name = "mpot-gen" -path = "src/gen.rs" [dependencies] chrono = { version = "^0.4" } @@ -28,10 +23,3 @@ minijinja = { version = "0.31.0", features = ["source", ] } percent-encoding = { version = "^2.1", optional = true } serde = { version = "^1", features = ["derive", ] } serde_json = "^1" -tokio = { version = "1", features = ["full"], optional = true } -warp = { version = "^0.3", optional = true } - -[features] -default = ["gen"] -gen = [] -warp = ["dep:percent-encoding", "dep:tokio", "dep:warp"] diff --git a/archive-http/src/main.rs b/archive-http/src/main.rs index b50ffcc..b486d83 100644 --- a/archive-http/src/main.rs +++ b/archive-http/src/main.rs @@ -17,26 +17,89 @@ * along with this program. If not, see . */ +use std::{fs::OpenOptions, io::Write}; + use mailpot::*; use mailpot_archives::utils::*; use minijinja::value::Value; -use percent_encoding::percent_decode_str; -use warp::Filter; -#[tokio::main] -async fn main() { - let config_path = std::env::args() - .nth(1) - .expect("Expected configuration file path as first argument."); - let conf = Configuration::from_file(config_path).unwrap(); +fn run_app() -> std::result::Result<(), Box> { + let args = std::env::args().collect::>(); + let Some(config_path) = args.get(1) else { + return Err("Expected configuration file path as first argument.".into()); + }; + let Some(output_path) = args.get(2) else { + return Err("Expected output dir path as second argument.".into()); + }; + let root_url_prefix = args.get(3).cloned().unwrap_or_default(); - let conf1 = conf.clone(); - let list_handler = warp::path!("lists" / i64).map(move |list_pk: i64| { - let db = Connection::open_db(conf1.clone()).unwrap(); - let list = db.list(list_pk).unwrap().unwrap(); - let post_policy = db.list_post_policy(list.pk).unwrap(); - let months = db.months(list.pk).unwrap(); - let posts = db.list_posts(list.pk, None).unwrap(); + let output_path = std::path::Path::new(&output_path); + if output_path.exists() && !output_path.is_dir() { + return Err("Output path is not a directory.".into()); + } + + std::fs::create_dir_all(&output_path.join("lists"))?; + std::fs::create_dir_all(&output_path.join("list"))?; + let conf = Configuration::from_file(config_path) + .map_err(|err| format!("Could not load config {config_path}: {err}"))?; + + let db = Connection::open_db(conf).map_err(|err| format!("Couldn't open db: {err}"))?; + let lists_values = db.lists()?; + { + //index.html + + let lists = lists_values + .iter() + .map(|list| { + let months = db.months(list.pk).unwrap(); + let posts = db.list_posts(list.pk, None).unwrap(); + minijinja::context! { + title => &list.name, + posts => &posts, + months => &months, + body => &list.description.as_deref().unwrap_or_default(), + root_prefix => &root_url_prefix, + list => Value::from_object(MailingList::from(list.clone())), + } + }) + .collect::>(); + let mut file = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(&output_path.join("index.html"))?; + let crumbs = vec![Crumb { + label: "Lists".into(), + url: format!("{root_url_prefix}/").into(), + }]; + + let context = minijinja::context! { + title => "mailing list archive", + description => "", + lists => &lists, + root_prefix => &root_url_prefix, + crumbs => crumbs, + }; + file.write_all( + TEMPLATES + .get_template("lists.html")? + .render(context)? + .as_bytes(), + )?; + } + + let mut lists_path = output_path.to_path_buf(); + + for list in &lists_values { + lists_path.push("lists"); + lists_path.push(list.pk.to_string()); + std::fs::create_dir_all(&lists_path)?; + lists_path.push("index.html"); + + let list = db.list(list.pk)?.unwrap(); + let post_policy = db.list_post_policy(list.pk)?; + let months = db.months(list.pk)?; + let posts = db.list_posts(list.pk, None)?; let mut hist = months .iter() .map(|m| (m.to_string(), [0usize; 31])) @@ -61,26 +124,26 @@ async fn main() { subject_ref = subject_ref[2 + list.id.len()..].trim(); } minijinja::context! { - pk => post.pk, - list => post.list, - subject => subject_ref, - address=> post.address, - message_id => msg_id, - message => post.message, - timestamp => post.timestamp, - datetime => post.datetime, - root_prefix => "", + pk => post.pk, + list => post.list, + subject => subject_ref, + address=> post.address, + message_id => msg_id, + message => post.message, + timestamp => post.timestamp, + datetime => post.datetime, + root_prefix => &root_url_prefix, } }) .collect::>(); let crumbs = vec![ Crumb { label: "Lists".into(), - url: "/".into(), + url: format!("{root_url_prefix}/").into(), }, Crumb { label: list.name.clone().into(), - url: format!("/lists/{}/", list.pk).into(), + url: format!("{root_url_prefix}/lists/{}/", list.pk).into(), }, ]; let context = minijinja::context! { @@ -92,34 +155,36 @@ async fn main() { hists => &hist, posts=> posts_ctx, body=>&list.description.clone().unwrap_or_default(), - root_prefix => "", - list => Value::from_object(MailingList::from(list)), + root_prefix => &root_url_prefix, + list => Value::from_object(MailingList::from(list.clone())), crumbs => crumbs, }; - Ok(warp::reply::html( + let mut file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(&lists_path) + .map_err(|err| format!("could not open {lists_path:?}: {err}"))?; + file.write_all( TEMPLATES - .get_template("list.html") - .unwrap() - .render(context) - .unwrap_or_else(|err| err.to_string()), - )) - }); - let conf2 = conf.clone(); - let post_handler = - warp::path!("list" / i64 / String).map(move |list_pk: i64, message_id: String| { - let message_id = percent_decode_str(&message_id).decode_utf8().unwrap(); - dbg!(&message_id); - let db = Connection::open_db(conf2.clone()).unwrap(); - let list = db.list(list_pk).unwrap().unwrap(); - let posts = db.list_posts(list_pk, None).unwrap(); - let post = posts - .iter() - .find(|p| message_id.contains(p.message_id.as_str().strip_carets())) - .unwrap(); - //let mut msg_id = &post.message_id[1..]; - //msg_id = &msg_id[..msg_id.len().saturating_sub(1)]; + .get_template("list.html")? + .render(context)? + .as_bytes(), + )?; + lists_path.pop(); + lists_path.pop(); + lists_path.pop(); + lists_path.push("list"); + lists_path.push(list.pk.to_string()); + std::fs::create_dir_all(&lists_path)?; + + for post in posts { + let mut msg_id = &post.message_id[1..]; + msg_id = &msg_id[..msg_id.len().saturating_sub(1)]; + lists_path.push(format!("{msg_id}.html")); let envelope = melib::Envelope::from_bytes(post.message.as_slice(), None) - .map_err(|err| format!("Could not parse mail {}: {err}", post.message_id)).unwrap(); + .map_err(|err| format!("Could not parse mail {}: {err}", post.message_id))?; let body = envelope.body_bytes(post.message.as_slice()); let body_text = body.text(); let subject = envelope.subject(); @@ -135,21 +200,22 @@ async fn main() { let crumbs = vec![ Crumb { label: "Lists".into(), - url: "/".into(), + url: format!("{root_url_prefix}/").into(), }, Crumb { label: list.name.clone().into(), - url: format!("/lists/{}/", list.pk).into(), + url: format!("{root_url_prefix}/lists/{}/", list.pk).into(), }, Crumb { label: subject_ref.to_string().into(), - url: format!("/lists/{}/{message_id}.html/", list.pk).into(), + url: format!("{root_url_prefix}/lists/{}/{message_id}.html/", list.pk).into(), }, ]; let context = minijinja::context! { title => &list.name, list => &list, post => &post, + posts => &posts_ctx, body => &body_text, from => &envelope.field_from_to_string(), date => &envelope.date_as_str(), @@ -158,66 +224,34 @@ async fn main() { trimmed_subject => subject_ref, in_reply_to => &envelope.in_reply_to_display().map(|r| r.to_string().as_str().strip_carets().to_string()), references => &envelope .references() .into_iter() .map(|m| m.to_string().as_str().strip_carets().to_string()) .collect::>(), - root_prefix => "", + root_prefix => &root_url_prefix, crumbs => crumbs, }; - Ok(warp::reply::html( - TEMPLATES - .get_template("post.html") - .unwrap() - .render(context) - .unwrap_or_else(|err| err.to_string()), - )) - }); - let conf3 = conf.clone(); - let index_handler = warp::path::end().map(move || { - let db = Connection::open_db(conf3.clone()).unwrap(); - let lists_values = db.lists().unwrap(); - let lists = lists_values - .iter() - .map(|list| { - let months = db.months(list.pk).unwrap(); - let posts = db.list_posts(list.pk, None).unwrap(); - minijinja::context! { - title => &list.name, - posts => &posts, - months => &months, - body => &list.description.as_deref().unwrap_or_default(), - root_prefix => "", - list => Value::from_object(MailingList::from(list.clone())), - } - }) - .collect::>(); - let crumbs = vec![Crumb { - label: "Lists".into(), - url: "/".into(), - }]; - - let context = minijinja::context! { - title => "mailing list archive", - description => "", - lists => &lists, - root_prefix => "", - crumbs => crumbs, - }; - Ok(warp::reply::html( - TEMPLATES - .get_template("lists.html") - .unwrap() - .render(context) - .unwrap_or_else(|err| err.to_string()), - )) - }); - let routes = warp::get() - .and(index_handler) - .or(list_handler) - .or(post_handler); - - // Note that composing filters for many routes may increase compile times - // (because it uses a lot of generics). If you wish to use dynamic dispatch - // instead and speed up compile times while making it slightly slower at - // runtime, you can use Filter::boxed(). - - eprintln!("Running at http://127.0.0.1:3030"); - warp::serve(routes).run(([127, 0, 0, 1], 3030)).await; + let mut file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(&lists_path) + .map_err(|err| format!("could not open {lists_path:?}: {err}"))?; + file.write_all( + TEMPLATES + .get_template("post.html")? + .render(context)? + .as_bytes(), + )?; + lists_path.pop(); + } + lists_path.pop(); + lists_path.pop(); + } + Ok(()) +} + +fn main() -> std::result::Result<(), i64> { + if let Err(err) = run_app() { + eprintln!("{err}"); + return Err(-1); + } + Ok(()) } diff --git a/rest-http/Cargo.toml b/rest-http/Cargo.toml index f95d6e0..9cd7197 100644 --- a/rest-http/Cargo.toml +++ b/rest-http/Cargo.toml @@ -18,4 +18,3 @@ path = "src/main.rs" [dependencies] mailpot = { version = "^0.1", path = "../core" } tokio = { version = "^1", features = ["full"] } -warp = "^0.3" diff --git a/rest-http/README.md b/rest-http/README.md index 63a4750..8fac8eb 100644 --- a/rest-http/README.md +++ b/rest-http/README.md @@ -1,5 +1,3 @@ # mailpot REST http server -```shell -cargo run --bin mpot-http -``` +Not implemented. diff --git a/rest-http/src/main.rs b/rest-http/src/main.rs index 85a1065..17d836f 100644 --- a/rest-http/src/main.rs +++ b/rest-http/src/main.rs @@ -17,73 +17,4 @@ * along with this program. If not, see . */ -use mailpot::*; -use warp::Filter; - -#[tokio::main] -async fn main() { - let config_path = std::env::args() - .nth(1) - .expect("Expected configuration file path as first argument."); - let conf = Configuration::from_file(config_path).unwrap(); - - let conf1 = conf.clone(); - // GET /lists/:i64/policy - let policy = warp::path!("lists" / i64 / "policy").map(move |list_pk| { - let db = Connection::open_db(conf1.clone()).unwrap(); - db.list_post_policy(list_pk) - .ok() - .map(|l| warp::reply::json(&l.unwrap())) - .unwrap() - }); - - let conf2 = conf.clone(); - //get("/lists")] - let lists = warp::path!("lists").map(move || { - let db = Connection::open_db(conf2.clone()).unwrap(); - let lists = db.lists().unwrap(); - warp::reply::json(&lists) - }); - - let conf3 = conf.clone(); - //get("/lists/")] - let lists_num = warp::path!("lists" / i64).map(move |list_pk| { - let db = Connection::open_db(conf3.clone()).unwrap(); - let list = db.list(list_pk).unwrap(); - warp::reply::json(&list) - }); - - let conf4 = conf.clone(); - //get("/lists//subscriptions")] - let lists_subscriptions = warp::path!("lists" / i64 / "subscriptions").map(move |list_pk| { - let db = Connection::open_db(conf4.clone()).unwrap(); - db.list_subscriptions(list_pk) - .ok() - .map(|l| warp::reply::json(&l)) - .unwrap() - }); - - //get("/lists//owners")] - let lists_owners = warp::path!("lists" / i64 / "owners").map(move |list_pk| { - let db = Connection::open_db(conf.clone()).unwrap(); - db.list_owners(list_pk) - .ok() - .map(|l| warp::reply::json(&l)) - .unwrap() - }); - - //post("/lists//owners/add", data = "")] - let lists_owner_add = - warp::post().and(warp::path!("lists" / i64 / "owners" / "add").map(|_list_pk| "todo")); - - let routes = warp::get().and( - lists - .or(policy) - .or(lists_num) - .or(lists_subscriptions) - .or(lists_owners) - .or(lists_owner_add), - ); - - warp::serve(routes).run(([127, 0, 0, 1], 3030)).await; -} +fn main() {}