mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-27 16:54:41 -05:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55ea00afdd |
@@ -259,20 +259,22 @@ where
|
||||
let options = options.clone();
|
||||
let app_fn = app_fn.clone();
|
||||
let res_options = ResponseOptions::default();
|
||||
let status = RouterStatusContext::default();
|
||||
|
||||
async move {
|
||||
let app = {
|
||||
let app_fn = app_fn.clone();
|
||||
let res_options = res_options.clone();
|
||||
let status = status.clone();
|
||||
move |cx| {
|
||||
provide_contexts(cx, &req, res_options);
|
||||
provide_contexts(cx, &req, res_options, status);
|
||||
(app_fn)(cx).into_view(cx)
|
||||
}
|
||||
};
|
||||
|
||||
let (head, tail) = html_parts(&options);
|
||||
|
||||
stream_app(app, head, tail, res_options).await
|
||||
stream_app(app, head, tail, res_options, status).await
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -336,6 +338,7 @@ where
|
||||
let app_fn = app_fn.clone();
|
||||
let data_fn = data_fn.clone();
|
||||
let res_options = ResponseOptions::default();
|
||||
let status = RouterStatusContext::default();
|
||||
|
||||
async move {
|
||||
let data = match data_fn(req.clone()).await {
|
||||
@@ -347,24 +350,31 @@ where
|
||||
let app = {
|
||||
let app_fn = app_fn.clone();
|
||||
let res_options = res_options.clone();
|
||||
let status = status.clone();
|
||||
move |cx| {
|
||||
provide_contexts(cx, &req, res_options);
|
||||
provide_contexts(cx, &req, res_options, status);
|
||||
(app_fn)(cx, data).into_view(cx)
|
||||
}
|
||||
};
|
||||
|
||||
let (head, tail) = html_parts(&options);
|
||||
|
||||
stream_app(app, head, tail, res_options).await
|
||||
stream_app(app, head, tail, res_options, status).await
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn provide_contexts(cx: leptos::Scope, req: &HttpRequest, res_options: ResponseOptions) {
|
||||
fn provide_contexts(
|
||||
cx: leptos::Scope,
|
||||
req: &HttpRequest,
|
||||
res_options: ResponseOptions,
|
||||
status: RouterStatusContext,
|
||||
) {
|
||||
let path = leptos_corrected_path(req);
|
||||
|
||||
let integration = ServerIntegration { path };
|
||||
provide_context(cx, RouterIntegrationContext::new(integration));
|
||||
provide_context(cx, status);
|
||||
provide_context(cx, MetaContext::new());
|
||||
provide_context(cx, res_options);
|
||||
provide_context(cx, req.clone());
|
||||
@@ -385,6 +395,7 @@ async fn stream_app(
|
||||
head: String,
|
||||
tail: String,
|
||||
res_options: ResponseOptions,
|
||||
router_status: RouterStatusContext,
|
||||
) -> HttpResponse<BoxBody> {
|
||||
let (stream, runtime, _) = render_to_stream_with_prefix_undisposed(app, move |cx| {
|
||||
let head = use_context::<MetaContext>(cx)
|
||||
@@ -411,7 +422,15 @@ async fn stream_app(
|
||||
let res_options = res_options.0.read().await;
|
||||
|
||||
let (status, mut headers) = (res_options.status, res_options.headers.clone());
|
||||
let status = status.unwrap_or_default();
|
||||
let status = status.unwrap_or_else(|| {
|
||||
router_status
|
||||
.status
|
||||
.read()
|
||||
.ok()
|
||||
.and_then(|s| s.map(|s| StatusCode::from_u16(s).ok()))
|
||||
.flatten()
|
||||
.unwrap_or_default()
|
||||
});
|
||||
|
||||
let complete_stream = futures::stream::iter([
|
||||
first_chunk.unwrap(),
|
||||
|
||||
@@ -318,6 +318,8 @@ where
|
||||
let default_res_options = ResponseOptions::default();
|
||||
let res_options2 = default_res_options.clone();
|
||||
let res_options3 = default_res_options.clone();
|
||||
let router_status = RouterStatusContext::default();
|
||||
let router_status2 = router_status.clone();
|
||||
|
||||
async move {
|
||||
// Need to get the path and query string of the Request
|
||||
@@ -403,6 +405,7 @@ where
|
||||
cx,
|
||||
RouterIntegrationContext::new(integration),
|
||||
);
|
||||
provide_context(cx, router_status2);
|
||||
provide_context(cx, MetaContext::new());
|
||||
provide_context(cx, req_parts);
|
||||
provide_context(cx, default_res_options);
|
||||
@@ -471,9 +474,16 @@ where
|
||||
Box::pin(complete_stream) as PinnedHtmlStream
|
||||
));
|
||||
|
||||
if let Some(status) = res_options.status {
|
||||
*res.status_mut() = status
|
||||
}
|
||||
let status = res_options.status.unwrap_or_else(|| {
|
||||
router_status
|
||||
.status
|
||||
.read()
|
||||
.ok()
|
||||
.and_then(|s| s.map(|s| StatusCode::from_u16(s).ok()))
|
||||
.flatten()
|
||||
.unwrap_or_default()
|
||||
});
|
||||
*res.status_mut() = status;
|
||||
let mut res_headers = res_options.headers.clone();
|
||||
res.headers_mut().extend(res_headers.drain());
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
use cfg_if::cfg_if;
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
rc::Rc,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
use leptos::*;
|
||||
use thiserror::Error;
|
||||
@@ -61,6 +65,14 @@ pub(crate) struct RouterContextInner {
|
||||
set_state: WriteSignal<State>,
|
||||
}
|
||||
|
||||
/// Context type that indicates the status of the last request
|
||||
/// (i.e., whether it was not found, or had an error.)
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct RouterStatusContext {
|
||||
pub status: Arc<RwLock<Option<u16>>>,
|
||||
pub message: Arc<RwLock<Option<String>>>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for RouterContextInner {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("RouterContextInner")
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::{
|
||||
expand_optionals, get_route_matches, join_paths, Branch, Matcher, RouteDefinition,
|
||||
RouteMatch,
|
||||
},
|
||||
RouteContext, RouterContext,
|
||||
RouteContext, RouterContext, RouterStatusContext,
|
||||
};
|
||||
|
||||
/// Contains route definitions and manages the actual routing process.
|
||||
@@ -190,12 +190,24 @@ pub fn Routes(
|
||||
});
|
||||
|
||||
// show the root route
|
||||
let router_status = use_context::<RouterStatusContext>(cx);
|
||||
let root = create_memo(cx, move |prev| {
|
||||
provide_context(cx, route_states);
|
||||
let router_status = router_status.clone();
|
||||
route_states.with(|state| {
|
||||
if state.routes.borrow().is_empty() {
|
||||
if let Some(status) = router_status {
|
||||
if let Ok(mut lock) = status.status.write() {
|
||||
*lock = Some(404);
|
||||
}
|
||||
}
|
||||
Some(base_route.outlet().into_view(cx))
|
||||
} else {
|
||||
if let Some(status) = router_status {
|
||||
if let Ok(mut lock) = status.status.write() {
|
||||
*lock = None;
|
||||
}
|
||||
}
|
||||
let root = state.routes.borrow();
|
||||
let root = root.get(0);
|
||||
if let Some(route) = root {
|
||||
|
||||
Reference in New Issue
Block a user