catalyzer/app/mod.rs
1use crate::internals::CatalyzerService;
2use crate::res::IntoRawResponse;
3use crate::internals::*;
4use crate::error::*;
5
6use std::net::{SocketAddr, ToSocketAddrs};
7use axum::Router as AxumRouter;
8
9pub(crate) mod launch;
10
11/// The main application type.
12///
13/// See the [module-level documentation](crate::app) for more information.
14#[derive(Debug)]
15pub struct App<State = ()> {
16 router: AxumRouter<State>,
17 address: Option<SocketAddr>,
18 https_address: Option<SocketAddr>,
19}
20
21impl<State> App<State> where
22 State: Clone + Send + Sync + 'static
23{
24 /// Creates a new [`App`] instance.
25 ///
26 /// This is the main entry point for creating a new application.
27 ///
28 /// It is recommended to use the [`App!`] macro instead of this method.
29 ///
30 /// [`App`]: crate::App
31 /// [`App!`]: macro.App.html
32 pub fn new() -> Self {
33 Self {
34 router: AxumRouter::<State>::new(),
35 address: None,
36 https_address: None,
37 }
38 }
39 /// Mounts a route handler on the application.
40 ///
41 /// This requires a handler that implements the [`AxumHandler`] trait.
42 /// Additionally, you need to provide a metadata type that implements the
43 /// [`HandlerMetadata`] trait.
44 ///
45 /// # Example
46 ///
47 /// ```rust
48 /// # use catalyzer::*;
49 /// # #[main]
50 /// # fn main() -> Result {
51 /// #[get("/")]
52 /// fn index() {
53 /// "Hello, world!"
54 /// }
55 ///
56 /// let app = App::new()
57 /// .route::<_, index_metadata, _>(index)?;
58 /// # }
59 ///
60 pub fn route<Return, Meta, Handler>(
61 mut self,
62 handler: Handler
63 ) -> Result<Self> where
64 Handler: AxumHandler<Return, State>,
65 Meta: HandlerMetadata,
66 Return: 'static
67 {
68 let method_router = match Meta::METHOD {
69 Method::GET => axum::routing::get(handler),
70 Method::POST => axum::routing::post(handler),
71 Method::PUT => axum::routing::put(handler),
72 Method::DELETE => axum::routing::delete(handler),
73 Method::PATCH => axum::routing::patch(handler),
74 Method::HEAD => axum::routing::head(handler),
75 Method::OPTIONS => axum::routing::options(handler),
76 Method::TRACE => axum::routing::trace(handler),
77 _ => return Err(crate::CatalyzerError::UnsupportedMethodError)
78 };
79 log::trace!("Mounted a {} on \"{}\"", Meta::METHOD, Meta::PATH);
80 self.router = self.router.route(Meta::PATH, method_router);
81 Ok(self)
82 }
83 /// Binds the application to a specific address.
84 ///
85 /// This is required before launching the application.
86 ///
87 /// # Example
88 ///
89 /// ```rust
90 /// # use catalyzer::*;
91 /// # #[main]
92 /// # fn main() -> Result {
93 /// let app = App::new().bind("0.0.0.0:8080")?;// Localhost on port 8080
94 /// # }
95 pub fn bind<Addr>(mut self, addr: Addr) -> Result<Self> where
96 Addr: ToSocketAddrs
97 {
98 let mut addrs = addr.to_socket_addrs()?;
99 let addr = addrs.next().ok_or(IoError::new(
100 IoErrorKind::AddrNotAvailable,
101 "No addresses found for the provided address"
102 ))?;
103
104 log::debug!("Binding to {}", addr);
105 self.address = Some(addr);
106 Ok(self)
107 }
108 /// Sets the state of the application.
109 ///
110 /// If your application requires a state, you must set it using this method.
111 ///
112 /// # Example
113 ///
114 /// ```rust
115 /// # use catalyzer::*;
116 /// struct AppState {
117 /// counter: u32,
118 /// }
119 ///
120 /// # #[main]
121 /// # fn main() -> Result {
122 /// let app = App::new()
123 /// .set_state(AppState { counter: 0 });
124 /// # }
125 pub fn set_state<S2>(self, state: State) -> App<S2> {
126 App {
127 router: self.router.with_state::<S2>(state),
128 address: self.address,
129 https_address: self.https_address,
130 }
131 }
132 /// Mounts a service on the application.
133 ///
134 /// This requires a service that implements the [`CatalyzerService`] trait.
135 pub fn service<S>(mut self, service: S) -> Self where
136 S: CatalyzerService + Clone + Send + 'static,
137 S::Response: IntoRawResponse,
138 S::Future: Send + 'static,
139 {
140 self.router = self.router.route_service(S::PATH, service);
141 self
142 }
143 /// Reveals the inner router of the application.
144 ///
145 /// This is used for advanced use-cases where you need to access the inner
146 /// router of the application (e.g. for mounting a sub-application or service).
147 pub fn inner<S2>(self, mapper: fn(AxumRouter<State>) -> AxumRouter<S2>) -> App<S2> {
148 App {
149 router: mapper(self.router),
150 address: self.address,
151 https_address: self.https_address,
152 }
153 }
154 /// Automatically configures the application.
155 ///
156 /// This is only available in debug builds.
157 ///
158 /// This is called by the `catalyze!` macro.
159 #[doc(hidden)]
160 #[cfg(debug_assertions)]
161 pub fn __auto_configure(self) -> Result<Self> {
162 self.bind("0.0.0.0:3000")
163 }
164}