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