use std::collections::HashMap;
use std::convert::Infallible;
use std::sync::{Arc, Mutex};
use hyper::server::Server;
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Method, Request, Response};
use tower::util::BoxCloneService;
use tower::Service as _;
async fn index(_req: Request<Body>) -> hyper::Result<Response<Body>> {
Ok(Response::new(Body::from("Hello, world!")))
}
async fn blog(_req: Request<Body>) -> hyper::Result<Response<Body>> {
Ok(Response::new(Body::from("...")))
}
async fn not_found(_req: Request<Body>) -> hyper::Result<Response<Body>> {
Ok(Response::builder().status(404).body(Body::empty()).unwrap())
}
type Service = Mutex<BoxCloneService<Request<Body>, Response<Body>, hyper::Error>>;
type Router = HashMap<Method, matchit::Router<Service>>;
async fn route(router: Arc<Router>, req: Request<Body>) -> hyper::Result<Response<Body>> {
let router = match router.get(req.method()) {
Some(router) => router,
None => return Ok(Response::builder().status(405).body(Body::empty()).unwrap()),
};
match router.at(req.uri().path()) {
Ok(found) => {
let mut service = found.value.lock().unwrap().clone();
service.call(req).await
}
Err(_) => not_found(req).await,
}
}
#[tokio::main]
async fn main() {
let mut router = Router::new();
router
.entry(Method::GET)
.or_default()
.insert("/", BoxCloneService::new(service_fn(index)).into())
.unwrap();
router
.entry(Method::GET)
.or_default()
.insert("/blog", BoxCloneService::new(service_fn(blog)).into())
.unwrap();
let router = Arc::new(router);
let make_service = make_service_fn(|_| {
let router = router.clone();
async { Ok::<_, Infallible>(service_fn(move |request| route(router.clone(), request))) }
});
Server::bind(&([127, 0, 0, 1], 3000).into())
.serve(make_service)
.await
.unwrap()
}