1#![forbid(unsafe_code)]
2#![deny(missing_docs)]
3
4pub mod client;
104
105pub mod server;
107
108pub mod codec;
110
111#[macro_use]
112pub mod error;
114pub mod middleware;
116pub mod redirect;
118pub mod request;
120pub mod response;
122
123#[cfg(feature = "actix-no-default")]
124#[doc(hidden)]
125pub use ::actix_web as actix_export;
126#[cfg(feature = "axum-no-default")]
127#[doc(hidden)]
128pub use ::axum as axum_export;
129#[cfg(feature = "generic")]
130#[doc(hidden)]
131pub use ::bytes as bytes_export;
132#[cfg(feature = "generic")]
133#[doc(hidden)]
134pub use ::http as http_export;
135use base64::{engine::general_purpose::STANDARD_NO_PAD, DecodeError, Engine};
136#[cfg(feature = "bitcode")]
137pub use bitcode;
138pub use bytes::Bytes;
141use bytes::{BufMut, BytesMut};
142use client::Client;
143use codec::{Encoding, FromReq, FromRes, IntoReq, IntoRes};
144#[doc(hidden)]
145pub use const_format;
146#[doc(hidden)]
147pub use const_str;
148pub use error::ServerFnError;
149#[cfg(feature = "form-redirects")]
150use error::ServerFnUrlError;
151use error::{FromServerFnError, ServerFnErrorErr};
152use futures::{pin_mut, SinkExt, Stream, StreamExt};
153use http::Method;
154use middleware::{BoxedService, Layer, Service};
155use redirect::call_redirect_hook;
156use request::Req;
157use response::{ClientRes, Res, TryRes};
158#[cfg(feature = "rkyv")]
159pub use rkyv;
160#[doc(hidden)]
161pub use serde;
162#[doc(hidden)]
163#[cfg(feature = "serde-lite")]
164pub use serde_lite;
165use server::Server;
166use std::{
167 collections::HashMap,
168 fmt::{Debug, Display},
169 future::Future,
170 marker::PhantomData,
171 ops::{Deref, DerefMut},
172 pin::Pin,
173 sync::{Arc, LazyLock, RwLock},
174};
175#[doc(hidden)]
176pub use xxhash_rust;
177
178type ServerFnServerRequest<Fn> = <<Fn as ServerFn>::Server as crate::Server<
179 <Fn as ServerFn>::Error,
180 <Fn as ServerFn>::InputStreamError,
181 <Fn as ServerFn>::OutputStreamError,
182>>::Request;
183type ServerFnServerResponse<Fn> = <<Fn as ServerFn>::Server as crate::Server<
184 <Fn as ServerFn>::Error,
185 <Fn as ServerFn>::InputStreamError,
186 <Fn as ServerFn>::OutputStreamError,
187>>::Response;
188
189pub trait ServerFn: Send + Sized {
219 const PATH: &'static str;
221
222 type Client: Client<
226 Self::Error,
227 Self::InputStreamError,
228 Self::OutputStreamError,
229 >;
230
231 type Server: Server<
235 Self::Error,
236 Self::InputStreamError,
237 Self::OutputStreamError,
238 >;
239
240 type Protocol: Protocol<
242 Self,
243 Self::Output,
244 Self::Client,
245 Self::Server,
246 Self::Error,
247 Self::InputStreamError,
248 Self::OutputStreamError,
249 >;
250
251 type Output: Send;
256
257 type Error: FromServerFnError + Send + Sync;
260 type InputStreamError: FromServerFnError + Send + Sync;
263 type OutputStreamError: FromServerFnError + Send + Sync;
266
267 fn url() -> &'static str {
269 Self::PATH
270 }
271
272 fn middlewares() -> Vec<
274 Arc<
275 dyn Layer<
276 ServerFnServerRequest<Self>,
277 ServerFnServerResponse<Self>,
278 >,
279 >,
280 > {
281 Vec::new()
282 }
283
284 fn run_body(
286 self,
287 ) -> impl Future<Output = Result<Self::Output, Self::Error>> + Send;
288
289 #[doc(hidden)]
290 fn run_on_server(
291 req: ServerFnServerRequest<Self>,
292 ) -> impl Future<Output = ServerFnServerResponse<Self>> + Send {
293 #[cfg(feature = "form-redirects")]
297 let accepts_html = req
298 .accepts()
299 .map(|n| n.contains("text/html"))
300 .unwrap_or(false);
301 #[cfg(feature = "form-redirects")]
302 let mut referer = req.referer().as_deref().map(ToOwned::to_owned);
303
304 async move {
305 #[allow(unused_variables, unused_mut)]
306 let (mut res, err) =
308 Self::Protocol::run_server(req, Self::run_body)
309 .await
310 .map(|res| (res, None))
311 .unwrap_or_else(|e| {
312 let mut response =
313 <<Self as ServerFn>::Server as crate::Server<
314 Self::Error,
315 Self::InputStreamError,
316 Self::OutputStreamError,
317 >>::Response::error_response(
318 Self::PATH, e.ser()
319 );
320 let content_type =
321 <Self::Error as FromServerFnError>::Encoder::CONTENT_TYPE;
322 response.content_type(content_type);
323 (response, Some(e))
324 });
325
326 #[cfg(feature = "form-redirects")]
328 if accepts_html {
329 if let Some(err) = err {
331 if let Ok(url) = ServerFnUrlError::new(Self::PATH, err)
332 .to_url(referer.as_deref().unwrap_or("/"))
333 {
334 referer = Some(url.to_string());
335 }
336 }
337 else if let Some(referer) = referer.as_mut() {
340 ServerFnUrlError::<Self::Error>::strip_error_info(referer)
341 }
342
343 res.redirect(referer.as_deref().unwrap_or("/"));
345 }
346
347 res
348 }
349 }
350
351 #[doc(hidden)]
352 fn run_on_client(
353 self,
354 ) -> impl Future<Output = Result<Self::Output, Self::Error>> + Send {
355 async move { Self::Protocol::run_client(Self::PATH, self).await }
356 }
357}
358
359pub trait Protocol<
363 Input,
364 Output,
365 Client,
366 Server,
367 Error,
368 InputStreamError = Error,
369 OutputStreamError = Error,
370> where
371 Server: crate::Server<Error, InputStreamError, OutputStreamError>,
372 Client: crate::Client<Error, InputStreamError, OutputStreamError>,
373{
374 const METHOD: Method;
376
377 fn run_server<F, Fut>(
380 request: Server::Request,
381 server_fn: F,
382 ) -> impl Future<Output = Result<Server::Response, Error>> + Send
383 where
384 F: Fn(Input) -> Fut + Send,
385 Fut: Future<Output = Result<Output, Error>> + Send;
386
387 fn run_client(
390 path: &str,
391 input: Input,
392 ) -> impl Future<Output = Result<Output, Error>> + Send;
393}
394
395pub struct Http<InputProtocol, OutputProtocol>(
431 PhantomData<(InputProtocol, OutputProtocol)>,
432);
433
434impl<InputProtocol, OutputProtocol, Input, Output, Client, Server, E>
435 Protocol<Input, Output, Client, Server, E>
436 for Http<InputProtocol, OutputProtocol>
437where
438 Input: IntoReq<InputProtocol, Client::Request, E>
439 + FromReq<InputProtocol, Server::Request, E>
440 + Send,
441 Output: IntoRes<OutputProtocol, Server::Response, E>
442 + FromRes<OutputProtocol, Client::Response, E>
443 + Send,
444 E: FromServerFnError,
445 InputProtocol: Encoding,
446 OutputProtocol: Encoding,
447 Client: crate::Client<E>,
448 Server: crate::Server<E>,
449{
450 const METHOD: Method = InputProtocol::METHOD;
451
452 async fn run_server<F, Fut>(
453 request: Server::Request,
454 server_fn: F,
455 ) -> Result<Server::Response, E>
456 where
457 F: Fn(Input) -> Fut + Send,
458 Fut: Future<Output = Result<Output, E>> + Send,
459 {
460 let input = Input::from_req(request).await?;
461
462 let output = server_fn(input).await?;
463
464 let response = Output::into_res(output).await?;
465
466 Ok(response)
467 }
468
469 async fn run_client(path: &str, input: Input) -> Result<Output, E>
470 where
471 Client: crate::Client<E>,
472 {
473 let req = input.into_req(path, OutputProtocol::CONTENT_TYPE)?;
475 let res = Client::send(req).await?;
476
477 let status = res.status();
478 let location = res.location();
479 let has_redirect_header = res.has_redirect();
480
481 let res = if (400..=599).contains(&status) {
483 Err(E::de(res.try_into_bytes().await?))
484 } else {
485 let output = Output::from_res(res).await?;
487 Ok(output)
488 }?;
489
490 if (300..=399).contains(&status) || has_redirect_header {
492 call_redirect_hook(&location);
493 }
494 Ok(res)
495 }
496}
497
498pub struct Websocket<InputEncoding, OutputEncoding>(
531 PhantomData<(InputEncoding, OutputEncoding)>,
532);
533
534pub struct BoxedStream<T, E> {
549 stream: Pin<Box<dyn Stream<Item = Result<T, E>> + Send>>,
550}
551
552impl<T, E> From<BoxedStream<T, E>>
553 for Pin<Box<dyn Stream<Item = Result<T, E>> + Send>>
554{
555 fn from(val: BoxedStream<T, E>) -> Self {
556 val.stream
557 }
558}
559
560impl<T, E> Deref for BoxedStream<T, E> {
561 type Target = Pin<Box<dyn Stream<Item = Result<T, E>> + Send>>;
562 fn deref(&self) -> &Self::Target {
563 &self.stream
564 }
565}
566
567impl<T, E> DerefMut for BoxedStream<T, E> {
568 fn deref_mut(&mut self) -> &mut Self::Target {
569 &mut self.stream
570 }
571}
572
573impl<T, E> Debug for BoxedStream<T, E> {
574 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
575 f.debug_struct("BoxedStream").finish()
576 }
577}
578
579impl<T, E, S> From<S> for BoxedStream<T, E>
580where
581 S: Stream<Item = Result<T, E>> + Send + 'static,
582{
583 fn from(stream: S) -> Self {
584 BoxedStream {
585 stream: Box::pin(stream),
586 }
587 }
588}
589
590impl<
591 Input,
592 InputItem,
593 OutputItem,
594 InputEncoding,
595 OutputEncoding,
596 Client,
597 Server,
598 Error,
599 InputStreamError,
600 OutputStreamError,
601 >
602 Protocol<
603 Input,
604 BoxedStream<OutputItem, OutputStreamError>,
605 Client,
606 Server,
607 Error,
608 InputStreamError,
609 OutputStreamError,
610 > for Websocket<InputEncoding, OutputEncoding>
611where
612 Input: Deref<Target = BoxedStream<InputItem, InputStreamError>>
613 + Into<BoxedStream<InputItem, InputStreamError>>
614 + From<BoxedStream<InputItem, InputStreamError>>,
615 InputEncoding: Encodes<InputItem> + Decodes<InputItem>,
616 OutputEncoding: Encodes<OutputItem> + Decodes<OutputItem>,
617 InputStreamError: FromServerFnError + Send,
618 OutputStreamError: FromServerFnError + Send,
619 Error: FromServerFnError + Send,
620 Server: crate::Server<Error, InputStreamError, OutputStreamError>,
621 Client: crate::Client<Error, InputStreamError, OutputStreamError>,
622 OutputItem: Send + 'static,
623 InputItem: Send + 'static,
624{
625 const METHOD: Method = Method::GET;
626
627 async fn run_server<F, Fut>(
628 request: Server::Request,
629 server_fn: F,
630 ) -> Result<Server::Response, Error>
631 where
632 F: Fn(Input) -> Fut + Send,
633 Fut: Future<
634 Output = Result<
635 BoxedStream<OutputItem, OutputStreamError>,
636 Error,
637 >,
638 > + Send,
639 {
640 let (request_bytes, response_stream, response) =
641 request.try_into_websocket().await?;
642 let input = request_bytes.map(|request_bytes| {
643 let request_bytes = request_bytes
644 .map(|bytes| deserialize_result::<InputStreamError>(bytes))
645 .unwrap_or_else(Err);
646 match request_bytes {
647 Ok(request_bytes) => InputEncoding::decode(request_bytes)
648 .map_err(|e| {
649 InputStreamError::from_server_fn_error(
650 ServerFnErrorErr::Deserialization(e.to_string()),
651 )
652 }),
653 Err(err) => Err(InputStreamError::de(err)),
654 }
655 });
656 let boxed = Box::pin(input)
657 as Pin<
658 Box<
659 dyn Stream<Item = Result<InputItem, InputStreamError>>
660 + Send,
661 >,
662 >;
663 let input = BoxedStream { stream: boxed };
664
665 let output = server_fn(input.into()).await?;
666
667 let output = output.stream.map(|output| {
668 let result = match output {
669 Ok(output) => OutputEncoding::encode(&output).map_err(|e| {
670 OutputStreamError::from_server_fn_error(
671 ServerFnErrorErr::Serialization(e.to_string()),
672 )
673 .ser()
674 }),
675 Err(err) => Err(err.ser()),
676 };
677 serialize_result(result)
678 });
679
680 Server::spawn(async move {
681 pin_mut!(response_stream);
682 pin_mut!(output);
683 while let Some(output) = output.next().await {
684 if response_stream.send(output).await.is_err() {
685 break;
686 }
687 }
688 })?;
689
690 Ok(response)
691 }
692
693 fn run_client(
694 path: &str,
695 input: Input,
696 ) -> impl Future<
697 Output = Result<BoxedStream<OutputItem, OutputStreamError>, Error>,
698 > + Send {
699 let input = input.into();
700
701 async move {
702 let (stream, sink) = Client::open_websocket(path).await?;
703
704 Client::spawn(async move {
706 pin_mut!(input);
707 pin_mut!(sink);
708 while let Some(input) = input.stream.next().await {
709 let result = match input {
710 Ok(input) => {
711 InputEncoding::encode(&input).map_err(|e| {
712 InputStreamError::from_server_fn_error(
713 ServerFnErrorErr::Serialization(
714 e.to_string(),
715 ),
716 )
717 .ser()
718 })
719 }
720 Err(err) => Err(err.ser()),
721 };
722 let result = serialize_result(result);
723 if sink.send(result).await.is_err() {
724 break;
725 }
726 }
727 });
728
729 let stream = stream.map(|request_bytes| {
731 let request_bytes = request_bytes
732 .map(|bytes| deserialize_result::<OutputStreamError>(bytes))
733 .unwrap_or_else(Err);
734 match request_bytes {
735 Ok(request_bytes) => OutputEncoding::decode(request_bytes)
736 .map_err(|e| {
737 OutputStreamError::from_server_fn_error(
738 ServerFnErrorErr::Deserialization(
739 e.to_string(),
740 ),
741 )
742 }),
743 Err(err) => Err(OutputStreamError::de(err)),
744 }
745 });
746 let boxed = Box::pin(stream)
747 as Pin<
748 Box<
749 dyn Stream<Item = Result<OutputItem, OutputStreamError>>
750 + Send,
751 >,
752 >;
753 let output = BoxedStream { stream: boxed };
754 Ok(output)
755 }
756 }
757}
758
759fn serialize_result(result: Result<Bytes, Bytes>) -> Bytes {
764 match result {
765 Ok(bytes) => {
766 let mut buf = BytesMut::with_capacity(1 + bytes.len());
767 buf.put_u8(0); buf.extend_from_slice(&bytes);
769 buf.freeze()
770 }
771 Err(bytes) => {
772 let mut buf = BytesMut::with_capacity(1 + bytes.len());
773 buf.put_u8(1); buf.extend_from_slice(&bytes);
775 buf.freeze()
776 }
777 }
778}
779
780fn deserialize_result<E: FromServerFnError>(
782 bytes: Bytes,
783) -> Result<Bytes, Bytes> {
784 if bytes.is_empty() {
785 return Err(E::from_server_fn_error(
786 ServerFnErrorErr::Deserialization("Data is empty".into()),
787 )
788 .ser());
789 }
790
791 let tag = bytes[0];
792 let content = bytes.slice(1..);
793
794 match tag {
795 0 => Ok(content),
796 1 => Err(content),
797 _ => Err(E::from_server_fn_error(ServerFnErrorErr::Deserialization(
798 "Invalid data tag".into(),
799 ))
800 .ser()), }
802}
803
804pub enum Format {
806 Binary,
808 Text,
810}
811pub trait ContentType {
813 const CONTENT_TYPE: &'static str;
815}
816
817pub trait FormatType {
819 const FORMAT_TYPE: Format;
821
822 fn into_encoded_string(bytes: Bytes) -> String {
824 match Self::FORMAT_TYPE {
825 Format::Binary => STANDARD_NO_PAD.encode(bytes),
826 Format::Text => String::from_utf8(bytes.into())
827 .expect("Valid text format type with utf-8 comptabile string"),
828 }
829 }
830
831 fn from_encoded_string(data: &str) -> Result<Bytes, DecodeError> {
833 match Self::FORMAT_TYPE {
834 Format::Binary => {
835 STANDARD_NO_PAD.decode(data).map(|data| data.into())
836 }
837 Format::Text => Ok(Bytes::copy_from_slice(data.as_bytes())),
838 }
839 }
840}
841
842pub trait Encodes<T>: ContentType + FormatType {
844 type Error: Display + Debug;
846
847 fn encode(output: &T) -> Result<Bytes, Self::Error>;
849}
850
851pub trait Decodes<T> {
853 type Error: Display;
855
856 fn decode(bytes: Bytes) -> Result<T, Self::Error>;
858}
859
860#[cfg(feature = "ssr")]
861#[doc(hidden)]
862pub use inventory;
863
864#[macro_export]
866macro_rules! initialize_server_fn_map {
867 ($req:ty, $res:ty) => {
868 std::sync::LazyLock::new(|| {
869 std::sync::RwLock::new(
870 $crate::inventory::iter::<ServerFnTraitObj<$req, $res>>
871 .into_iter()
872 .map(|obj| {
873 ((obj.path().to_string(), obj.method()), obj.clone())
874 })
875 .collect(),
876 )
877 })
878 };
879}
880
881pub type MiddlewareSet<Req, Res> = Vec<Arc<dyn Layer<Req, Res>>>;
883
884pub struct ServerFnTraitObj<Req, Res> {
888 path: &'static str,
889 method: Method,
890 handler: fn(Req) -> Pin<Box<dyn Future<Output = Res> + Send>>,
891 middleware: fn() -> MiddlewareSet<Req, Res>,
892 ser: fn(ServerFnErrorErr) -> Bytes,
893}
894
895impl<Req, Res> ServerFnTraitObj<Req, Res> {
896 pub const fn new<
898 S: ServerFn<
899 Server: crate::Server<
900 S::Error,
901 S::InputStreamError,
902 S::OutputStreamError,
903 Request = Req,
904 Response = Res,
905 >,
906 >,
907 >(
908 handler: fn(Req) -> Pin<Box<dyn Future<Output = Res> + Send>>,
909 ) -> Self
910 where
911 Req: crate::Req<
912 S::Error,
913 S::InputStreamError,
914 S::OutputStreamError,
915 WebsocketResponse = Res,
916 > + Send
917 + 'static,
918 Res: crate::TryRes<S::Error> + Send + 'static,
919 {
920 Self {
921 path: S::PATH,
922 method: S::Protocol::METHOD,
923 handler,
924 middleware: S::middlewares,
925 ser: |e| S::Error::from_server_fn_error(e).ser(),
926 }
927 }
928
929 pub fn path(&self) -> &'static str {
931 self.path
932 }
933
934 pub fn method(&self) -> Method {
936 self.method.clone()
937 }
938
939 pub fn handler(&self, req: Req) -> impl Future<Output = Res> + Send {
941 (self.handler)(req)
942 }
943
944 pub fn middleware(&self) -> MiddlewareSet<Req, Res> {
946 (self.middleware)()
947 }
948
949 pub fn boxed(self) -> BoxedService<Req, Res>
951 where
952 Self: Service<Req, Res>,
953 Req: 'static,
954 Res: 'static,
955 {
956 BoxedService::new(self.ser, self)
957 }
958}
959
960impl<Req, Res> Service<Req, Res> for ServerFnTraitObj<Req, Res>
961where
962 Req: Send + 'static,
963 Res: 'static,
964{
965 fn run(
966 &mut self,
967 req: Req,
968 _ser: fn(ServerFnErrorErr) -> Bytes,
969 ) -> Pin<Box<dyn Future<Output = Res> + Send>> {
970 let handler = self.handler;
971 Box::pin(async move { handler(req).await })
972 }
973}
974
975impl<Req, Res> Clone for ServerFnTraitObj<Req, Res> {
976 fn clone(&self) -> Self {
977 Self {
978 path: self.path,
979 method: self.method.clone(),
980 handler: self.handler,
981 middleware: self.middleware,
982 ser: self.ser,
983 }
984 }
985}
986
987#[allow(unused)] type LazyServerFnMap<Req, Res> =
989 LazyLock<RwLock<HashMap<(String, Method), ServerFnTraitObj<Req, Res>>>>;
990
991#[cfg(feature = "ssr")]
992impl<Req: 'static, Res: 'static> inventory::Collect
993 for ServerFnTraitObj<Req, Res>
994{
995 #[inline]
996 fn registry() -> &'static inventory::Registry {
997 static REGISTRY: inventory::Registry = inventory::Registry::new();
998 ®ISTRY
999 }
1000}
1001
1002#[cfg(feature = "axum-no-default")]
1004pub mod axum {
1005 use crate::{
1006 error::FromServerFnError, middleware::BoxedService, LazyServerFnMap,
1007 Protocol, Server, ServerFn, ServerFnTraitObj,
1008 };
1009 use axum::body::Body;
1010 use http::{Method, Request, Response, StatusCode};
1011 use or_poisoned::OrPoisoned;
1012 use std::future::Future;
1013
1014 static REGISTERED_SERVER_FUNCTIONS: LazyServerFnMap<
1015 Request<Body>,
1016 Response<Body>,
1017 > = initialize_server_fn_map!(Request<Body>, Response<Body>);
1018
1019 pub struct AxumServerFnBackend;
1021
1022 impl<Error, InputStreamError, OutputStreamError>
1023 Server<Error, InputStreamError, OutputStreamError>
1024 for AxumServerFnBackend
1025 where
1026 Error: FromServerFnError + Send + Sync,
1027 InputStreamError: FromServerFnError + Send + Sync,
1028 OutputStreamError: FromServerFnError + Send + Sync,
1029 {
1030 type Request = Request<Body>;
1031 type Response = Response<Body>;
1032
1033 #[allow(unused_variables)]
1034 fn spawn(
1035 future: impl Future<Output = ()> + Send + 'static,
1036 ) -> Result<(), Error> {
1037 #[cfg(feature = "axum")]
1038 {
1039 tokio::spawn(future);
1040 Ok(())
1041 }
1042 #[cfg(not(feature = "axum"))]
1043 {
1044 Err(Error::from_server_fn_error(
1045 crate::error::ServerFnErrorErr::Request(
1046 "No async runtime available. You need to either \
1047 enable the full axum feature to pull in tokio, or \
1048 implement the `Server` trait for your async runtime \
1049 manually."
1050 .into(),
1051 ),
1052 ))
1053 }
1054 }
1055 }
1056
1057 pub fn register_explicit<T>()
1061 where
1062 T: ServerFn<
1063 Server: crate::Server<
1064 T::Error,
1065 T::InputStreamError,
1066 T::OutputStreamError,
1067 Request = Request<Body>,
1068 Response = Response<Body>,
1069 >,
1070 > + 'static,
1071 {
1072 REGISTERED_SERVER_FUNCTIONS.write().or_poisoned().insert(
1073 (T::PATH.into(), T::Protocol::METHOD),
1074 ServerFnTraitObj::new::<T>(|req| Box::pin(T::run_on_server(req))),
1075 );
1076 }
1077
1078 pub fn server_fn_paths() -> impl Iterator<Item = (&'static str, Method)> {
1080 let paths: Vec<_> = REGISTERED_SERVER_FUNCTIONS
1081 .read()
1082 .unwrap()
1083 .values()
1084 .map(|item| (item.path(), item.method()))
1085 .collect();
1086
1087 paths.into_iter()
1088 }
1089
1090 pub async fn handle_server_fn(req: Request<Body>) -> Response<Body> {
1092 let path = req.uri().path();
1093
1094 if let Some(mut service) =
1095 get_server_fn_service(path, req.method().clone())
1096 {
1097 service.run(req).await
1098 } else {
1099 Response::builder()
1100 .status(StatusCode::BAD_REQUEST)
1101 .body(Body::from(format!(
1102 "Could not find a server function at the route {path}. \
1103 \n\nIt's likely that either\n 1. The API prefix you \
1104 specify in the `#[server]` macro doesn't match the \
1105 prefix at which your server function handler is mounted, \
1106 or \n2. You are on a platform that doesn't support \
1107 automatic server function registration and you need to \
1108 call ServerFn::register_explicit() on the server \
1109 function type, somewhere in your `main` function.",
1110 )))
1111 .unwrap()
1112 }
1113 }
1114
1115 pub fn get_server_fn_service(
1117 path: &str,
1118 method: Method,
1119 ) -> Option<BoxedService<Request<Body>, Response<Body>>> {
1120 let key = (path.into(), method);
1121 REGISTERED_SERVER_FUNCTIONS
1122 .read()
1123 .or_poisoned()
1124 .get(&key)
1125 .map(|server_fn| {
1126 let middleware = (server_fn.middleware)();
1127 let mut service = server_fn.clone().boxed();
1128 for middleware in middleware {
1129 service = middleware.layer(service);
1130 }
1131 service
1132 })
1133 }
1134}
1135
1136#[cfg(feature = "actix-no-default")]
1138pub mod actix {
1139 use crate::{
1140 error::FromServerFnError, middleware::BoxedService,
1141 request::actix::ActixRequest, response::actix::ActixResponse,
1142 server::Server, LazyServerFnMap, Protocol, ServerFn, ServerFnTraitObj,
1143 };
1144 use actix_web::{web::Payload, HttpRequest, HttpResponse};
1145 use http::Method;
1146 use or_poisoned::OrPoisoned;
1147 #[doc(hidden)]
1148 pub use send_wrapper::SendWrapper;
1149 use std::future::Future;
1150
1151 static REGISTERED_SERVER_FUNCTIONS: LazyServerFnMap<
1152 ActixRequest,
1153 ActixResponse,
1154 > = initialize_server_fn_map!(ActixRequest, ActixResponse);
1155
1156 pub struct ActixServerFnBackend;
1158
1159 impl<Error, InputStreamError, OutputStreamError>
1160 Server<Error, InputStreamError, OutputStreamError>
1161 for ActixServerFnBackend
1162 where
1163 Error: FromServerFnError + Send + Sync,
1164 InputStreamError: FromServerFnError + Send + Sync,
1165 OutputStreamError: FromServerFnError + Send + Sync,
1166 {
1167 type Request = ActixRequest;
1168 type Response = ActixResponse;
1169
1170 fn spawn(
1171 future: impl Future<Output = ()> + Send + 'static,
1172 ) -> Result<(), Error> {
1173 actix_web::rt::spawn(future);
1174 Ok(())
1175 }
1176 }
1177
1178 pub fn register_explicit<T>()
1182 where
1183 T: ServerFn<
1184 Server: crate::Server<
1185 T::Error,
1186 T::InputStreamError,
1187 T::OutputStreamError,
1188 Request = ActixRequest,
1189 Response = ActixResponse,
1190 >,
1191 > + 'static,
1192 {
1193 REGISTERED_SERVER_FUNCTIONS.write().or_poisoned().insert(
1194 (T::PATH.into(), T::Protocol::METHOD),
1195 ServerFnTraitObj::new::<T>(|req| Box::pin(T::run_on_server(req))),
1196 );
1197 }
1198
1199 pub fn server_fn_paths() -> impl Iterator<Item = (&'static str, Method)> {
1201 let paths: Vec<_> = REGISTERED_SERVER_FUNCTIONS
1202 .read()
1203 .unwrap()
1204 .values()
1205 .map(|item| (item.path(), item.method()))
1206 .collect();
1207
1208 paths.into_iter()
1209 }
1210
1211 pub async fn handle_server_fn(
1213 req: HttpRequest,
1214 payload: Payload,
1215 ) -> HttpResponse {
1216 let path = req.uri().path();
1217 let method = req.method();
1218 if let Some(mut service) = get_server_fn_service(path, method) {
1219 service
1220 .run(ActixRequest::from((req, payload)))
1221 .await
1222 .0
1223 .take()
1224 } else {
1225 HttpResponse::BadRequest().body(format!(
1226 "Could not find a server function at the route {path}. \
1227 \n\nIt's likely that either\n 1. The API prefix you specify \
1228 in the `#[server]` macro doesn't match the prefix at which \
1229 your server function handler is mounted, or \n2. You are on \
1230 a platform that doesn't support automatic server function \
1231 registration and you need to call \
1232 ServerFn::register_explicit() on the server function type, \
1233 somewhere in your `main` function.",
1234 ))
1235 }
1236 }
1237
1238 pub fn get_server_fn_service(
1240 path: &str,
1241 method: &actix_web::http::Method,
1242 ) -> Option<BoxedService<ActixRequest, ActixResponse>> {
1243 use actix_web::http::Method as ActixMethod;
1244
1245 let method = match *method {
1246 ActixMethod::GET => Method::GET,
1247 ActixMethod::POST => Method::POST,
1248 ActixMethod::PUT => Method::PUT,
1249 ActixMethod::PATCH => Method::PATCH,
1250 ActixMethod::DELETE => Method::DELETE,
1251 ActixMethod::HEAD => Method::HEAD,
1252 ActixMethod::TRACE => Method::TRACE,
1253 ActixMethod::OPTIONS => Method::OPTIONS,
1254 ActixMethod::CONNECT => Method::CONNECT,
1255 _ => unreachable!(),
1256 };
1257 REGISTERED_SERVER_FUNCTIONS
1258 .read()
1259 .or_poisoned()
1260 .get(&(path.into(), method))
1261 .map(|server_fn| {
1262 let middleware = (server_fn.middleware)();
1263 let mut service = server_fn.clone().boxed();
1264 for middleware in middleware {
1265 service = middleware.layer(service);
1266 }
1267 service
1268 })
1269 }
1270}
1271
1272pub mod mock {
1274 use std::future::Future;
1275
1276 pub struct BrowserMockServer;
1283
1284 impl<Error, InputStreamError, OutputStreamError>
1285 crate::server::Server<Error, InputStreamError, OutputStreamError>
1286 for BrowserMockServer
1287 where
1288 Error: Send + 'static,
1289 InputStreamError: Send + 'static,
1290 OutputStreamError: Send + 'static,
1291 {
1292 type Request = crate::request::BrowserMockReq;
1293 type Response = crate::response::BrowserMockRes;
1294
1295 fn spawn(
1296 _: impl Future<Output = ()> + Send + 'static,
1297 ) -> Result<(), Error> {
1298 unreachable!()
1299 }
1300 }
1301}
1302
1303#[cfg(test)]
1304mod tests {
1305
1306 use super::*;
1307 use crate::codec::JsonEncoding;
1308 use serde::{Deserialize, Serialize};
1309
1310 #[derive(Debug, Serialize, Deserialize)]
1311 enum TestError {
1312 ServerFnError(ServerFnErrorErr),
1313 }
1314
1315 impl FromServerFnError for TestError {
1316 type Encoder = JsonEncoding;
1317
1318 fn from_server_fn_error(value: ServerFnErrorErr) -> Self {
1319 Self::ServerFnError(value)
1320 }
1321 }
1322 #[test]
1323 fn test_result_serialization() {
1324 let ok_result: Result<Bytes, Bytes> =
1326 Ok(Bytes::from_static(b"success data"));
1327 let serialized = serialize_result(ok_result);
1328 let deserialized = deserialize_result::<TestError>(serialized);
1329 assert!(deserialized.is_ok());
1330 assert_eq!(deserialized.unwrap(), Bytes::from_static(b"success data"));
1331
1332 let err_result: Result<Bytes, Bytes> =
1334 Err(Bytes::from_static(b"error details"));
1335 let serialized = serialize_result(err_result);
1336 let deserialized = deserialize_result::<TestError>(serialized);
1337 assert!(deserialized.is_err());
1338 assert_eq!(
1339 deserialized.unwrap_err(),
1340 Bytes::from_static(b"error details")
1341 );
1342 }
1343}