use std::net::SocketAddr;
use std::sync::Arc;
use crate::middleware::{Middleware, Next};
use crate::router::{Router, Selection};
use crate::{Endpoint, Route};
pub struct Server {
router: Arc<Router>,
#[allow(clippy::rc_buffer)]
middleware: Arc<Vec<Arc<dyn Middleware>>>,
}
impl Server {
#[must_use]
pub fn new() -> Self {
Self {
router: Arc::new(Router::new()),
middleware: Arc::new(Vec::new()),
}
}
}
impl Default for Server {
fn default() -> Self {
Self::new()
}
}
impl Server {
pub fn at<'a>(&'a mut self, path: &str) -> Route<'a> {
let router = Arc::get_mut(&mut self.router)
.expect("Registering routes is not possible after the Server has started");
Route::new(router, path.to_owned())
}
pub fn with(&mut self, middleware: impl Middleware + 'static) -> &mut Self
{
tracing::trace!("Adding middleware {}", middleware.name());
let m = Arc::get_mut(&mut self.middleware)
.expect("Registering middleware is not possible after the Server has started");
m.push(Arc::new(middleware));
self
}
pub async fn respond<Req, Res>(self, req: Req) -> hyper::Result<Res>
where
Req: Into<hyper::Request<hyper::Body>>,
Res: From<hyper::Response<hyper::Body>>,
{
let req: hyper::Request<hyper::Body> = req.into();
let Self {
router,
middleware,
} = self.clone();
let method = req.method().to_owned();
let Selection { endpoint, params } = router.route(req.uri().path(), method);
let route_params = vec![params];
let mut ctx = crate::Context::new(req, route_params);
let next = Next::new(endpoint, middleware);
match next.run(&mut ctx).await {
Ok(res) => Ok(res.into()),
Err(e) => {
let res = hyper::Response::builder()
.status(hyper::StatusCode::INTERNAL_SERVER_ERROR)
.body(hyper::Body::from(format!("{}", e)))
.unwrap();
Ok(res.into())
}
}
}
pub async fn listen(self, port: u16) -> Result<(), crate::Error> {
let addr = SocketAddr::from(([127, 0, 0, 1], port));
let make_svc = hyper::service::make_service_fn(move |_conn|{
let server = self.clone();
async move {
Ok::<_, hyper::Error>(hyper::service::service_fn(move |req| server.clone().respond(req)))
}
});
let server = hyper::Server::bind(&addr).serve(make_svc);
server.await?;
Ok(())
}
}
impl std::fmt::Debug for Server {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Server").finish()
}
}
impl Clone for Server {
fn clone(&self) -> Self {
Self {
router: self.router.clone(),
middleware: self.middleware.clone(),
}
}
}
#[async_trait::async_trait]
impl Endpoint for Server
{
async fn call(&self, ctx: &mut crate::Context) -> crate::Result {
let path = ctx.req.uri().path().to_owned();
let method = ctx.req.method().to_owned();
let router = self.router.clone();
let middleware = self.middleware.clone();
let Selection { endpoint, params } = router.route(&path, method);
ctx.params.push(params);
let next = Next::new(endpoint, middleware);
next.run(ctx).await
}
}
#[cfg(test)]
mod test {
use crate as envoy;
#[test]
fn allow_nested_server_with_same_state() {
let inner = envoy::new();
let mut outer = envoy::new();
outer.at("/foo").get(inner);
}
}