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