From 8c55d20ed2a71b83a88cc3aa27c81fbaa7c9dd58 Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Sat, 12 Mar 2022 22:18:49 +0100 Subject: [PATCH] add mailer --- Cargo.lock | 339 +++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + assets/ffplayout.yml | 2 +- src/utils/config.rs | 2 +- src/utils/logging.rs | 66 ++++++++- 5 files changed, 400 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ce8f294a..c676f845 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,6 +34,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + [[package]] name = "bitflags" version = "1.3.2" @@ -46,6 +52,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + [[package]] name = "cfg-if" version = "0.1.10" @@ -101,6 +113,22 @@ dependencies = [ "syn", ] +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + [[package]] name = "crc32fast" version = "1.3.2" @@ -110,6 +138,15 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + [[package]] name = "ffplayout-rs" version = "0.1.0" @@ -118,6 +155,7 @@ dependencies = [ "clap", "ffprobe", "file-rotate", + "lettre", "log", "notify", "rand", @@ -174,6 +212,21 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "fsevent" version = "0.4.0" @@ -209,6 +262,39 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-core", + "futures-io", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "getrandom" version = "0.2.5" @@ -241,6 +327,34 @@ dependencies = [ "libc", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi 0.3.9", +] + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "indexmap" version = "1.8.0" @@ -271,6 +385,15 @@ dependencies = [ "libc", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "iovec" version = "0.1.4" @@ -308,6 +431,26 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +[[package]] +name = "lettre" +version = "0.10.0-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d8da8f34d086b081c9cc3b57d3bb3b51d16fc06b5c848a188e2f14d58ac2a5" +dependencies = [ + "base64", + "fastrand", + "futures-util", + "hostname", + "httpdate", + "idna", + "mime", + "native-tls", + "nom", + "once_cell", + "quoted_printable", + "regex", +] + [[package]] name = "libc" version = "0.2.119" @@ -338,12 +481,36 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + [[package]] name = "memchr" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.4.4" @@ -419,6 +586,24 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "native-tls" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "net2" version = "0.2.37" @@ -430,6 +615,17 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "nom" +version = "7.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" +dependencies = [ + "memchr", + "minimal-lexical", + "version_check", +] + [[package]] name = "notify" version = "4.0.17" @@ -492,6 +688,39 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +[[package]] +name = "openssl" +version = "0.10.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" +dependencies = [ + "bitflags", + "cfg-if 1.0.0", + "foreign-types", + "libc", + "once_cell", + "openssl-sys", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "os_str_bytes" version = "6.0.0" @@ -536,6 +765,18 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" + [[package]] name = "ppv-lite86" version = "0.2.16" @@ -584,6 +825,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "quoted_printable" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fee2dce59f7a43418e3382c766554c614e06a552d53a8f07ef499ea4b332c0f" + [[package]] name = "rand" version = "0.8.5" @@ -640,6 +887,15 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "ryu" version = "1.0.9" @@ -655,12 +911,45 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +dependencies = [ + "lazy_static", + "winapi 0.3.9", +] + [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "security-framework" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" version = "1.0.136" @@ -764,6 +1053,20 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if 1.0.0", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi 0.3.9", +] + [[package]] name = "termcolor" version = "1.1.3" @@ -789,6 +1092,21 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "tinyvec" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + [[package]] name = "tokio" version = "1.17.0" @@ -820,12 +1138,33 @@ dependencies = [ "syn", ] +[[package]] +name = "unicode-bidi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index 9e875515..265616d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ chrono = "0.4" clap = { version = "3.1.6", features = ["derive"] } ffprobe = "0.3" file-rotate = "0.6.0" +lettre = "0.10.0-rc.4" log = "0.4.14" notify = "4.0.17" rand = "0.8.5" diff --git a/assets/ffplayout.yml b/assets/ffplayout.yml index 2f0cf4ce..72f13ea9 100644 --- a/assets/ffplayout.yml +++ b/assets/ffplayout.yml @@ -13,7 +13,7 @@ mail: 'mail_level' can be WARNING or ERROR. subject: "Playout Error" smtp_server: "mail.example.org" - smtp_port: 587 + starttls: true sender_addr: "ffplayout@example.org" sender_pass: "abc123" recipient: diff --git a/src/utils/config.rs b/src/utils/config.rs index d49ba7e8..983bf5d9 100644 --- a/src/utils/config.rs +++ b/src/utils/config.rs @@ -27,7 +27,7 @@ pub struct General { pub struct Mail { pub subject: String, pub smtp_server: String, - pub smtp_port: u32, + pub starttls: bool, pub sender_addr: String, pub sender_pass: String, pub recipient: String, diff --git a/src/utils/logging.rs b/src/utils/logging.rs index 5b0efb63..194d02ce 100644 --- a/src/utils/logging.rs +++ b/src/utils/logging.rs @@ -1,24 +1,33 @@ extern crate log; extern crate simplelog; +use regex::Regex; use std::path::Path; use file_rotate::{compression::Compression, suffix::AppendCount, ContentLimit, FileRotate}; use log::{Level, LevelFilter, Log, Metadata, Record}; use simplelog::*; +use lettre::{transport::smtp::authentication::Credentials, Message, SmtpTransport, Transport}; + use crate::utils; pub struct LogMailer { level: LevelFilter, config: Config, + playout_config: utils::Config, } impl LogMailer { - pub fn new(log_level: LevelFilter, config: Config) -> Box { + pub fn new( + log_level: LevelFilter, + config: Config, + playout_config: &utils::Config, + ) -> Box { Box::new(LogMailer { level: log_level, config, + playout_config: playout_config.clone(), }) } } @@ -31,12 +40,8 @@ impl Log for LogMailer { fn log(&self, record: &Record<'_>) { if self.enabled(record.metadata()) { match record.level() { - Level::Error => { - // println!("Send Error Mail: {:?}\n{:?}", record, self.config) - } - Level::Warn => { - // println!("Send Warn Mail: {:?}", record.args()) - } + Level::Error => send_mail(record.args().to_string(), &self.playout_config), + Level::Warn => send_mail(record.args().to_string(), &self.playout_config), _ => (), } } @@ -59,6 +64,45 @@ impl SharedLogger for LogMailer { } } +fn clean_string(text: String) -> String { + let regex: Regex = Regex::new( + r"\x1b\[[0-9;]*[mGKF]" + ).unwrap(); + + regex.replace_all(text.as_str(), "").to_string() +} + +fn send_mail(msg: String, config: &utils::Config) { + let email = Message::builder() + .from(config.mail.sender_addr.parse().unwrap()) + .to(config.mail.recipient.parse().unwrap()) + .subject(config.mail.subject.clone()) + .body(clean_string(msg.clone())) + .unwrap(); + + let credentials = Credentials::new( + config.mail.sender_addr.clone(), + config.mail.sender_pass.clone(), + ); + + let mut transporter = SmtpTransport::relay(config.mail.smtp_server.clone().as_str()); + + if config.mail.starttls { + transporter = SmtpTransport::starttls_relay(config.mail.smtp_server.clone().as_str()) + } + + let mailer = transporter + .unwrap() + .credentials(credentials) + .build(); + + // Send the email + match mailer.send(&email) { + Ok(_) => (), + Err(e) => info!("Could not send email: {:?}", e), + } +} + pub fn init_logging(config: &utils::Config) -> Vec> { let app_config = config.logging.clone(); let mut app_logger: Vec> = vec![]; @@ -117,12 +161,18 @@ pub fn init_logging(config: &utils::Config) -> Vec> { } if config.mail.recipient.len() > 3 { + let mut filter = LevelFilter::Error; + let mail_config = log_config .clone() .set_time_format_str("[%Y-%m-%d %H:%M:%S%.3f]") .build(); - app_logger.push(LogMailer::new(LevelFilter::Warn, mail_config)); + if config.mail.mail_level.to_lowercase() == "warning".to_string() { + filter = LevelFilter::Warn + } + + app_logger.push(LogMailer::new(filter, mail_config, config)); } app_logger