Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update to hyper 1 #55

Merged
merged 2 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ routefinder = "0.5.2"
# examples
tower = { version = "0.4", features = ["make", "util"] }
tokio = { version = "1", features = ["full"] }
hyper = { version = "0.14", features = ["full"] }
http-body-util = "0.1"
hyper = { version = "1", features = ["http1", "server"] }
hyper-util = { version = "0.1", features = ["tokio"] }

[features]
default = []
Expand Down
63 changes: 43 additions & 20 deletions examples/hyper.rs
Original file line number Diff line number Diff line change
@@ -1,44 +1,57 @@
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 http_body_util::Full;
use hyper::body::{Bytes, Incoming};
use hyper::server::conn::http1::Builder as ConnectionBuilder;
use hyper::{Method, Request, Response};
use hyper_util::rt::TokioIo;
use tokio::net::TcpListener;
use tower::service_fn;
use tower::util::BoxCloneService;
use tower::Service as _;

type Body = Full<Bytes>;

// GET /
async fn index(_req: Request<Body>) -> hyper::Result<Response<Body>> {
async fn index(_req: Request<Incoming>) -> hyper::Result<Response<Body>> {
Ok(Response::new(Body::from("Hello, world!")))
}

// GET /blog
async fn blog(_req: Request<Body>) -> hyper::Result<Response<Body>> {
async fn blog(_req: Request<Incoming>) -> hyper::Result<Response<Body>> {
Ok(Response::new(Body::from("...")))
}

// 404 handler
async fn not_found(_req: Request<Body>) -> hyper::Result<Response<Body>> {
Ok(Response::builder().status(404).body(Body::empty()).unwrap())
async fn not_found(_req: Request<Incoming>) -> hyper::Result<Response<Body>> {
Ok(Response::builder()
.status(404)
.body(Body::default())
.unwrap())
}

// We can use `BoxCloneService` to erase the type of each handler service.
//
// We still need a `Mutex` around each service because `BoxCloneService` doesn't
// require the service to implement `Sync`.
type Service = Mutex<BoxCloneService<Request<Body>, Response<Body>, hyper::Error>>;
type Service = Mutex<BoxCloneService<Request<Incoming>, Response<Body>, hyper::Error>>;

// We use a `HashMap` to hold a `Router` for each HTTP method. This allows us
// to register the same route for multiple methods.
type Router = HashMap<Method, matchit::Router<Service>>;

async fn route(router: Arc<Router>, req: Request<Body>) -> hyper::Result<Response<Body>> {
async fn route(router: Arc<Router>, req: Request<Incoming>) -> hyper::Result<Response<Body>> {
// find the subrouter for this request method
let router = match router.get(req.method()) {
Some(router) => router,
// if there are no routes for this method, respond with 405 Method Not Allowed
None => return Ok(Response::builder().status(405).body(Body::empty()).unwrap()),
None => {
return Ok(Response::builder()
.status(405)
.body(Body::default())
.unwrap())
}
};

// find the service for this request path
Expand Down Expand Up @@ -72,16 +85,26 @@ async fn main() {
.insert("/blog", BoxCloneService::new(service_fn(blog)).into())
.unwrap();

let listener = TcpListener::bind(("127.0.0.1", 3000)).await.unwrap();

// boilerplate for the hyper service
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))) }
});

// run the server
Server::bind(&([127, 0, 0, 1], 3000).into())
.serve(make_service)
.await
.unwrap()
loop {
let router = router.clone();
let (tcp, _) = listener.accept().await.unwrap();
tokio::task::spawn(async move {
if let Err(err) = ConnectionBuilder::new()
.serve_connection(
TokioIo::new(tcp),
hyper::service::service_fn(|request| async {
route(router.clone(), request).await
}),
)
.await
{
println!("Error serving connection: {:?}", err);
}
});
}
}
Loading