use crate::config::Config; use anyhow::Context; use rand::{rngs::StdRng, SeedableRng}; use sqlx::MySqlPool; use std::sync::Arc; use structopt::StructOpt; use tera::Tera; use tokio::sync::Mutex; use warp::Filter; mod config; mod handlers; mod util; #[derive(StructOpt)] struct Opt { #[structopt(index = 1, help = "config file to use")] config: String, } #[tokio::main] async fn main() -> anyhow::Result<()> { env_logger::init(); let opt = Opt::from_args(); let config = load_config(&opt.config) .await .context("error loading config")?; let pool = MySqlPool::connect(&config.database_url) .await .context("error creating mysql pool")?; let mut tera = Tera::default(); tera.add_raw_templates(vec![ ("index.html", include_str!("../assets/index.html.tera")), ("success.html", include_str!("../assets/success.html.tera")), ("404.html", include_str!("../assets/404.html.tera")), ]) .context("error adding templates to tera")?; let brevo = Arc::new(Brevo { config, pool, tera, rng: Mutex::new(StdRng::from_rng(rand::thread_rng())?), }); let brevo_idx = Arc::clone(&brevo); let brevo_submit = Arc::clone(&brevo); let brevo_srv = Arc::clone(&brevo); let brevo_reject = Arc::clone(&brevo); let routes = warp::get() .and( warp::path::end() .and_then(move || handlers::index(Arc::clone(&brevo_idx))) .or(warp::path::param::() .and(warp::path::end()) .and_then(move |id| handlers::shortened(id, Arc::clone(&brevo)))), ) .or(warp::post() .and(warp::body::content_length_limit(1024 * 16)) .and(warp::body::form()) .and_then(move |form_data| handlers::submit(form_data, Arc::clone(&brevo_submit)))) .recover(move |err| handlers::handle_reject(Arc::clone(&brevo_reject), err)); warp::serve(routes).run(brevo_srv.config.bind_addr).await; Ok(()) } async fn load_config(path: &str) -> anyhow::Result { let data = tokio::fs::read(path).await?; Ok(toml::from_slice::(&data)?) } pub struct Brevo { pub config: Config, pub pool: MySqlPool, pub tera: Tera, pub rng: Mutex, }