From 6de17253d83e2067d00ba1ced6e67aa682dd5dea Mon Sep 17 00:00:00 2001 From: Christopher Moyer Date: Sun, 19 May 2024 21:55:21 -0400 Subject: [PATCH 1/3] add feature to process multiple mailboxes --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/main.rs | 41 ++++++++++++++++++++++++++++++++--------- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 428e0b5..771f8af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -187,7 +187,7 @@ dependencies = [ [[package]] name = "email2matrix-message-service" -version = "1.0.0" +version = "1.1.0" dependencies = [ "confy", "imap", diff --git a/Cargo.toml b/Cargo.toml index 783321a..023a9c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "email2matrix-message-service" -version = "1.0.0" +version = "1.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/main.rs b/src/main.rs index d2116d7..cf22180 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,21 @@ fn main() { let args: Vec = env::args().collect(); let cfg: AppConfig = confy::load_path(Path::new(&args[1])).expect("Couldn't read config"); - let mut imap_session = get_imap_session(&cfg); + for mailbox in cfg.mailboxes.values() { + process_mailbox(&cfg.imap.ip, &mailbox); + } +} + +fn process_mailbox(imap_ip: &str, mailbox: &Mailbox) { + let mut imap_session = match get_imap_session(imap_ip, mailbox) { + Ok(x) => x, + Err(_) => { + println!("Unable to start session for {}", mailbox.user); + return; + } + }; + + imap_session.select("INBOX").unwrap(); let message = get_emails(&mut imap_session); @@ -19,7 +33,7 @@ fn main() { Some(x) => { let mut messages_sent_successfully = Vec::new(); for email in x { - let response = post_to_hookshot(&cfg.hookshot_url, &email.1); + let response = post_to_hookshot(&mailbox.hookshot_url, &email.1); match response { Ok(x) => { if x.status().is_success() { @@ -38,11 +52,10 @@ fn main() { imap_session.logout().unwrap(); } -fn get_imap_session(config: &AppConfig) -> imap::Session { - let stream = TcpStream::connect(&config.imap_ip).unwrap(); +fn get_imap_session(imap_ip: &str, mailbox: &Mailbox) -> Result, (imap::Error, imap::Client)> { + let stream = TcpStream::connect(imap_ip).unwrap(); let client = imap::Client::new(stream); - let mut imap_session = client.login(&config.imap_user, &config.imap_password).expect("Couldn't login"); - imap_session.select("INBOX").unwrap(); + let mut imap_session = client.login(&mailbox.user, &mailbox.password); return imap_session; } @@ -119,9 +132,19 @@ fn post_to_hookshot(hookshot_url: &str, email: &Email) -> reqwest::Result, +} + +#[derive(Debug, Serialize, Deserialize)] +struct Imap { + ip: String +} + +#[derive(Debug, Serialize, Deserialize)] +struct Mailbox { + user: String, + password: String, hookshot_url: String } -- 2.45.2 From 052523073137c834bf4dfa37787e45fca8b65b21 Mon Sep 17 00:00:00 2001 From: Christopher Moyer Date: Sun, 19 May 2024 22:21:44 -0400 Subject: [PATCH 2/3] add logging with log4rs --- Cargo.lock | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 2 + log4rs.yaml | 33 +++++++ src/main.rs | 12 ++- 4 files changed, 307 insertions(+), 9 deletions(-) create mode 100644 log4rs.yaml diff --git a/Cargo.lock b/Cargo.lock index 771f8af..34e737b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,6 +41,18 @@ dependencies = [ "libc", ] +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "arrayvec" version = "0.5.2" @@ -164,6 +176,23 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "destructure_traitobject" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7" + [[package]] name = "directories" version = "5.0.1" @@ -191,6 +220,8 @@ version = "1.1.0" dependencies = [ "confy", "imap", + "log", + "log4rs", "reqwest", "serde", "serde_json", @@ -395,6 +426,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "1.3.1" @@ -581,11 +618,58 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +dependencies = [ + "serde", +] + +[[package]] +name = "log-mdc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7" + +[[package]] +name = "log4rs" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0816135ae15bd0391cf284eab37e6e3ee0a6ee63d2ceeb659862bd8d0a984ca6" +dependencies = [ + "anyhow", + "arc-swap", + "chrono", + "derivative", + "fnv", + "humantime", + "libc", + "log", + "log-mdc", + "once_cell", + "parking_lot", + "rand", + "serde", + "serde-value", + "serde_json", + "serde_yaml", + "thiserror", + "thread-id", + "typemap-ors", + "winapi", +] [[package]] name = "memchr" @@ -705,7 +789,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.63", ] [[package]] @@ -732,6 +816,38 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "parking_lot" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.5", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -755,7 +871,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.63", ] [[package]] @@ -776,6 +892,12 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro2" version = "1.0.82" @@ -794,6 +916,45 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +dependencies = [ + "bitflags 2.5.0", +] + [[package]] name = "redox_users" version = "0.4.5" @@ -927,6 +1088,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "security-framework" version = "2.11.0" @@ -959,6 +1126,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.202" @@ -967,7 +1144,7 @@ checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.63", ] [[package]] @@ -1002,6 +1179,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "slab" version = "0.4.9" @@ -1033,6 +1223,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.63" @@ -1100,7 +1301,17 @@ checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.63", +] + +[[package]] +name = "thread-id" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0ec81c46e9eb50deaa257be2f148adf052d1fb7701cfd55ccfab2525280b70b" +dependencies = [ + "libc", + "winapi", ] [[package]] @@ -1245,6 +1456,15 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typemap-ors" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68c24b707f02dd18f1e4ccceb9d49f2058c2fb86384ef9972592904d7a28867" +dependencies = [ + "unsafe-any-ors", +] + [[package]] name = "unicode-bidi" version = "0.3.15" @@ -1266,6 +1486,21 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unsafe-any-ors" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a303d30665362d9680d7d91d78b23f5f899504d4f08b3c4cf08d055d87c0ad" +dependencies = [ + "destructure_traitobject", +] + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "url" version = "2.5.0" @@ -1325,7 +1560,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.63", "wasm-bindgen-shared", ] @@ -1359,7 +1594,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.63", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1380,6 +1615,28 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-core" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index 023a9c4..04086d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,3 +11,5 @@ imap = "2.4.1" serde = { version = "1.0.201", features = ["derive"] } serde_json = "1.0.117" reqwest = { version = "0.12.4", features = ["json", "blocking"] } +log = "0.4.21" +log4rs = "1.3.0" diff --git a/log4rs.yaml b/log4rs.yaml new file mode 100644 index 0000000..ffdc372 --- /dev/null +++ b/log4rs.yaml @@ -0,0 +1,33 @@ +# Scan this file for changes every 30 seconds +refresh_rate: 30 seconds + +appenders: + # An appender named "stdout" that writes to stdout + stdout: + kind: console + + # An appender named "requests" that writes to a file with a custom pattern encoder + requests: + kind: file + path: "log/requests.log" + encoder: + pattern: "{d} - {m}{n}" + +# Set the default logging level to "warn" and attach the "stdout" appender to the root +root: + level: info + appenders: + - stdout + +loggers: + # Raise the maximum log level for events sent to the "app::backend::db" logger to "info" + app::backend::db: + level: info + + # Route log events sent to the "app::requests" logger to the "requests" appender, + # and *not* the normal appenders installed at the root + app::requests: + level: info + appenders: + - requests + additive: false \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index cf22180..0c67e51 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use std::fmt::Display; use std::net::TcpStream; use std::path::Path; +use log::{debug, info}; use reqwest::blocking::Response; use serde::{Deserialize, Serialize}; @@ -10,6 +11,10 @@ use serde::{Deserialize, Serialize}; fn main() { let args: Vec = env::args().collect(); let cfg: AppConfig = confy::load_path(Path::new(&args[1])).expect("Couldn't read config"); + match Path::new("log4rs.yaml").exists() { + true => log4rs::init_file("log4rs.yaml", Default::default()).unwrap(), + false => println!("No log4rs.yaml file found. Logging will not be enabled") + } for mailbox in cfg.mailboxes.values() { process_mailbox(&cfg.imap.ip, &mailbox); @@ -19,8 +24,9 @@ fn main() { fn process_mailbox(imap_ip: &str, mailbox: &Mailbox) { let mut imap_session = match get_imap_session(imap_ip, mailbox) { Ok(x) => x, - Err(_) => { - println!("Unable to start session for {}", mailbox.user); + Err(error) => { + info!("Unable to start session for {}", mailbox.user); + debug!("{}", error.0); return; } }; @@ -46,7 +52,7 @@ fn process_mailbox(imap_ip: &str, mailbox: &Mailbox) { delete_emails(messages_sent_successfully, &mut imap_session); }, - None => println!("No emails") + None => info!("No emails for {}", mailbox.user) } imap_session.logout().unwrap(); -- 2.45.2 From d1c3083a8f07054ba5920da3879309013e9a7658 Mon Sep 17 00:00:00 2001 From: Christopher Moyer Date: Sun, 19 May 2024 22:49:50 -0400 Subject: [PATCH 3/3] add better error handling --- log4rs.yaml | 2 +- src/main.rs | 21 ++++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/log4rs.yaml b/log4rs.yaml index ffdc372..1e80189 100644 --- a/log4rs.yaml +++ b/log4rs.yaml @@ -15,7 +15,7 @@ appenders: # Set the default logging level to "warn" and attach the "stdout" appender to the root root: - level: info + level: debug appenders: - stdout diff --git a/src/main.rs b/src/main.rs index 0c67e51..8d12e6a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use std::fmt::Display; use std::net::TcpStream; use std::path::Path; -use log::{debug, info}; +use log::{debug, error, info, warn}; use reqwest::blocking::Response; use serde::{Deserialize, Serialize}; @@ -31,7 +31,13 @@ fn process_mailbox(imap_ip: &str, mailbox: &Mailbox) { } }; - imap_session.select("INBOX").unwrap(); + match imap_session.select("INBOX") { + Err(error) => { + error!("Unable to select INBOX: {}", error); + return; + } + _ => {} + } let message = get_emails(&mut imap_session); @@ -105,11 +111,16 @@ fn get_emails(imap_session: &mut imap::Session) -> Option, imap_session: &mut imap::Session) { for ordinal in ordinals { - imap_session.store(format!("{}", ordinal), "+FLAGS (\\Deleted)") - .expect("Couldn't delete message"); + match imap_session.store(format!("{}", ordinal), "+FLAGS (\\Deleted)") { + Err(error) => warn!("Failed to delete message {ordinal}: {error}"), + _ => {} + } } - imap_session.expunge().unwrap(); + match imap_session.expunge() { + Err(error) => warn!("Failed to expunge session: {error}"), + _ => {} + } } fn post_to_hookshot(hookshot_url: &str, email: &Email) -> reqwest::Result { -- 2.45.2