mod captcha_solutions; mod config; mod errors; mod forms; mod logging; mod mailer; mod routes; mod states; mod templates; use anyhow::{Context, Result}; use axum::{ http::StatusCode, routing::{get, get_service, Router}, Server, }; use std::{future::ready, net::SocketAddr, process}; use tower_http::services::ServeDir; use tracing::info; use crate::states::AppState; async fn init() -> Result<()> { let app_state = AppState::build()?; let path_prefix = app_state.config.path_prefix.clone(); let socket_address = app_state .config .socket_address .parse::() .context("Failed to parse the socket address: {e:?}")?; logging::init_logger( &app_state.config.log_file, app_state.config.utc_offset.hours, app_state.config.utc_offset.minutes, )?; let static_service = get_service(ServeDir::new("static")).handle_error(|_| ready(StatusCode::NOT_FOUND)); let routes = Router::new() .route("/", get(routes::index).post(routes::submit)) .with_state(app_state) .nest_service("/static", static_service); let app = Router::new().nest(&path_prefix, routes); info!("Starting server"); Server::bind(&socket_address) .serve(app.into_make_service()) .await?; Ok(()) } /// Single thread. #[tokio::main(flavor = "current_thread")] async fn main() { if let Err(e) = init().await { eprintln!("{e:?}"); process::exit(1); }; }