server_fn.rs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #[cfg(any(feature = "ssr", doc))]
  2. #[derive(Clone)]
  3. /// A trait object for a function that be called on serializable arguments and returns a serializable result.
  4. pub struct ServerFnTraitObj(server_fn::ServerFnTraitObj<()>);
  5. #[cfg(any(feature = "ssr", doc))]
  6. impl std::ops::Deref for ServerFnTraitObj {
  7. type Target = server_fn::ServerFnTraitObj<()>;
  8. fn deref(&self) -> &Self::Target {
  9. &self.0
  10. }
  11. }
  12. #[cfg(any(feature = "ssr", doc))]
  13. impl std::ops::DerefMut for ServerFnTraitObj {
  14. fn deref_mut(&mut self) -> &mut Self::Target {
  15. &mut self.0
  16. }
  17. }
  18. #[cfg(any(feature = "ssr", doc))]
  19. impl ServerFnTraitObj {
  20. fn new(
  21. prefix: &'static str,
  22. url: &'static str,
  23. encoding: server_fn::Encoding,
  24. run: ServerFunction,
  25. ) -> Self {
  26. Self(server_fn::ServerFnTraitObj::new(prefix, url, encoding, run))
  27. }
  28. /// Create a new `ServerFnTraitObj` from a `server_fn::ServerFnTraitObj`.
  29. pub const fn from_generic_server_fn(server_fn: server_fn::ServerFnTraitObj<()>) -> Self {
  30. Self(server_fn)
  31. }
  32. }
  33. #[cfg(feature = "ssr")]
  34. server_fn::inventory::collect!(ServerFnTraitObj);
  35. #[cfg(feature = "ssr")]
  36. /// Middleware for a server function
  37. pub struct ServerFnMiddleware {
  38. /// The prefix of the server function.
  39. pub prefix: &'static str,
  40. /// The url of the server function.
  41. pub url: &'static str,
  42. /// The middleware layers.
  43. pub middleware: fn() -> Vec<std::sync::Arc<dyn crate::layer::Layer>>,
  44. }
  45. #[cfg(feature = "ssr")]
  46. pub(crate) static MIDDLEWARE: once_cell::sync::Lazy<
  47. std::collections::HashMap<
  48. (&'static str, &'static str),
  49. Vec<std::sync::Arc<dyn crate::layer::Layer>>,
  50. >,
  51. > = once_cell::sync::Lazy::new(|| {
  52. let mut map: std::collections::HashMap<
  53. (&'static str, &'static str),
  54. Vec<std::sync::Arc<dyn crate::layer::Layer>>,
  55. > = std::collections::HashMap::new();
  56. for middleware in server_fn::inventory::iter::<ServerFnMiddleware> {
  57. map.entry((middleware.prefix, middleware.url))
  58. .or_default()
  59. .extend((middleware.middleware)().iter().cloned());
  60. }
  61. map
  62. });
  63. #[cfg(feature = "ssr")]
  64. server_fn::inventory::collect!(ServerFnMiddleware);
  65. #[cfg(any(feature = "ssr", doc))]
  66. /// A server function that can be called on serializable arguments and returns a serializable result.
  67. pub type ServerFunction = server_fn::SerializedFnTraitObj<()>;
  68. #[cfg(feature = "ssr")]
  69. #[allow(clippy::type_complexity)]
  70. static REGISTERED_SERVER_FUNCTIONS: once_cell::sync::Lazy<
  71. std::sync::Arc<std::sync::RwLock<std::collections::HashMap<&'static str, ServerFnTraitObj>>>,
  72. > = once_cell::sync::Lazy::new(|| {
  73. let mut map = std::collections::HashMap::new();
  74. for server_fn in server_fn::inventory::iter::<ServerFnTraitObj> {
  75. map.insert(server_fn.0.url(), server_fn.clone());
  76. }
  77. std::sync::Arc::new(std::sync::RwLock::new(map))
  78. });
  79. #[cfg(any(feature = "ssr", doc))]
  80. /// The registry of all Dioxus server functions.
  81. pub struct DioxusServerFnRegistry;
  82. #[cfg(feature = "ssr")]
  83. impl server_fn::ServerFunctionRegistry<()> for DioxusServerFnRegistry {
  84. type Error = ServerRegistrationFnError;
  85. fn register_explicit(
  86. prefix: &'static str,
  87. url: &'static str,
  88. server_function: ServerFunction,
  89. encoding: server_fn::Encoding,
  90. ) -> Result<(), Self::Error> {
  91. // store it in the hashmap
  92. let mut write = REGISTERED_SERVER_FUNCTIONS
  93. .write()
  94. .map_err(|e| ServerRegistrationFnError::Poisoned(e.to_string()))?;
  95. let prev = write.insert(
  96. url,
  97. ServerFnTraitObj::new(prefix, url, encoding, server_function),
  98. );
  99. // if there was already a server function with this key,
  100. // return Err
  101. match prev {
  102. Some(_) => Err(ServerRegistrationFnError::AlreadyRegistered(format!(
  103. "There was already a server function registered at {:?}. \
  104. This can happen if you use the same server function name \
  105. in two different modules
  106. on `stable` or in `release` mode.",
  107. url
  108. ))),
  109. None => Ok(()),
  110. }
  111. }
  112. /// Returns the server function registered at the given URL, or `None` if no function is registered at that URL.
  113. fn get(url: &str) -> Option<server_fn::ServerFnTraitObj<()>> {
  114. REGISTERED_SERVER_FUNCTIONS
  115. .read()
  116. .ok()
  117. .and_then(|fns| fns.get(url).map(|inner| inner.0.clone()))
  118. }
  119. /// Returns the server function registered at the given URL, or `None` if no function is registered at that URL.
  120. fn get_trait_obj(url: &str) -> Option<server_fn::ServerFnTraitObj<()>> {
  121. Self::get(url)
  122. }
  123. fn get_encoding(url: &str) -> Option<server_fn::Encoding> {
  124. REGISTERED_SERVER_FUNCTIONS
  125. .read()
  126. .ok()
  127. .and_then(|fns| fns.get(url).map(|f| f.encoding()))
  128. }
  129. /// Returns a list of all registered server functions.
  130. fn paths_registered() -> Vec<&'static str> {
  131. REGISTERED_SERVER_FUNCTIONS
  132. .read()
  133. .ok()
  134. .map(|fns| fns.keys().cloned().collect())
  135. .unwrap_or_default()
  136. }
  137. }
  138. #[cfg(any(feature = "ssr", doc))]
  139. /// Errors that can occur when registering a server function.
  140. #[derive(thiserror::Error, Debug, Clone, serde::Serialize, serde::Deserialize)]
  141. pub enum ServerRegistrationFnError {
  142. /// The server function is already registered.
  143. #[error("The server function {0} is already registered")]
  144. AlreadyRegistered(String),
  145. /// The server function registry is poisoned.
  146. #[error("The server function registry is poisoned: {0}")]
  147. Poisoned(String),
  148. }
  149. /// Defines a "server function." A server function can be called from the server or the client,
  150. /// but the body of its code will only be run on the server, i.e., if a crate feature `ssr` is enabled.
  151. ///
  152. /// Server functions are created using the `server` macro.
  153. ///
  154. /// The set of server functions
  155. /// can be queried on the server for routing purposes by calling [server_fn::ServerFunctionRegistry::get].
  156. ///
  157. /// Technically, the trait is implemented on a type that describes the server function's arguments, not the function itself.
  158. pub trait DioxusServerFn: server_fn::ServerFn<()> {
  159. /// Registers the server function, allowing the client to query it by URL.
  160. #[cfg(any(feature = "ssr", doc))]
  161. fn register_explicit() -> Result<(), server_fn::ServerFnError> {
  162. Self::register_in_explicit::<DioxusServerFnRegistry>()
  163. }
  164. }
  165. impl<T> DioxusServerFn for T where T: server_fn::ServerFn<()> {}