use aws_smithy_http_server::{routing::IntoMakeService, serve::serve};
use http::{Request, Response};
use http_body_util::{BodyExt, Full};
use hyper::body::{Bytes, Incoming};
use std::{convert::Infallible, time::Duration};
use tokio::net::TcpListener;
use tower::service_fn;
use tracing::{info, warn};
async fn hello_handler(_req: Request<Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {
Ok(Response::new(Full::new(Bytes::from("Hello, World!\n"))))
}
async fn echo_handler(req: Request<Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {
let body = req.into_body();
let bytes = match body.collect().await {
Ok(collected) => collected.to_bytes(),
Err(e) => {
warn!("echo handler: error reading body: {}", e);
return Ok(Response::new(Full::new(Bytes::from("Error reading body\n"))));
}
};
info!("echo handler: received {} bytes", bytes.len());
if bytes.is_empty() {
Ok(Response::new(Full::new(Bytes::from("No body provided\n"))))
} else {
Ok(Response::new(Full::new(bytes)))
}
}
async fn router(req: Request<Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {
match req.uri().path() {
"/echo" => echo_handler(req).await,
_ => hello_handler(req).await,
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt::init();
info!("Starting server with aws_smithy_http_server::serve()...");
let listener = TcpListener::bind("0.0.0.0:3000").await?;
let local_addr = listener.local_addr()?;
info!("Server listening on http://{}", local_addr);
info!("Press Ctrl+C to shutdown gracefully");
let app = service_fn(router);
serve(listener, IntoMakeService::new(app))
.configure_hyper(|mut builder| {
builder
.http2()
.keep_alive_interval(Duration::from_secs(60))
.keep_alive_timeout(Duration::from_secs(20));
builder
})
.with_graceful_shutdown(async {
tokio::signal::ctrl_c().await.expect("failed to listen for Ctrl+C");
info!("Received Ctrl+C, shutting down gracefully...");
})
.await?;
Ok(())
}