Skip to content

Instantly share code, notes, and snippets.

@theoparis
Last active March 1, 2023 16:46
Show Gist options
  • Save theoparis/39d1544c0fb6c63ca39b975d28d6fda8 to your computer and use it in GitHub Desktop.
Save theoparis/39d1544c0fb6c63ca39b975d28d6fda8 to your computer and use it in GitHub Desktop.
rust + hyper http dynamic routing
#![feature(async_closure)]
use crate::handler::router::handle;
use anyhow::Result;
use futures::future::FutureExt;
use handler::router::DynamicRouter;
use hyper::{
service::{make_service_fn, service_fn},
Body, Response, Server, StatusCode,
};
use matchit::Router;
use std::{
convert::Infallible,
net::{IpAddr, Ipv6Addr, SocketAddr},
sync::Arc,
};
use tokio::sync::Mutex;
use tracing::{error, info};
pub mod handler;
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt::init();
let addr = SocketAddr::new(IpAddr::V6(Ipv6Addr::LOCALHOST), 6969);
let router: Arc<Mutex<DynamicRouter>> = Arc::new(Mutex::new(Router::new()));
{
let mut router = router.lock().await;
router.insert(
"/404",
Box::new(|(parts, bytes)| {
Box::pin(async move {
Response::builder()
.status(StatusCode::NOT_FOUND)
.body(Body::from("404 Not Found"))
})
}),
)?;
router.insert(
"/",
Box::new(|(parts, bytes)| {
Box::pin(async move {
Response::builder()
.status(StatusCode::OK)
.body(Body::from("eeeeeee it works"))
})
}),
)?;
}
info!("Starting server on {}", addr);
let server = Server::bind(&addr).serve(make_service_fn(move |_conn| {
let router = router.clone();
async move {
Ok::<_, Infallible>(service_fn(move |req| {
handle(req, router.clone())
}))
}
}));
if let Err(e) = server.await {
error!("server error: {}", e);
}
Ok(())
}
use std::sync::Arc;
use anyhow::Result;
use futures::future::BoxFuture;
use hyper::{body::Bytes, http::request::Parts, Body, Request, Response};
use matchit::Router;
use tokio::sync::Mutex;
pub type RouteFn<'a> = Box<
dyn Send
+ Sync
+ Fn(
(Parts, Bytes),
) -> BoxFuture<'a, Result<Response<Body>, hyper::http::Error>>,
>;
pub type DynamicRouter<'a> = Router<RouteFn<'a>>;
pub async fn handle(
request: Request<Body>,
router: Arc<Mutex<DynamicRouter<'_>>>,
) -> Result<Response<Body>> {
let parts = request.into_parts();
let bytes = hyper::body::to_bytes(parts.1).await?;
let router = router.lock().await;
let handler = router.at(parts.0.uri.path());
match handler {
Ok(handler) => {
let response = (handler.value)((parts.0, bytes)).await?;
Ok(response)
}
Err(_) => {
let not_found_handler = router.at("/404").unwrap();
let response = (not_found_handler.value)((parts.0, bytes)).await?;
Ok(response)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment