From 556e4f374b1cf226e4302e4150a381990118a512 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 3 Apr 2023 11:59:40 -0500 Subject: [PATCH] Document salvo adapter --- packages/server/src/adapters/axum_adapter.rs | 127 ++++++------- packages/server/src/adapters/salvo_adapter.rs | 167 +++++++++++++++++- 2 files changed, 217 insertions(+), 77 deletions(-) diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index ad3fafd6a..34e6a5e46 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -39,7 +39,7 @@ //! to_owned![text]; //! async move { //! if let Ok(data) = get_server_data().await { -//! text.set(data.clone()); +//! text.set(data); //! } //! } //! }, @@ -85,25 +85,22 @@ pub trait DioxusRouterExt { /// # use dioxus::prelude::*; /// # use dioxus_server::prelude::*; /// - /// fn main() { - /// tokio::runtime::Runtime::new() - /// .unwrap() - /// .block_on(async move { - /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); - /// axum::Server::bind(&addr) - /// .serve( - /// axum::Router::new() - /// .register_server_fns_with_handler("", |func| { - /// move |headers: HeaderMap, body: Request| async move { - /// // Add the headers to the context - /// server_fn_handler((headers.clone(),).into(), func.clone(), headers, body).await - /// } - /// }) - /// .into_make_service(), - /// ) - /// .await - /// .unwrap(); - /// }); + /// #[tokio::main] + /// async fn main() { + /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + /// axum::Server::bind(&addr) + /// .serve( + /// axum::Router::new() + /// .register_server_fns_with_handler("", |func| { + /// move |headers: HeaderMap, body: Request| async move { + /// // Add the headers to the context + /// server_fn_handler((headers.clone(),), func.clone(), headers, body).await + /// } + /// }) + /// .into_make_service(), + /// ) + /// .await + /// .unwrap(); /// } /// ``` fn register_server_fns_with_handler( @@ -123,20 +120,17 @@ pub trait DioxusRouterExt { /// # use dioxus::prelude::*; /// # use dioxus_server::prelude::*; /// - /// fn main() { - /// tokio::runtime::Runtime::new() - /// .unwrap() - /// .block_on(async move { - /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); - /// axum::Server::bind(&addr) - /// .serve( - /// axum::Router::new() - /// .register_server_fns("") - /// .into_make_service(), - /// ) - /// .await - /// .unwrap(); - /// }); + /// #[tokio::main] + /// async fn main() { + /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + /// axum::Server::bind(&addr) + /// .serve( + /// axum::Router::new() + /// .register_server_fns("") + /// .into_make_service(), + /// ) + /// .await + /// .unwrap(); /// } /// ``` fn register_server_fns(self, server_fn_route: &'static str) -> Self; @@ -150,23 +144,19 @@ pub trait DioxusRouterExt { /// # use dioxus::prelude::*; /// # use dioxus_server::prelude::*; /// - /// fn main() { - /// GetServerData::register().unwrap(); - /// tokio::runtime::Runtime::new() - /// .unwrap() - /// .block_on(async move { - /// hot_reload_init!(); - /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); - /// axum::Server::bind(&addr) - /// .serve( - /// axum::Router::new() - /// // Server side render the application, serve static assets, and register server functions - /// .connect_hot_reload() - /// .into_make_service(), - /// ) - /// .await - /// .unwrap(); - /// }); + /// #[tokio::main] + /// async fn main() { + /// hot_reload_init!(); + /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + /// axum::Server::bind(&addr) + /// .serve( + /// axum::Router::new() + /// // Server side render the application, serve static assets, and register server functions + /// .connect_hot_reload() + /// .into_make_service(), + /// ) + /// .await + /// .unwrap(); /// } /// /// # fn app(cx: Scope) -> Element {todo!()} @@ -174,7 +164,7 @@ pub trait DioxusRouterExt { fn connect_hot_reload(self) -> Self; /// Serves the Dioxus application. This will serve a complete server side rendered application. - /// It will serve static assets, server render the application, register server functions, and intigrate with hot reloading. + /// This will serve static assets, server render the application, register server functions, and intigrate with hot reloading. /// /// # Example /// ```rust @@ -182,22 +172,18 @@ pub trait DioxusRouterExt { /// # use dioxus::prelude::*; /// # use dioxus_server::prelude::*; /// - /// fn main() { - /// GetServerData::register().unwrap(); - /// tokio::runtime::Runtime::new() - /// .unwrap() - /// .block_on(async move { - /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); - /// axum::Server::bind(&addr) - /// .serve( - /// axum::Router::new() - /// // Server side render the application, serve static assets, and register server functions - /// .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) - /// .into_make_service(), - /// ) - /// .await - /// .unwrap(); - /// }); + /// #[tokio::main] + /// async fn main() { + /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + /// axum::Server::bind(&addr) + /// .serve( + /// axum::Router::new() + /// // Server side render the application, serve static assets, and register server functions + /// .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) + /// .into_make_service(), + /// ) + /// .await + /// .unwrap(); /// } /// /// # fn app(cx: Scope) -> Element {todo!()} @@ -235,7 +221,7 @@ where fn register_server_fns(self, server_fn_route: &'static str) -> Self { self.register_server_fns_with_handler(server_fn_route, |func| { move |headers: HeaderMap, body: Request| async move { - server_fn_handler(().into(), func.clone(), headers, body).await + server_fn_handler((), func.clone(), headers, body).await } }) } @@ -314,11 +300,12 @@ async fn render_handler( /// 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: DioxusServerContext, + server_context: impl Into, function: Arc, headers: HeaderMap, req: Request, ) -> impl IntoResponse { + let server_context = server_context.into(); let (_, body) = req.into_parts(); let body = hyper::body::to_bytes(body).await; let Ok(body)=body else { diff --git a/packages/server/src/adapters/salvo_adapter.rs b/packages/server/src/adapters/salvo_adapter.rs index 357e1c19c..6bc8947a6 100644 --- a/packages/server/src/adapters/salvo_adapter.rs +++ b/packages/server/src/adapters/salvo_adapter.rs @@ -1,3 +1,54 @@ +//! Dioxus utilities for the [Salvo](https://salvo.rs) server framework. +//! +//! # Example +//! ```rust +//! # #![allow(non_snake_case)] +//! # use dioxus::prelude::*; +//! # use dioxus_server::prelude::*; +//! +//! fn main() { +//! #[cfg(feature = "web")] +//! dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); +//! #[cfg(feature = "ssr")] +//! { +//! use salvo::prelude::*; +//! GetServerData::register().unwrap(); +//! tokio::runtime::Runtime::new() +//! .unwrap() +//! .block_on(async move { +//! let router = +//! Router::new().serve_dioxus_application("", ServeConfigBuilder::new(app, ())); +//! Server::new(TcpListener::bind("127.0.0.1:8080")) +//! .serve(router) +//! .await; +//! }); +//! } +//! } +//! +//! fn app(cx: Scope) -> Element { +//! let text = use_state(cx, || "...".to_string()); +//! +//! cx.render(rsx! { +//! button { +//! onclick: move |_| { +//! to_owned![text]; +//! async move { +//! if let Ok(data) = get_server_data().await { +//! text.set(data); +//! } +//! } +//! }, +//! "Run a server function" +//! } +//! "Server said: {text}" +//! }) +//! } +//! +//! #[server(GetServerData)] +//! async fn get_server_data() -> Result { +//! Ok("Hello from the server!".to_string()) +//! } + use std::{error::Error, sync::Arc}; use hyper::{http::HeaderValue, StatusCode}; @@ -11,14 +62,51 @@ use tokio::task::spawn_blocking; use crate::{ prelude::DioxusServerContext, - prelude::SSRState, - serve::ServeConfig, + render::SSRState, + serve_config::ServeConfig, server_fn::{DioxusServerFnRegistry, ServerFnTraitObj}, }; +/// A extension trait with utilities for integrating Dioxus with your Salvo router. pub trait DioxusRouterExt { - fn register_server_fns(self, server_fn_route: &'static str) -> Self; - + /// Registers server functions with a custom handler function. This allows you to pass custom context to your server functions by generating a [`DioxusServerContext`] from the request. + /// + /// ```rust + /// use salvo::prelude::*; + /// use std::{net::TcpListener, sync::Arc}; + /// use dioxus_server::prelude::*; + /// + /// struct ServerFunctionHandler { + /// server_fn: Arc, + /// } + /// + /// #[handler] + /// impl ServerFunctionHandler { + /// async fn handle( + /// &self, + /// req: &mut Request, + /// depot: &mut Depot, + /// res: &mut Response, + /// flow: &mut FlowCtrl, + /// ) { + /// // Add the headers to server context + /// ServerFnHandler::new((req.headers().clone(),), self.server_fn.clone()) + /// .handle(req, depot, res, flow) + /// .await + /// } + /// } + /// + /// #[tokio::main] + /// async fn main() { + /// let router = Router::new() + /// .register_server_fns_with_handler("", |func| { + /// ServerFnHandler::new(DioxusServerContext::default(), func) + /// }); + /// Server::new(TcpListener::bind("127.0.0.1:8080")) + /// .serve(router) + /// .await; + /// } + /// ``` fn register_server_fns_with_handler( self, server_fn_route: &'static str, @@ -27,13 +115,70 @@ pub trait DioxusRouterExt { where H: Handler + 'static; + /// Registers server functions with the default handler. This handler function will pass an empty [`DioxusServerContext`] to your server functions. + /// + /// # Example + /// ```rust + /// use salvo::prelude::*; + /// use std::{net::TcpListener, sync::Arc}; + /// use dioxus_server::prelude::*; + /// + /// #[tokio::main] + /// async fn main() { + /// let router = Router::new() + /// .register_server_fns(""); + /// Server::new(TcpListener::bind("127.0.0.1:8080")) + /// .serve(router) + /// .await; + /// } + /// + /// ``` + fn register_server_fns(self, server_fn_route: &'static str) -> Self; + + /// Register the web RSX hot reloading endpoint. This will enable hot reloading for your application in debug mode when you call [`dioxus_hot_reload::hot_reload_init`]. + /// + /// # Example + /// ```rust + /// use salvo::prelude::*; + /// use std::{net::TcpListener, sync::Arc}; + /// use dioxus_server::prelude::*; + /// + /// #[tokio::main] + /// async fn main() { + /// let router = Router::new() + /// .connect_hot_reload(); + /// Server::new(TcpListener::bind("127.0.0.1:8080")) + /// .serve(router) + /// .await; + /// } + fn connect_hot_reload(self) -> Self; + + /// Serves the Dioxus application. This will serve a complete server side rendered application. + /// This will serve static assets, server render the application, register server functions, and intigrate with hot reloading. + /// + /// # Example + /// ```rust + /// #![allow(non_snake_case)] + /// use dioxus::prelude::*; + /// use dioxus_server::prelude::*; + /// use salvo::prelude::*; + /// use std::{net::TcpListener, sync::Arc}; + /// + /// #[tokio::main] + /// async fn main() { + /// let router = Router::new().serve_dioxus_application("", ServeConfigBuilder::new(app, ())); + /// Server::new(TcpListener::bind("127.0.0.1:8080")) + /// .serve(router) + /// .await; + /// } + /// + /// # fn app(cx: Scope) -> Element {todo!()} + /// ``` fn serve_dioxus_application( self, server_fn_path: &'static str, cfg: impl Into>, ) -> Self; - - fn connect_hot_reload(self) -> Self; } impl DioxusRouterExt for Router { @@ -138,13 +283,19 @@ impl 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: Arc, } impl ServerFnHandler { - pub fn new(server_context: DioxusServerContext, function: Arc) -> Self { + /// Create a new server function handler with the given server context and server function. + pub fn new( + server_context: impl Into, + function: Arc, + ) -> Self { + let server_context = server_context.into(); Self { server_context, function, @@ -234,6 +385,7 @@ fn handle_error(error: impl Error + Send + Sync, res: &mut Response) { *res = resp_err; } +/// A handler for Dioxus web hot reload websocket. This will send the updated static parts of the RSX to the client when they change. #[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "ssr")))] #[derive(Default)] pub struct HotReloadHandler; @@ -251,6 +403,7 @@ impl HotReloadHandler { } } +/// A handler for Dioxus web hot reload websocket. This will send the updated static parts of the RSX to the client when they change. #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] #[derive(Default)] pub struct HotReloadHandler {