1use dioxus::dioxus_core::Element;
2
3#[cfg(feature = "server")]
4use axum::routing::Route;
5#[cfg(feature = "server")]
6use axum_core::{extract::Request, response::IntoResponse};
7#[cfg(feature = "server")]
8use std::convert::Infallible;
9#[cfg(feature = "server")]
10use tower_layer::Layer;
11#[cfg(feature = "server")]
12use tower_service::Service;
13
14#[cfg(feature = "lambda")]
15mod lambda;
16
17pub mod prelude {
18 pub use dioxus::prelude::*;
19 pub use dioxus_fullstack::prelude::*;
20}
21
22#[doc = include_str!("../docs/launch.md")]
23pub fn launch(_app: fn() -> Element) {
24 #[cfg(feature = "web")]
25 dioxus::launch(_app);
26
27 #[cfg(feature = "server")]
28 {
29 use axum::routing::*;
30 use dioxus_fullstack::prelude::*;
31
32 struct TryIntoResult(Result<ServeConfig, dioxus_fullstack::UnableToLoadIndex>);
33
34 impl TryInto<ServeConfig> for TryIntoResult {
35 type Error = dioxus_fullstack::UnableToLoadIndex;
36
37 fn try_into(self) -> Result<ServeConfig, Self::Error> {
38 self.0
39 }
40 }
41
42 tokio::runtime::Runtime::new()
43 .unwrap()
44 .block_on(async move {
45 let app = Router::new().serve_dioxus_application(
46 TryIntoResult(ServeConfigBuilder::default().build()),
47 _app,
48 );
49
50 #[cfg(not(feature = "lambda"))]
51 {
52 let address = dioxus_cli_config::fullstack_address_or_localhost();
53 let listener = tokio::net::TcpListener::bind(address).await.unwrap();
54
55 axum::serve(listener, app.into_make_service())
56 .await
57 .unwrap();
58 }
59
60 #[cfg(feature = "lambda")]
61 {
62 use self::lambda::LambdaAdapter;
63
64 tracing::info!("Running in lambda mode");
65 lambda_runtime::run(LambdaAdapter::from(app)).await.unwrap();
66 }
67 });
68 };
69}
70
71#[cfg(feature = "server")]
72pub async fn launch_with_layers<L>(app: fn() -> Element, layers: Vec<L>)
73where
74 L: Layer<Route> + Clone + Send + 'static,
75 L::Service: Service<Request> + Clone + Send + 'static,
76 <L::Service as Service<Request>>::Response: IntoResponse + 'static,
77 <L::Service as Service<Request>>::Error: Into<Infallible> + 'static,
78 <L::Service as Service<Request>>::Future: Send + 'static,
79{
80 #[cfg(feature = "web")]
81 dioxus::launch(app);
82
83 #[cfg(feature = "server")]
84 {
85 use axum::routing::*;
86 use dioxus_fullstack::prelude::*;
87
88 struct TryIntoResult(Result<ServeConfig, dioxus_fullstack::UnableToLoadIndex>);
89
90 impl TryInto<ServeConfig> for TryIntoResult {
91 type Error = dioxus_fullstack::UnableToLoadIndex;
92
93 fn try_into(self) -> Result<ServeConfig, Self::Error> {
94 self.0
95 }
96 }
97
98 let mut app = Router::new()
99 .serve_dioxus_application(TryIntoResult(ServeConfigBuilder::default().build()), app);
100
101 for layer in layers {
102 app = app.layer(layer);
103 }
104
105 #[cfg(not(feature = "lambda"))]
106 {
107 let address = dioxus_cli_config::fullstack_address_or_localhost();
108 let listener = tokio::net::TcpListener::bind(address).await.unwrap();
109
110 axum::serve(listener, app.into_make_service())
111 .await
112 .unwrap();
113 }
114
115 #[cfg(feature = "lambda")]
116 {
117 use self::lambda::LambdaAdapter;
118
119 tracing::info!("Running in lambda mode");
120 lambda_runtime::run(LambdaAdapter::from(app)).await.unwrap();
121 }
122 };
123}
124
125#[cfg(feature = "server")]
126pub struct AppBuilder<L> {
127 layers: Vec<L>,
128 app: fn() -> Element,
129}
130
131#[cfg(feature = "server")]
132impl<L> AppBuilder<L>
133where
134 L: Layer<Route> + Clone + Send + 'static,
135 L::Service: Service<Request> + Clone + Send + 'static,
136 <L::Service as Service<Request>>::Response: IntoResponse + 'static,
137 <L::Service as Service<Request>>::Error: Into<Infallible> + 'static,
138 <L::Service as Service<Request>>::Future: Send + 'static,
139{
140 pub fn new(app: fn() -> Element) -> Self {
141 Self {
142 layers: Vec::new(),
143 app,
144 }
145 }
146
147 pub fn layer(mut self, layer: L) -> Self {
148 self.layers.push(layer);
149 self
150 }
151
152 pub async fn serve(self) {
153 launch_with_layers(self.app, self.layers).await;
154 }
155}