-
Notifications
You must be signed in to change notification settings - Fork 105
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs(example): add an example for server using auto conn (#110)
- Loading branch information
1 parent
99b77a5
commit 16daef6
Showing
2 changed files
with
78 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
//! This example runs a server that responds to any request with "Hello, world!" | ||
|
||
use std::{convert::Infallible, error::Error}; | ||
|
||
use bytes::Bytes; | ||
use http::{header::CONTENT_TYPE, Request, Response}; | ||
use http_body_util::{combinators::BoxBody, BodyExt, Full}; | ||
use hyper::{body::Incoming, service::service_fn}; | ||
use hyper_util::{ | ||
rt::{TokioExecutor, TokioIo}, | ||
server::conn::auto::Builder, | ||
}; | ||
use tokio::{net::TcpListener, task::JoinSet}; | ||
|
||
/// Function from an incoming request to an outgoing response | ||
/// | ||
/// This function gets turned into a [`hyper::service::Service`] later via | ||
/// [`service_fn`]. Instead of doing this, you could also write a type that | ||
/// implements [`hyper::service::Service`] directly and pass that in place of | ||
/// writing a function like this and calling [`service_fn`]. | ||
/// | ||
/// This function could use [`Full`] as the body type directly since that's | ||
/// the only type that can be returned in this case, but this uses [`BoxBody`] | ||
/// anyway for demonstration purposes, since this is what's usually used when | ||
/// writing a more complex webserver library. | ||
async fn handle_request( | ||
_request: Request<Incoming>, | ||
) -> Result<Response<BoxBody<Bytes, Infallible>>, Infallible> { | ||
let response = Response::builder() | ||
.header(CONTENT_TYPE, "text/plain") | ||
.body(Full::new(Bytes::from("Hello, world!\n")).boxed()) | ||
.expect("values provided to the builder should be valid"); | ||
|
||
Ok(response) | ||
} | ||
|
||
#[tokio::main(flavor = "current_thread")] | ||
async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> { | ||
let listen_addr = "127.0.0.1:8000"; | ||
let tcp_listener = TcpListener::bind(listen_addr).await?; | ||
println!("listening on http://{listen_addr}"); | ||
|
||
let mut join_set = JoinSet::new(); | ||
loop { | ||
let (stream, addr) = match tcp_listener.accept().await { | ||
Ok(x) => x, | ||
Err(e) => { | ||
eprintln!("failed to accept connection: {e}"); | ||
continue; | ||
} | ||
}; | ||
|
||
let serve_connection = async move { | ||
println!("handling a request from {addr}"); | ||
|
||
let result = Builder::new(TokioExecutor::new()) | ||
.serve_connection(TokioIo::new(stream), service_fn(handle_request)) | ||
.await; | ||
|
||
if let Err(e) = result { | ||
eprintln!("error serving {addr}: {e}"); | ||
} | ||
|
||
println!("handled a request from {addr}"); | ||
}; | ||
|
||
join_set.spawn(serve_connection); | ||
} | ||
|
||
// If you add a method for breaking the above loop (i.e. graceful shutdown), | ||
// then you may also want to wait for all existing connections to finish | ||
// being served before terminating the program, which can be done like this: | ||
// | ||
// while let Some(_) = join_set.join_next().await {} | ||
} |