use crate::{Error, Method, Middleware, Request, Response, Result, Router};
use std::future::Future;
use std::sync::Arc;
pub struct App {
router: Router,
middleware: Vec<Arc<dyn Middleware>>,
}
impl App {
pub fn new() -> Self {
Self {
router: Router::new(""),
middleware: Vec::new(),
}
}
pub fn get<F, Fut>(&mut self, path: &str, handler: F) -> &mut Self
where
F: Fn(Request) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<Response>> + Send + 'static,
{
self.router.get(path, handler);
self
}
pub fn post<F, Fut>(&mut self, path: &str, handler: F) -> &mut Self
where
F: Fn(Request) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<Response>> + Send + 'static,
{
self.router.post(path, handler);
self
}
pub fn put<F, Fut>(&mut self, path: &str, handler: F) -> &mut Self
where
F: Fn(Request) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<Response>> + Send + 'static,
{
self.router.put(path, handler);
self
}
pub fn delete<F, Fut>(&mut self, path: &str, handler: F) -> &mut Self
where
F: Fn(Request) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<Response>> + Send + 'static,
{
self.router.delete(path, handler);
self
}
pub fn patch<F, Fut>(&mut self, path: &str, handler: F) -> &mut Self
where
F: Fn(Request) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<Response>> + Send + 'static,
{
self.router.patch(path, handler);
self
}
pub fn use_middleware(&mut self, middleware: Arc<dyn Middleware>) -> &mut Self {
self.middleware.push(middleware);
self
}
pub fn mount(&mut self, prefix: &str, router: Router) -> &mut Self {
self.router.mount(prefix, router);
self
}
pub async fn handle_request(&self, mut req: Request) -> Result<Response> {
use crate::middleware::{Next};
let method = Method::from(req.method().clone());
let path = req.uri().path().to_string();
if let Some((route, params)) = self.router.find_route(&method, &path) {
for (key, value) in params {
req.set_param(key, value);
}
if self.middleware.is_empty() {
route.handle(req).await
} else {
let handler_fn = route.handler_fn();
let handler = Arc::new(move |req: Request| {
handler_fn(req)
});
let next = Next::new(self.middleware.clone(), Some(handler));
next.run(req).await
}
} else {
if self.router.path_exists(&path) {
let allowed = self.router.allowed_methods(&path);
let allowed_http: Vec<http::Method> = allowed.into_iter().map(|m| m.into()).collect();
Err(Error::MethodNotAllowed(allowed_http))
} else {
Err(Error::RouteNotFound)
}
}
}
pub fn router(&self) -> &Router {
&self.router
}
pub fn router_mut(&mut self) -> &mut Router {
&mut self.router
}
pub fn middleware(&self) -> &[Arc<dyn Middleware>] {
&self.middleware
}
pub async fn listen(self, addr: &str) -> Result<()> {
use hyper::server::conn::http1;
use hyper::service::service_fn;
use hyper_util::rt::TokioIo;
use tokio::net::TcpListener;
let addr = addr.parse::<std::net::SocketAddr>()
.map_err(|e| Error::InternalServerError(format!("Invalid address: {}", e)))?;
let listener = TcpListener::bind(addr)
.await
.map_err(|e| Error::InternalServerError(format!("Failed to bind: {}", e)))?;
println!("Ruffus server listening on http://{}", addr);
let app = Arc::new(self);
loop {
let (stream, _) = listener.accept()
.await
.map_err(|e| Error::InternalServerError(format!("Failed to accept connection: {}", e)))?;
let io = TokioIo::new(stream);
let app_clone = app.clone();
tokio::spawn(async move {
let service = service_fn(move |hyper_req: hyper::Request<hyper::body::Incoming>| {
let app = app_clone.clone();
async move {
let req = match Request::from_hyper(hyper_req).await {
Ok(req) => req,
Err(e) => {
let response: hyper::Response<http_body_util::Full<bytes::Bytes>> =
e.into_response().into();
return Ok::<_, hyper::Error>(response);
}
};
let response = match app.handle_request(req).await {
Ok(resp) => resp,
Err(e) => e.into_response(),
};
let hyper_response: hyper::Response<http_body_util::Full<bytes::Bytes>> =
response.into();
Ok::<_, hyper::Error>(hyper_response)
}
});
if let Err(err) = http1::Builder::new()
.serve_connection(io, service)
.await
{
eprintln!("Error serving connection: {:?}", err);
}
});
}
}
}
impl Default for App {
fn default() -> Self {
Self::new()
}
}