From 738da0aac63f9300240203f00588a3fe008aa3e8 Mon Sep 17 00:00:00 2001 From: Ethan Girouard Date: Tue, 14 Jul 2026 20:13:07 -0400 Subject: [PATCH] Create axum router directly Bind to configured host/port Warn if configured host/port differs from dx-specified host/port Make main async --- src/main.rs | 5 ++-- src/server/main.rs | 57 +++++++++++++++++++++++++++++++--------------- 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/main.rs b/src/main.rs index e9dd853..a5c942c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,10 +28,11 @@ fn main() { } #[cfg(feature = "server")] -fn main() -> std::process::ExitCode { +#[tokio::main] +async fn main() -> std::process::ExitCode { tracing_setup(); - let Err(e) = server::main(); + let Err(e) = server::main().await; tracing::error!("Server main failed:\n{e}"); std::process::ExitCode::FAILURE diff --git a/src/server/main.rs b/src/server/main.rs index 10756ba..c7dd949 100644 --- a/src/server/main.rs +++ b/src/server/main.rs @@ -1,20 +1,21 @@ use dioxus::{ - fullstack::axum::{Router, middleware::from_fn}, + cli_config, + fullstack::axum::{self, Router, middleware::from_fn}, + prelude::{DioxusRouterExt, ServeConfig}, server::axum::Extension, }; +use tokio::net::TcpListener; use tower_http::services::ServeFile; use crate::App; use crate::app::LOGO_ICO; use crate::server::{ - auth::build_auth_layer, - config::{self, Config}, - database, key_val_store, + auth::build_auth_layer, config, database, key_val_store, require_auth_mw::require_auth_middleware, }; -use crate::util::error::{Contextualize, Error, Result}; +use crate::util::error::{Contextualize, Error, ErrorType, Result}; -pub fn main() -> Result { +pub async fn main() -> Result { if let Err(e) = dotenvy::dotenv() { tracing::warn!("Error reading .env: {e}"); } @@ -32,15 +33,6 @@ pub fn main() -> Result { std::env::set_var("DIOXUS_PUBLIC_PATH", config.server.public_path.clone()); } - // `Ok(...?)` is because `dioxus::serve` expects an `anyhow::Result` - dioxus::serve(move || { - let config = config.clone(); - async move { Ok(router_setup(config).await?) } - }); -} - -/// Set up the axum Router -async fn router_setup(config: Config) -> Result { let db_pool = database::setup(config.database.connection_uri()) .await .err_context("Failed database setup")?; @@ -65,13 +57,42 @@ async fn router_setup(config: Config) -> Result { let auth_layer = build_auth_layer(db_pool.clone(), key_val_pool, config.auth.cookies_secure); - let router = dioxus::server::router(App) + #[cfg(debug_assertions)] + if let Some(dx_port) = cli_config::server_port() + && dx_port != config.server.port + { + tracing::warn!( + "Your configured server port ({}) doesn't match the one specified from environment \ + variables set by the Dioxus CLI ({dx_port}). If you are intending to use the dx tool, \ + please do not specify a port in the configuration.", + config.server.port + ); + } + + let addr = config.server.serve_addr(); + + tracing::info!("Setup complete, building router..."); + + let router = Router::new() + .serve_dioxus_application(ServeConfig::new(), App) .layer(from_fn(require_auth_middleware)) .layer(Extension(config)) .layer(Extension(db_pool)) .layer(auth_layer) .nest_service("/favicon.ico", ServeFile::new(favicon_path)); - tracing::info!("Setup complete, returning Router..."); - Ok(router) + tracing::info!("Listening on {addr}..."); + let listener = TcpListener::bind(addr) + .await + .map_err(|e| ErrorType::HttpServer(e.to_string())) + .err_context(format!("Failed to bind to {addr}"))?; + + axum::serve(listener, router) + .await + .map_err(|e| ErrorType::HttpServer(e.to_string())) + .err_context("HTTP server error")?; + + Err(Error::new_here(ErrorType::HttpServer( + "axum::serve should never return".to_owned(), + ))) }