mod user; use std::sync::Arc; use axum::Router; use tokio::net::TcpListener; use webauthn_rs::prelude::*; use crate::{ db::DbPool, models::{AppError, Environment}, }; #[derive(Clone)] pub struct AppState { pool: DbPool, env: Environment, webauthn: Arc, } impl AppState { pub fn new(pool: DbPool, env: Environment) -> Self { let rp_id = env.rp_id(); let rp_origin = env .domain() .parse::() .expect("RP_ORIGIN must be in a valid domain name format"); let webauthn = Arc::new( WebauthnBuilder::new(rp_id, &rp_origin) .map(|builder| builder.allow_any_port(true)) .and_then(WebauthnBuilder::build) .inspect_err(|err| eprintln!("{err}")) .expect("Unable to build authenticator"), ); Self { pool, env, webauthn, } } pub fn pool(&self) -> &DbPool { &self.pool } pub fn env(&self) -> &Environment { &self.env } pub fn webauthn(&self) -> Arc { Arc::clone(&self.webauthn) } } pub async fn start_app(pool: DbPool, env: Environment) -> Result<(), AppError> { let address = env.hostname(); let port = env.port(); let listener = TcpListener::bind(format!("{address}:{port}")) .await .unwrap(); let app_state = AppState::new(pool, env); let app = Router::new().merge(user::requests(app_state.clone())); axum::serve(listener, app) .await .inspect(|_| println!("Application started successfully.")) .map_err(AppError::app_startup)?; Ok(()) }