use futures::future::{self, FutureObj};
use http_service::HttpService;
use std::{
any::Any,
fmt::Debug,
ops::{Deref, DerefMut},
sync::Arc,
};
use crate::{
configuration::{Configuration, Store},
endpoint::BoxedEndpoint,
endpoint::Endpoint,
extract::Extract,
middleware::{logger::RootLogger, RequestContext},
router::{EndpointData, Resource, RouteResult, Router},
Middleware, Request, Response, RouteMatch,
};
pub struct App<Data> {
data: Data,
router: Router<Data>,
default_handler: EndpointData<Data>,
}
impl<Data: Clone + Send + Sync + 'static> App<Data> {
pub fn new(data: Data) -> App<Data> {
let logger = RootLogger::new();
let mut app = App {
data,
router: Router::new(),
default_handler: EndpointData {
endpoint: BoxedEndpoint::new(async || http::status::StatusCode::NOT_FOUND),
store: Store::new(),
},
};
app.middleware(logger);
app.setup_configuration();
app
}
fn setup_configuration(&mut self) {
let config = Configuration::build().finalize();
self.config(config);
}
pub fn router(&mut self) -> &mut Router<Data> {
&mut self.router
}
pub fn at<'a>(&'a mut self, path: &'a str) -> Resource<'a, Data> {
self.router.at(path)
}
pub fn default_handler<T: Endpoint<Data, U>, U>(
&mut self,
handler: T,
) -> &mut EndpointData<Data> {
let endpoint = EndpointData {
endpoint: BoxedEndpoint::new(handler),
store: self.router.store_base.clone(),
};
self.default_handler = endpoint;
&mut self.default_handler
}
pub fn middleware(&mut self, middleware: impl Middleware<Data> + 'static) -> &mut Self {
self.router.middleware(middleware);
self
}
pub fn config<T: Any + Debug + Clone + Send + Sync>(&mut self, item: T) -> &mut Self {
self.router.config(item);
self
}
pub fn get_item<T: Any + Debug + Clone + Send + Sync>(&self) -> Option<&T> {
self.router.get_item()
}
pub fn into_http_service(mut self) -> Server<Data> {
self.router.apply_default_config();
Server {
data: self.data,
router: Arc::new(self.router),
default_handler: Arc::new(self.default_handler),
}
}
#[cfg(feature = "hyper")]
pub fn serve(self) {
let configuration = self.get_item::<Configuration>().unwrap();
let addr = format!("{}:{}", configuration.address, configuration.port)
.parse::<std::net::SocketAddr>()
.unwrap();
println!("Server is listening on: http://{}", addr);
crate::serve::serve(self.into_http_service(), addr);
}
}
#[derive(Clone)]
pub struct Server<Data> {
data: Data,
router: Arc<Router<Data>>,
default_handler: Arc<EndpointData<Data>>,
}
impl<Data> HttpService for Server<Data>
where
Data: Clone + Send + Sync + 'static,
{
type Connection = ();
type ConnectionFuture = future::Ready<Result<(), std::io::Error>>;
type Fut = FutureObj<'static, Result<http_service::Response, std::io::Error>>;
fn connect(&self) -> Self::ConnectionFuture {
future::ok(())
}
fn respond(&self, _conn: &mut (), req: http_service::Request) -> Self::Fut {
let data = self.data.clone();
let router = self.router.clone();
let default_handler = self.default_handler.clone();
let path = req.uri().path().to_owned();
let method = req.method().to_owned();
FutureObj::new(Box::new(
async move {
let RouteResult {
endpoint,
params,
middleware,
} = router.route(&path, &method, &default_handler);
let ctx = RequestContext {
app_data: data,
req,
params,
endpoint,
next_middleware: middleware,
};
Ok(await!(ctx.next()))
},
))
}
}
pub struct AppData<T>(pub T);
impl<T> Deref for AppData<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> DerefMut for AppData<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T: Clone + Send + 'static> Extract<T> for AppData<T> {
type Fut = future::Ready<Result<Self, Response>>;
fn extract(
data: &mut T,
req: &mut Request,
params: &Option<RouteMatch<'_>>,
store: &Store,
) -> Self::Fut {
future::ok(AppData(data.clone()))
}
}