Skip to main content

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}