diff --git a/Cargo.lock b/Cargo.lock index 3d5a442..2431f45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3685,12 +3685,21 @@ checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ "bitflags 2.6.0", "bytes", + "futures-util", "http 1.2.0", "http-body 1.0.1", "http-body-util", + "http-range-header", + "httpdate", + "mime", + "mime_guess", + "percent-encoding", "pin-project-lite", + "tokio", + "tokio-util", "tower-layer", "tower-service", + "tracing", ] [[package]] diff --git a/crates/site-app/src/components/header.rs b/crates/site-app/src/components/header.rs index 41c60b1..60e64cb 100644 --- a/crates/site-app/src/components/header.rs +++ b/crates/site-app/src/components/header.rs @@ -9,7 +9,7 @@ pub fn Header() -> impl IntoView { flex-row items-center rounded-b-xl border border-t-0 \ border-base-7 dark:border-basedark-7"; - let auth_status = use_context::(); + let auth_status = use_context::().and_then(|as_| as_.0); let auth_status_text = format!("Status: {:?}", auth_status); view! { @@ -21,7 +21,7 @@ pub fn Header() -> impl IntoView {
- { auth_status_text } +

{ auth_status_text }

diff --git a/crates/site-server/Cargo.toml b/crates/site-server/Cargo.toml index 2118b72..265eb37 100644 --- a/crates/site-server/Cargo.toml +++ b/crates/site-server/Cargo.toml @@ -19,7 +19,7 @@ leptos_router.workspace = true axum.workspace = true tokio.workspace = true tower.workspace = true -tower-http.workspace = true +tower-http = { workspace = true, features = [ "fs" ] } tower-sessions.workspace = true tracing.workspace = true diff --git a/crates/site-server/src/file_and_error_handler.rs b/crates/site-server/src/file_and_error_handler.rs new file mode 100644 index 0000000..73f3f5a --- /dev/null +++ b/crates/site-server/src/file_and_error_handler.rs @@ -0,0 +1,62 @@ +use axum::{ + body::Body, + extract::{FromRef, Request, State}, + http::{HeaderMap, HeaderValue, StatusCode, Uri}, + response::{IntoResponse, Response}, +}; +use leptos::config::LeptosOptions; +use tower::ServiceExt; + +use crate::{app_state::AppState, leptos_routes_handler, AuthSession}; + +pub async fn fallback_handler( + uri: Uri, + auth_session: AuthSession, + State(state): State, + req: Request, +) -> Response { + let options = LeptosOptions::from_ref(&state); + let app_state = AppState::from_ref(&state); + let res = get_static_file(uri, &options.site_root, req.headers()); + let res = res.await.unwrap(); + + if res.status() == StatusCode::OK { + res.into_response() + } else { + let mut res = + leptos_routes_handler(auth_session, State(app_state), req).await; + *res.status_mut() = StatusCode::NOT_FOUND; + res + } +} + +async fn get_static_file( + uri: Uri, + root: &str, + headers: &HeaderMap, +) -> Result, (StatusCode, String)> { + use axum::http::header::ACCEPT_ENCODING; + + let req = Request::builder().uri(uri); + + let req = match headers.get(ACCEPT_ENCODING) { + Some(value) => req.header(ACCEPT_ENCODING, value), + None => req, + }; + + let req = req.body(Body::empty()).unwrap(); + // `ServeDir` implements `tower::Service` so we can call it with + // `tower::ServiceExt::oneshot` This path is relative to the cargo root + match tower_http::services::ServeDir::new(root) + .precompressed_gzip() + .precompressed_br() + .oneshot(req) + .await + { + Ok(res) => Ok(res.into_response()), + Err(err) => Err(( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Something went wrong: {err}"), + )), + } +} diff --git a/crates/site-server/src/main.rs b/crates/site-server/src/main.rs index 3893b0a..20b686e 100644 --- a/crates/site-server/src/main.rs +++ b/crates/site-server/src/main.rs @@ -1,4 +1,5 @@ mod app_state; +mod file_and_error_handler; use std::sync::Arc; @@ -7,7 +8,6 @@ use axum::{ body::Body, extract::{Request, State}, response::IntoResponse, - routing::get, Router, }; use axum_login::AuthManagerLayerBuilder; @@ -82,7 +82,7 @@ async fn main() { let app = Router::new() .leptos_routes_with_handler(routes, leptos_routes_handler) - .fallback(leptos_axum::file_and_error_handler::(shell)) + .fallback(self::file_and_error_handler::fallback_handler) .with_state(app_state) .layer(auth_layer); @@ -94,91 +94,3 @@ async fn main() { .await .unwrap(); } - -mod file_and_error_handler { - use std::{future::Future, pin::Pin}; - - use axum::{ - body::Body, - extract::{FromRef, Request, State}, - http::Uri, - }; - use leptos::{config::LeptosOptions, IntoView}; - - pub fn file_and_error_handler( - shell: fn(LeptosOptions) -> IV, - ) -> impl Fn( - Uri, - State, - Request, - ) -> Pin> + Send + 'static>> - + Clone - + Send - + 'static - where - IV: IntoView + 'static, - S: Send + 'static, - LeptosOptions: FromRef, - { - move |uri: Uri, State(options): State, req: Request| { - Box::pin(async move { - let options = LeptosOptions::from_ref(&options); - let res = get_static_file(uri, &options.site_root, req.headers()); - let res = res.await.unwrap(); - - if res.status() == StatusCode::OK { - res.into_response() - } else { - let mut res = handle_response_inner( - || {}, - move || shell(options), - req, - |app, chunks| { - Box::pin(async move { - let app = - app.to_html_stream_in_order().collect::().await; - let chunks = chunks(); - Box::pin(once(async move { app }).chain(chunks)) - as PinnedStream - }) - }, - ) - .await; - *res.status_mut() = StatusCode::NOT_FOUND; - res - } - }) - } - } - - async fn get_static_file( - uri: Uri, - root: &str, - headers: &HeaderMap, - ) -> Result, (StatusCode, String)> { - use axum::http::header::ACCEPT_ENCODING; - - let req = Request::builder().uri(uri); - - let req = match headers.get(ACCEPT_ENCODING) { - Some(value) => req.header(ACCEPT_ENCODING, value), - None => req, - }; - - let req = req.body(Body::empty()).unwrap(); - // `ServeDir` implements `tower::Service` so we can call it with - // `tower::ServiceExt::oneshot` This path is relative to the cargo root - match tower_http::services::ServeDir::new(root) - .precompressed_gzip() - .precompressed_br() - .oneshot(req) - .await - { - Ok(res) => Ok(res.into_response()), - Err(err) => Err(( - axum::http::StatusCode::INTERNAL_SERVER_ERROR, - format!("Something went wrong: {err}"), - )), - } - } -}