mod captcha_solutions; mod config; mod errors; mod forms; mod logging; mod mailer; mod routes; mod states; mod templates; use anyhow::Result; use axum::routing::get; use axum::{Router, Server}; use axum_extra::routing::SpaRouter; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::process; use std::sync::Arc; use tracing::info; async fn init() -> Result<()> { let mut config = config::Config::new()?; let path_prefix = config.path_prefix.clone(); let mailer = Arc::new(mailer::Mailer::new(&mut config)?); let address = config.socket_address.address; let socket_address = SocketAddr::new( IpAddr::V4(Ipv4Addr::new( address[0], address[1], address[2], address[3], )), config.socket_address.port, ); let _tracing_gurad = logging::init_logger(&config.logging); let config = Arc::new(config); let captcha_solutions = Arc::new(captcha_solutions::SharedCaptchaSolutions::default()); let app_state = states::AppState { config, mailer, captcha_solutions, }; let routes = Router::new() .route("/", get(routes::index).post(routes::submit)) .with_state(app_state); let spa = SpaRouter::new(&format!("{}/static", &path_prefix), "static"); let app = Router::new().nest(&path_prefix, routes).merge(spa); info!("Starting server"); Server::bind(&socket_address) .serve(app.into_make_service()) .await .unwrap(); Ok(()) } /// Single thread #[tokio::main(flavor = "current_thread")] async fn main() { if let Err(e) = init().await { eprintln!("{e:?}"); process::exit(1); }; }