1
0
Эх сурвалжийг харах

make regestering server functions optional

Evan Almloff 2 жил өмнө
parent
commit
158852e5a0

+ 0 - 3
docs/guide/examples/server_context.rs

@@ -16,9 +16,6 @@ fn main() {
         use axum::extract::State;
         use axum::routing::get;
 
-        // Register the server function before starting the server
-        DoubleServer::register().unwrap();
-
         tokio::runtime::Runtime::new()
             .unwrap()
             .block_on(async move {

+ 0 - 3
docs/guide/examples/server_context_state.rs

@@ -25,9 +25,6 @@ fn main() {
         use axum::routing::get;
         use std::sync::Arc;
 
-        // Register the server function before starting the server
-        DoubleServer::register().unwrap();
-
         tokio::runtime::Runtime::new()
             .unwrap()
             .block_on(async move {

+ 0 - 3
docs/guide/examples/server_function.rs

@@ -16,9 +16,6 @@ fn main() {
         use axum::extract::State;
         use axum::routing::get;
 
-        // Register the server function before starting the server
-        DoubleServer::register().unwrap();
-
         tokio::runtime::Runtime::new()
             .unwrap()
             .block_on(async move {

+ 1 - 1
packages/fullstack/Cargo.toml

@@ -13,7 +13,7 @@ keywords = ["dom", "ui", "gui", "react", "ssr", "fullstack"]
 
 [dependencies]
 # server functions
-server_fn = { git = "https://github.com/leptos-rs/leptos", rev = "671b1e4a8fff7a2e05bb621ef08e87be2b18ccae", default-features = false, features = ["stable"] }
+server_fn = { git = "https://github.com/leptos-rs/leptos", rev = "15a4e54435eb5a539afb75891292bcccd2cc8e85", default-features = false, features = ["stable"] }
 dioxus_server_macro = { path = "server-macro" }
 
 # warp

+ 0 - 1
packages/fullstack/README.md

@@ -46,7 +46,6 @@ fn main() {
     );
     #[cfg(feature = "ssr")]
     {
-        GetMeaning::register().unwrap();
         tokio::runtime::Runtime::new()
             .unwrap()
             .block_on(async move {

+ 0 - 3
packages/fullstack/examples/axum-desktop/src/server.rs

@@ -8,9 +8,6 @@ use dioxus_fullstack::prelude::*;
 
 #[tokio::main]
 async fn main() {
-    PostServerData::register().unwrap();
-    GetServerData::register().unwrap();
-
     let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
     axum::Server::bind(&addr)
         .serve(

+ 0 - 2
packages/fullstack/examples/axum-hello-world/src/main.rs

@@ -32,8 +32,6 @@ fn main() {
             true
         }));
 
-        PostServerData::register().unwrap();
-        GetServerData::register().unwrap();
         tokio::runtime::Runtime::new()
             .unwrap()
             .block_on(async move {

+ 0 - 2
packages/fullstack/examples/axum-router/src/main.rs

@@ -34,8 +34,6 @@ fn main() {
         }));
 
         use axum::extract::State;
-        PostServerData::register().unwrap();
-        GetServerData::register().unwrap();
         tokio::runtime::Runtime::new()
             .unwrap()
             .block_on(async move {

+ 0 - 2
packages/fullstack/examples/salvo-hello-world/src/main.rs

@@ -33,8 +33,6 @@ fn main() {
         }));
 
         use salvo::prelude::*;
-        PostServerData::register().unwrap();
-        GetServerData::register().unwrap();
         tokio::runtime::Runtime::new()
             .unwrap()
             .block_on(async move {

+ 0 - 2
packages/fullstack/examples/warp-hello-world/src/main.rs

@@ -32,8 +32,6 @@ fn main() {
             true
         }));
 
-        PostServerData::register().unwrap();
-        GetServerData::register().unwrap();
         tokio::runtime::Runtime::new()
             .unwrap()
             .block_on(async move {

+ 2 - 2
packages/fullstack/server-macro/Cargo.toml

@@ -7,8 +7,8 @@ edition = "2021"
 
 [dependencies]
 quote = "1.0.26"
-server_fn_macro = { git = "https://github.com/leptos-rs/leptos", rev = "671b1e4a8fff7a2e05bb621ef08e87be2b18ccae", features = ["stable"] }
-syn = { version = "1", features = ["full"] }
+server_fn_macro = { git = "https://github.com/leptos-rs/leptos", rev = "15a4e54435eb5a539afb75891292bcccd2cc8e85", features = ["stable"] }
+syn = { version = "2", features = ["full"] }
 
 [lib]
 proc-macro = true

+ 1 - 1
packages/fullstack/server-macro/src/lib.rs

@@ -35,7 +35,6 @@ use server_fn_macro::*;
 /// ```
 ///
 /// Note the following:
-/// - You must **register** the server function by calling `T::register()` somewhere in your main function.
 /// - **Server functions must be `async`.** Even if the work being done inside the function body
 ///   can run synchronously on the server, from the client’s perspective it involves an asynchronous
 ///   function call.
@@ -62,6 +61,7 @@ pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
     match server_macro_impl(
         args.into(),
         s.into(),
+        syn::parse_quote!(::dioxus_fullstack::prelude::ServerFnTraitObj),
         Some(context),
         Some(syn::parse_quote!(::dioxus_fullstack::prelude::server_fn)),
     ) {

+ 7 - 8
packages/fullstack/src/adapters/axum_adapter.rs

@@ -12,7 +12,6 @@
 //!     dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true));
 //!     #[cfg(feature = "ssr")]
 //!     {
-//!         GetServerData::register().unwrap();
 //!         tokio::runtime::Runtime::new()
 //!             .unwrap()
 //!             .block_on(async move {
@@ -107,7 +106,7 @@ pub trait DioxusRouterExt<S> {
     fn register_server_fns_with_handler<H, T>(
         self,
         server_fn_route: &'static str,
-        handler: impl Fn(ServerFunction) -> H,
+        handler: impl FnMut(server_fn::ServerFnTraitObj<DioxusServerContext>) -> H,
     ) -> Self
     where
         H: Handler<T, S>,
@@ -232,7 +231,7 @@ where
     fn register_server_fns_with_handler<H, T>(
         self,
         server_fn_route: &'static str,
-        mut handler: impl FnMut(ServerFunction) -> H,
+        mut handler: impl FnMut(server_fn::ServerFnTraitObj<DioxusServerContext>) -> H,
     ) -> Self
     where
         H: Handler<T, S, Body>,
@@ -243,7 +242,7 @@ where
         for server_fn_path in DioxusServerFnRegistry::paths_registered() {
             let func = DioxusServerFnRegistry::get(server_fn_path).unwrap();
             let full_route = format!("{server_fn_route}/{server_fn_path}");
-            match func.encoding {
+            match func.encoding() {
                 Encoding::Url | Encoding::Cbor => {
                     router = router.route(&full_route, post(handler(func)));
                 }
@@ -314,7 +313,7 @@ where
         let cfg = cfg.into();
 
         // Add server functions and render index.html
-        self.serve_static_assets(&cfg.assets_path)
+        self.serve_static_assets(cfg.assets_path)
             .route(
                 "/",
                 get(render_handler).with_state((cfg, SSRState::default())),
@@ -371,7 +370,7 @@ 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: ServerFunction,
+    function: server_fn::ServerFnTraitObj<DioxusServerContext>,
     parts: Arc<RequestParts>,
     body: Body,
 ) -> impl IntoResponse {
@@ -389,11 +388,11 @@ pub async fn server_fn_handler(
                 .expect("couldn't spawn runtime")
                 .block_on(async {
                     let query = &query_string.into();
-                    let data = match &function.encoding {
+                    let data = match &function.encoding() {
                         Encoding::Url | Encoding::Cbor => &body,
                         Encoding::GetJSON | Encoding::GetCBOR => query,
                     };
-                    let resp = match (function.trait_obj)(server_context.clone(), &data).await {
+                    let resp = match function.call(server_context.clone(), data).await {
                         Ok(serialized) => {
                             // if this is Accept: application/json then send a serialized JSON response
                             let accept_header = parts

+ 13 - 11
packages/fullstack/src/adapters/salvo_adapter.rs

@@ -12,7 +12,6 @@
 //!     #[cfg(feature = "ssr")]
 //!     {
 //!         use salvo::prelude::*;
-//!         GetServerData::register().unwrap();
 //!         tokio::runtime::Runtime::new()
 //!             .unwrap()
 //!             .block_on(async move {
@@ -110,7 +109,7 @@ pub trait DioxusRouterExt {
     fn register_server_fns_with_handler<H>(
         self,
         server_fn_route: &'static str,
-        handler: impl Fn(ServerFunction) -> H,
+        handler: impl Fn(server_fn::ServerFnTraitObj<DioxusServerContext>) -> H,
     ) -> Self
     where
         H: Handler + 'static;
@@ -204,7 +203,7 @@ impl DioxusRouterExt for Router {
     fn register_server_fns_with_handler<H>(
         self,
         server_fn_route: &'static str,
-        mut handler: impl FnMut(ServerFunction) -> H,
+        mut handler: impl FnMut(server_fn::ServerFnTraitObj<DioxusServerContext>) -> H,
     ) -> Self
     where
         H: Handler + 'static,
@@ -213,7 +212,7 @@ impl DioxusRouterExt for Router {
         for server_fn_path in DioxusServerFnRegistry::paths_registered() {
             let func = DioxusServerFnRegistry::get(server_fn_path).unwrap();
             let full_route = format!("{server_fn_route}/{server_fn_path}");
-            match func.encoding {
+            match func.encoding() {
                 Encoding::Url | Encoding::Cbor => {
                     router = router.push(Router::with_path(&full_route).post(handler(func)));
                 }
@@ -280,7 +279,7 @@ impl DioxusRouterExt for Router {
     ) -> Self {
         let cfg = cfg.into();
 
-        self.serve_static_assets(&cfg.assets_path)
+        self.serve_static_assets(cfg.assets_path)
             .connect_hot_reload()
             .register_server_fns(server_fn_path)
             .push(Router::with_path("/").get(SSRHandler { cfg }))
@@ -288,8 +287,8 @@ impl DioxusRouterExt for Router {
 
     fn connect_hot_reload(self) -> Self {
         let mut _dioxus_router = Router::with_path("_dioxus");
-        _dioxus_router = _dioxus_router
-            .push(Router::with_path("hot_reload").handle(HotReloadHandler::default()));
+        _dioxus_router =
+            _dioxus_router.push(Router::with_path("hot_reload").handle(HotReloadHandler));
         #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))]
         {
             _dioxus_router = _dioxus_router.push(Router::with_path("disconnect").handle(ignore_ws));
@@ -346,12 +345,15 @@ 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: ServerFunction,
+    function: server_fn::ServerFnTraitObj<DioxusServerContext>,
 }
 
 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: ServerFunction) -> Self {
+    pub fn new(
+        server_context: impl Into<DioxusServerContext>,
+        function: server_fn::ServerFnTraitObj<DioxusServerContext>,
+    ) -> Self {
         let server_context = server_context.into();
         Self {
             server_context,
@@ -395,11 +397,11 @@ impl ServerFnHandler {
                 tokio::runtime::Runtime::new()
                     .expect("couldn't spawn runtime")
                     .block_on(async move {
-                        let data = match &function.encoding {
+                        let data = match function.encoding() {
                             Encoding::Url | Encoding::Cbor => &body,
                             Encoding::GetJSON | Encoding::GetCBOR => &query,
                         };
-                        let resp = (function.trait_obj)(server_context, data).await;
+                        let resp = function.call(server_context, data).await;
 
                         resp_tx.send(resp).unwrap();
                     })

+ 8 - 9
packages/fullstack/src/adapters/warp_adapter.rs

@@ -11,7 +11,6 @@
 //!     dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true));
 //!     #[cfg(feature = "ssr")]
 //!     {
-//!         GetServerData::register().unwrap();
 //!         tokio::runtime::Runtime::new()
 //!             .unwrap()
 //!             .block_on(async move {
@@ -93,7 +92,7 @@ pub fn register_server_fns_with_handler<H, F, R>(
     mut handler: H,
 ) -> BoxedFilter<(R,)>
 where
-    H: FnMut(String, ServerFunction) -> F,
+    H: FnMut(String, server_fn::ServerFnTraitObj<DioxusServerContext>) -> F,
     F: Filter<Extract = (R,), Error = warp::Rejection> + Send + Sync + 'static,
     F::Extract: Send,
     R: Reply + 'static,
@@ -104,7 +103,7 @@ where
         let full_route = format!("{server_fn_route}/{server_fn_path}")
             .trim_start_matches('/')
             .to_string();
-        let route = handler(full_route, func.clone()).boxed();
+        let route = handler(full_route, func).boxed();
         if let Some(boxed_filter) = filter.take() {
             filter = Some(boxed_filter.or(route).unify().boxed());
         } else {
@@ -128,7 +127,7 @@ where
 /// ```
 pub fn register_server_fns(server_fn_route: &'static str) -> BoxedFilter<(impl Reply,)> {
     register_server_fns_with_handler(server_fn_route, |full_route, func| {
-        path(full_route.clone())
+        path(full_route)
             .and(warp::post().or(warp::get()).unify())
             .and(request_parts())
             .and(warp::body::bytes())
@@ -250,7 +249,7 @@ 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: ServerFunction,
+    function: server_fn::ServerFnTraitObj<DioxusServerContext>,
     parts: RequestParts,
     body: Bytes,
 ) -> Result<Box<dyn warp::Reply>, warp::Rejection> {
@@ -274,11 +273,11 @@ pub async fn server_fn_handler(
                         .as_bytes()
                         .to_vec()
                         .into();
-                    let data = match &function.encoding {
+                    let data = match function.encoding() {
                         Encoding::Url | Encoding::Cbor => &body,
                         Encoding::GetJSON | Encoding::GetCBOR => &query,
                     };
-                    let resp = match (function.trait_obj)(server_context.clone(), data).await {
+                    let resp = match function.call(server_context.clone(), data).await {
                         Ok(serialized) => {
                             // if this is Accept: application/json then send a serialized JSON response
                             let accept_header = parts
@@ -373,7 +372,7 @@ pub fn connect_hot_reload() -> impl Filter<Extract = (impl Reply,), Error = warp
         use warp::ws::Message;
 
         let hot_reload = warp::path!("_dioxus" / "hot_reload")
-            .and(warp::any().then(|| crate::hot_reload::spawn_hot_reload()))
+            .and(warp::any().then(crate::hot_reload::spawn_hot_reload))
             .and(warp::ws())
             .map(move |state: &'static HotReloadState, ws: warp::ws::Ws| {
                 #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))]
@@ -425,7 +424,7 @@ pub fn connect_hot_reload() -> impl Filter<Extract = (impl Reply,), Error = warp
                         struct DisconnectOnDrop(Option<warp::ws::WebSocket>);
                         impl Drop for DisconnectOnDrop {
                             fn drop(&mut self) {
-                                let _ = self.0.take().unwrap().close();
+                                std::mem::drop(self.0.take().unwrap().close());
                             }
                         }
 

+ 1 - 1
packages/fullstack/src/lib.rs

@@ -34,7 +34,7 @@ pub mod prelude {
     #[cfg(feature = "ssr")]
     pub use crate::server_context::RequestParts;
     pub use crate::server_context::{DioxusServerContext, HasServerContext};
-    pub use crate::server_fn::ServerFn;
+    pub use crate::server_fn::DioxusServerFn;
     #[cfg(feature = "ssr")]
     pub use crate::server_fn::{ServerFnTraitObj, ServerFunction};
     pub use dioxus_server_macro::*;

+ 72 - 24
packages/fullstack/src/server_fn.rs

@@ -1,30 +1,76 @@
 use crate::server_context::DioxusServerContext;
 
 #[cfg(any(feature = "ssr", doc))]
+#[derive(Clone)]
 /// A trait object for a function that be called on serializable arguments and returns a serializable result.
-pub type ServerFnTraitObj = server_fn::ServerFnTraitObj<DioxusServerContext>;
+pub struct ServerFnTraitObj(server_fn::ServerFnTraitObj<DioxusServerContext>);
+
+#[cfg(any(feature = "ssr", doc))]
+impl std::ops::Deref for ServerFnTraitObj {
+    type Target = server_fn::ServerFnTraitObj<DioxusServerContext>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+#[cfg(any(feature = "ssr", doc))]
+impl std::ops::DerefMut for ServerFnTraitObj {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+#[cfg(any(feature = "ssr", doc))]
+impl ServerFnTraitObj {
+    fn new(
+        prefix: &'static str,
+        url: &'static str,
+        encoding: server_fn::Encoding,
+        run: ServerFunction,
+    ) -> Self {
+        Self(server_fn::ServerFnTraitObj::new(prefix, url, encoding, run))
+    }
+
+    /// Create a new `ServerFnTraitObj` from a `server_fn::ServerFnTraitObj`.
+    pub const fn from_generic_server_fn(
+        server_fn: server_fn::ServerFnTraitObj<DioxusServerContext>,
+    ) -> Self {
+        Self(server_fn)
+    }
+}
+
+#[cfg(any(feature = "ssr", doc))]
+server_fn::inventory::collect!(ServerFnTraitObj);
 
 #[cfg(any(feature = "ssr", doc))]
 /// A server function that can be called on serializable arguments and returns a serializable result.
-pub type ServerFunction = server_fn::ServerFunction<DioxusServerContext>;
+pub type ServerFunction = server_fn::SerializedFnTraitObj<DioxusServerContext>;
 
 #[cfg(any(feature = "ssr", doc))]
 #[allow(clippy::type_complexity)]
 static REGISTERED_SERVER_FUNCTIONS: once_cell::sync::Lazy<
-    std::sync::Arc<std::sync::RwLock<std::collections::HashMap<&'static str, ServerFunction>>>,
-> = once_cell::sync::Lazy::new(Default::default);
+    std::sync::Arc<std::sync::RwLock<std::collections::HashMap<&'static str, ServerFnTraitObj>>>,
+> = once_cell::sync::Lazy::new(|| {
+    let mut map = std::collections::HashMap::new();
+    for server_fn in server_fn::inventory::iter::<ServerFnTraitObj> {
+        map.insert(server_fn.0.url(), server_fn.clone());
+    }
+    std::sync::Arc::new(std::sync::RwLock::new(map))
+});
 
 #[cfg(any(feature = "ssr", doc))]
 /// The registry of all Dioxus server functions.
 pub struct DioxusServerFnRegistry;
 
-#[cfg(any(feature = "ssr"))]
+#[cfg(feature = "ssr")]
 impl server_fn::ServerFunctionRegistry<DioxusServerContext> for DioxusServerFnRegistry {
     type Error = ServerRegistrationFnError;
 
-    fn register(
+    fn register_explicit(
+        prefix: &'static str,
         url: &'static str,
-        server_function: std::sync::Arc<ServerFnTraitObj>,
+        server_function: ServerFunction,
         encoding: server_fn::Encoding,
     ) -> Result<(), Self::Error> {
         // store it in the hashmap
@@ -33,10 +79,7 @@ impl server_fn::ServerFunctionRegistry<DioxusServerContext> for DioxusServerFnRe
             .map_err(|e| ServerRegistrationFnError::Poisoned(e.to_string()))?;
         let prev = write.insert(
             url,
-            ServerFunction {
-                trait_obj: server_function,
-                encoding,
-            },
+            ServerFnTraitObj::new(prefix, url, encoding, server_function),
         );
 
         // if there was already a server function with this key,
@@ -53,27 +96,32 @@ impl server_fn::ServerFunctionRegistry<DioxusServerContext> for DioxusServerFnRe
         }
     }
 
+    fn register(
+        url: &'static str,
+        server_function: ServerFunction,
+        encoding: server_fn::Encoding,
+    ) -> Result<(), Self::Error> {
+        Self::register_explicit("", url, server_function, encoding)
+    }
+
     /// Returns the server function registered at the given URL, or `None` if no function is registered at that URL.
-    fn get(url: &str) -> Option<ServerFunction> {
+    fn get(url: &str) -> Option<server_fn::ServerFnTraitObj<DioxusServerContext>> {
         REGISTERED_SERVER_FUNCTIONS
             .read()
             .ok()
-            .and_then(|fns| fns.get(url).cloned())
+            .and_then(|fns| fns.get(url).map(|inner| inner.0.clone()))
     }
 
     /// Returns the server function registered at the given URL, or `None` if no function is registered at that URL.
-    fn get_trait_obj(url: &str) -> Option<std::sync::Arc<ServerFnTraitObj>> {
-        REGISTERED_SERVER_FUNCTIONS
-            .read()
-            .ok()
-            .and_then(|fns| fns.get(url).map(|f| f.trait_obj.clone()))
+    fn get_trait_obj(url: &str) -> Option<server_fn::ServerFnTraitObj<DioxusServerContext>> {
+        Self::get(url)
     }
 
     fn get_encoding(url: &str) -> Option<server_fn::Encoding> {
         REGISTERED_SERVER_FUNCTIONS
             .read()
             .ok()
-            .and_then(|fns| fns.get(url).map(|f| f.encoding.clone()))
+            .and_then(|fns| fns.get(url).map(|f| f.encoding()))
     }
 
     /// Returns a list of all registered server functions.
@@ -103,16 +151,16 @@ pub enum ServerRegistrationFnError {
 ///
 /// Server functions are created using the `server` macro.
 ///
-/// The function should be registered by calling `ServerFn::register()`. The set of server functions
+/// The set of server functions
 /// can be queried on the server for routing purposes by calling [server_fn::ServerFunctionRegistry::get].
 ///
 /// Technically, the trait is implemented on a type that describes the server function's arguments, not the function itself.
-pub trait ServerFn: server_fn::ServerFn<DioxusServerContext> {
+pub trait DioxusServerFn: server_fn::ServerFn<DioxusServerContext> {
     /// Registers the server function, allowing the client to query it by URL.
     #[cfg(any(feature = "ssr", doc))]
-    fn register() -> Result<(), server_fn::ServerFnError> {
-        Self::register_in::<DioxusServerFnRegistry>()
+    fn register_explicit() -> Result<(), server_fn::ServerFnError> {
+        Self::register_in_explicit::<DioxusServerFnRegistry>()
     }
 }
 
-impl<T> ServerFn for T where T: server_fn::ServerFn<DioxusServerContext> {}
+impl<T> DioxusServerFn for T where T: server_fn::ServerFn<DioxusServerContext> {}