add extractors to server-fn

This commit is contained in:
Evan Almloff committed 2023-07-06 17:54:05 -07:00
1 parent 523be82965
commit 4f6e6a7c0d
12 files changed
+260 -139

No files matched your search

+22 -17
View File
@@ -64,8 +64,8 @@ use axum::{
Router,
};
use server_fn::{Encoding, Payload, ServerFunctionRegistry};
use std::error::Error;
use std::sync::Arc;
use std::sync::RwLock;
use tokio::task::spawn_blocking;
use crate::{
@@ -91,7 +91,7 @@ pub trait DioxusRouterExt<S> {
/// .register_server_fns_with_handler("", |func| {
/// move |req: Request<Body>| async move {
/// let (parts, body) = req.into_parts();
/// let parts: Arc<RequestParts> = Arc::new(parts.into());
/// let parts: Arc<http::request::Parts> = Arc::new(parts.into());
/// let server_context = DioxusServerContext::new(parts.clone());
/// server_fn_handler(server_context, func.clone(), parts, body).await
/// }
@@ -105,7 +105,7 @@ pub trait DioxusRouterExt<S> {
fn register_server_fns_with_handler<H, T>(
self,
server_fn_route: &'static str,
handler: impl FnMut(server_fn::ServerFnTraitObj<DioxusServerContext>) -> H,
handler: impl FnMut(server_fn::ServerFnTraitObj<()>) -> H,
) -> Self
where
H: Handler<T, S>,
@@ -230,7 +230,7 @@ where
fn register_server_fns_with_handler<H, T>(
self,
server_fn_route: &'static str,
mut handler: impl FnMut(server_fn::ServerFnTraitObj<DioxusServerContext>) -> H,
mut handler: impl FnMut(server_fn::ServerFnTraitObj<()>) -> H,
) -> Self
where
H: Handler<T, S, Body>,
@@ -257,7 +257,7 @@ where
self.register_server_fns_with_handler(server_fn_route, |func| {
move |req: Request<Body>| async move {
let (parts, body) = req.into_parts();
let parts: Arc<RequestParts> = Arc::new(parts.into());
let parts: Arc<RwLock<http::request::Parts>> = Arc::new(parts.into());
let server_context = DioxusServerContext::new(parts.clone());
server_fn_handler(server_context, func.clone(), parts, body).await
}
@@ -364,16 +364,11 @@ async fn render_handler<P: Clone + serde::Serialize + Send + Sync + 'static>(
request: Request<Body>,
) -> impl IntoResponse {
let (parts, _) = request.into_parts();
let parts: Arc<RequestParts> = Arc::new(parts.into());
let url = parts.uri.path_and_query().unwrap().to_string();
let parts: Arc<RwLock<http::request::Parts>> = Arc::new(RwLock::new(parts.into()));
let server_context = DioxusServerContext::new(parts.clone());
match ssr_state
.render(url, &cfg, |vdom| {
vdom.base_scope().provide_context(server_context.clone());
})
.await
{
match ssr_state.render(url, &cfg, &server_context).await {
Ok(rendered) => {
let crate::render::RenderResponse { html, freshness } = rendered;
let mut response = axum::response::Html::from(html).into_response();
@@ -392,8 +387,8 @@ async fn render_handler<P: Clone + serde::Serialize + Send + Sync + 'static>(
/// A default handler for server functions. It will deserialize the request, call the server function, and serialize the response.
pub async fn server_fn_handler(
server_context: DioxusServerContext,
function: server_fn::ServerFnTraitObj<DioxusServerContext>,
parts: Arc<RequestParts>,
function: server_fn::ServerFnTraitObj<()>,
parts: Arc<RwLock<http::request::Parts>>,
body: Body,
) -> impl IntoResponse {
let body = hyper::body::to_bytes(body).await;
@@ -403,7 +398,13 @@ pub async fn server_fn_handler(
// Because the future returned by `server_fn_handler` is `Send`, and the future returned by this function must be send, we need to spawn a new runtime
let (resp_tx, resp_rx) = tokio::sync::oneshot::channel();
let query_string = parts.uri.query().unwrap_or_default().to_string();
let query_string = parts
.read()
.unwrap()
.uri
.query()
.unwrap_or_default()
.to_string();
spawn_blocking({
move || {
tokio::runtime::Runtime::new()
@@ -414,9 +415,13 @@ pub async fn server_fn_handler(
Encoding::Url | Encoding::Cbor => &body,
Encoding::GetJSON | Encoding::GetCBOR => query,
};
let resp = match function.call(server_context.clone(), data).await {
let server_function_future = function.call((), data);
let server_function_future =
ProvideServerContext::new(server_function_future, server_context.clone());
let resp = match server_function_future.await {
Ok(serialized) => {
// if this is Accept: application/json then send a serialized JSON response
let parts = parts.read().unwrap();
let accept_header = parts
.headers
.get("Accept")
@@ -463,7 +468,7 @@ pub async fn server_fn_handler(
resp_rx.await.unwrap()
}
fn report_err<E: Error>(e: E) -> Response<BoxBody> {
fn report_err<E: std::fmt::Display>(e: E) -> Response<BoxBody> {
Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(body::boxed(format!("Error: {}", e)))
@@ -75,7 +75,7 @@ pub trait DioxusRouterExt {
/// use dioxus_fullstack::prelude::*;
///
/// struct ServerFunctionHandler {
/// server_fn: server_fn::ServerFnTraitObj<DioxusServerContext>,
/// server_fn: server_fn::ServerFnTraitObj<()>,
/// }
///
/// #[handler]
@@ -108,7 +108,7 @@ pub trait DioxusRouterExt {
fn register_server_fns_with_handler<H>(
self,
server_fn_route: &'static str,
handler: impl Fn(server_fn::ServerFnTraitObj<DioxusServerContext>) -> H,
handler: impl Fn(server_fn::ServerFnTraitObj<()>) -> H,
) -> Self
where
H: Handler + 'static;
@@ -202,7 +202,7 @@ impl DioxusRouterExt for Router {
fn register_server_fns_with_handler<H>(
self,
server_fn_route: &'static str,
mut handler: impl FnMut(server_fn::ServerFnTraitObj<DioxusServerContext>) -> H,
mut handler: impl FnMut(server_fn::ServerFnTraitObj<()>) -> H,
) -> Self
where
H: Handler + 'static,
@@ -333,9 +333,7 @@ impl<P: Clone + serde::Serialize + Send + Sync + 'static> Handler for SSRHandler
let server_context = DioxusServerContext::new(parts);
match renderer_pool
.render(route, &self.cfg, |vdom| {
vdom.base_scope().provide_context(server_context.clone());
})
.render(route, &self.cfg, &server_context)
.await
{
Ok(rendered) => {
@@ -357,14 +355,14 @@ impl<P: Clone + serde::Serialize + Send + Sync + 'static> Handler for SSRHandler
/// A default handler for server functions. It will deserialize the request body, call the server function, and serialize the response.
pub struct ServerFnHandler {
server_context: DioxusServerContext,
function: server_fn::ServerFnTraitObj<DioxusServerContext>,
function: server_fn::ServerFnTraitObj<()>,
}
impl ServerFnHandler {
/// Create a new server function handler with the given server context and server function.
pub fn new(
server_context: impl Into<DioxusServerContext>,
function: server_fn::ServerFnTraitObj<DioxusServerContext>,
function: server_fn::ServerFnTraitObj<()>,
) -> Self {
let server_context = server_context.into();
Self {
@@ -413,7 +411,12 @@ impl ServerFnHandler {
Encoding::Url | Encoding::Cbor => &body,
Encoding::GetJSON | Encoding::GetCBOR => &query,
};
let resp = function.call(server_context, data).await;
let server_function_future = function.call((), data);
let server_function_future = ProvideServerContext::new(
server_function_future,
server_context.clone(),
);
let resp = server_function_future.await;
resp_tx.send(resp).unwrap();
})
@@ -91,7 +91,7 @@ pub fn register_server_fns_with_handler<H, F, R>(
mut handler: H,
) -> BoxedFilter<(R,)>
where
H: FnMut(String, server_fn::ServerFnTraitObj<DioxusServerContext>) -> F,
H: FnMut(String, server_fn::ServerFnTraitObj<()>) -> F,
F: Filter<Extract = (R,), Error = warp::Rejection> + Send + Sync + 'static,
F::Extract: Send,
R: Reply + 'static,
@@ -192,12 +192,7 @@ pub fn render_ssr<P: Clone + serde::Serialize + Send + Sync + 'static>(
async move {
let server_context = DioxusServerContext::new(parts);
match renderer
.render(route, &cfg, |vdom| {
vdom.base_scope().provide_context(server_context.clone());
})
.await
{
match renderer.render(route, &cfg, &server_context).await {
Ok(rendered) => {
let crate::render::RenderResponse { html, freshness } = rendered;
@@ -270,8 +265,8 @@ impl warp::reject::Reject for RecieveFailed {}
/// A default handler for server functions. It will deserialize the request body, call the server function, and serialize the response.
pub async fn server_fn_handler(
server_context: impl Into<DioxusServerContext>,
function: server_fn::ServerFnTraitObj<DioxusServerContext>,
server_context: impl Into<(DioxusServerContext)>,
function: server_fn::ServerFnTraitObj<()>,
parts: RequestParts,
body: Bytes,
) -> Result<Box<dyn warp::Reply>, warp::Rejection> {
@@ -299,7 +294,10 @@ pub async fn server_fn_handler(
Encoding::Url | Encoding::Cbor => &body,
Encoding::GetJSON | Encoding::GetCBOR => &query,
};
let resp = match function.call(server_context.clone(), data).await {
let server_function_future = function.call((), data);
let server_function_future =
ProvideServerContext::new(server_function_future, server_context.clone());
let resp = match server_function_future.await {
Ok(serialized) => {
// if this is Accept: application/json then send a serialized JSON response
let accept_header = parts