use anyhow::Result; use clap::Parser; use diesel::{ prelude::*, r2d2::{ConnectionManager, Pool, PooledConnection}, }; use lettre::{Message, SmtpTransport, Transport}; use std::{env, thread::park_timeout}; use time::{Duration, OffsetDateTime}; use tracing::{debug, info, trace}; mod args; mod config; mod models; mod schema; use args::Args; use config::Config; use models::{NewReminder, Reminder}; fn remind( db: &mut PooledConnection>, mailer: &SmtpTransport, ) -> Result<()> { info!("checking for reminders"); for reminder in schema::reminders::dsl::reminders .filter(schema::reminders::executed.is_null()) .order(schema::reminders::planned.asc()) .load::(db)? { trace!(?reminder, "checking reminder"); if reminder.planned <= OffsetDateTime::now_utc() { let email = Message::builder() .from("whakarite@localhost".parse()?) .to(reminder.receiver.parse()?) .subject(&reminder.title) .body(reminder.message.to_string())?; mailer.send(&email)?; diesel::update(&reminder) .set(schema::reminders::executed.eq(Some(OffsetDateTime::now_utc()))) .execute(db)?; debug!("email sent to {}", reminder.receiver); } else { let duration = reminder.planned - OffsetDateTime::now_utc(); info!(?duration, "parking reminder"); park_timeout(::try_from(duration)?); } // Check for another remind job if none dont loop forever } Ok(()) } fn main() -> Result<()> { let args = Args::parse(); if env::var("RUST_LOG").is_err() { env::set_var("RUST_LOG", format!("{}", args.log_level)); } tracing_subscriber::fmt::init(); info!( "{} {} started", env!("CARGO_BIN_NAME"), env!("CARGO_PKG_VERSION") ); let config_path = "./config.toml"; let config: Config = toml::from_str(&std::fs::read_to_string(config_path)?)?; trace!(?config, config_path, "loaded config"); let db_pool = Pool::builder().build(ConnectionManager::::new(format!( "postgresql://{}:{}@{}:{}/{}", config.database.user, config.database.pass, config.database.host, config.database.port, config.database.name )))?; let test_reminder = NewReminder { created: OffsetDateTime::now_utc(), planned: (OffsetDateTime::now_utc() + Duration::MINUTE), title: "Test title", message: "Test message", receiver: "finga@localhost", }; diesel::insert_into(schema::reminders::table) .values(&test_reminder) .execute(&mut db_pool.get()?)?; let mailer = SmtpTransport::unencrypted_localhost(); loop { remind(&mut db_pool.get()?, &mailer)?; } }