// This is an async port of `examples/simple_server.rs`. Please see that example first. // // Features `async` and `tokio-net` must be enabled for this example to compile. // It is also possible to enable feature `full` (which will enable all the features). use std::{collections::HashMap, net::SocketAddr}; use tokio::net::{TcpListener, TcpStream}; use inferium::{ h1::{ProtocolVariant, Request, ResponseHead, ServerSendError, AsyncServer}, HeaderKey, Method, Status, TokioInet }; #[tokio::main] async fn main() { let listener = TcpListener::bind("localhost:8080").await.unwrap(); loop { let (conn, addr) = listener.accept().await.unwrap(); // Here we are creating a new asynchronous task for every client. // This will fork off in an asynchronous manner and won't block our accept loop. tokio::task::spawn(async move { // We created this new async block, so we need to `.await` on this function to propagate // the future from the function to the top of the spawned task (this async block). handle_client(conn, addr).await; }); // You can now handle multiple clients at once... congratulations. } } async fn handle_client(conn: TcpStream, addr: SocketAddr) { println!("connection from {addr:?}"); let mut server_handler = AsyncServer::::new(TokioInet::new(conn)); // When receiving or sending - we call the same functions with `.await` appended (in an async // context). This will automatically poll the returned future from the top of the context. // The polling is handled by tokio here - so we don't need to worry about it. while let Ok(request) = server_handler.receive_request().await { match handle_request(request, addr) { Ok((h, b)) => if let Err(_) = send_response(h, b, &mut server_handler).await { break; }, Err(()) => break, } }; println!("ended connection for {addr:?}"); } fn handle_request( req: Request, addr: SocketAddr ) -> Result<(ResponseHead, &'static [u8]), ()> { let Request::HeadersOnly(headers) = req else { return Err(()); }; println!("req from {addr:?}: {headers}"); const OK_RESPONSE: &[u8] = b"

Hello, world!

Hello from inferium.

"; const NOT_FOUND_RESPONSE: &[u8] = b"

Not found

This page was not found

"; Ok(match (headers.method(), headers.uri().path()) { (&Method::GET, "/") => (ResponseHead::new( Status::Ok, ProtocolVariant::HTTP1_0, HashMap::from([ (HeaderKey::SERVER, "inferium".parse().unwrap()), (HeaderKey::CONTENT_LENGTH, OK_RESPONSE.len().into()), ]) ), OK_RESPONSE), _ => (ResponseHead::new( Status::NotFound, ProtocolVariant::HTTP1_0, HashMap::from([ (HeaderKey::SERVER, "inferium".parse().unwrap()), (HeaderKey::CONTENT_LENGTH, NOT_FOUND_RESPONSE.len().into()), ]) ), NOT_FOUND_RESPONSE), }) } async fn send_response( response: ResponseHead, body: &[u8], conn: &mut AsyncServer )-> Result<(), ServerSendError> { conn.send_response(&response).await?; conn.send_body_bytes(body).await.map_err(|e| e.try_into().unwrap()) }