11use axum:: {
22 body:: Bytes ,
3- error_handling:: HandleErrorLayer ,
4- extract:: { Extension , Path } ,
3+ extract:: { Path , State } ,
54 http:: { header, HeaderValue , StatusCode } ,
65 response:: IntoResponse ,
76 routing:: get,
8- BoxError , Router ,
7+ Router ,
98} ;
109use clap:: Parser ;
1110use std:: {
1211 collections:: HashMap ,
13- net:: SocketAddr ,
12+ net:: { Ipv4Addr , SocketAddr } ,
1413 sync:: { Arc , RwLock } ,
1514 time:: Duration ,
1615} ;
1716use tower:: ServiceBuilder ;
1817use tower_http:: {
18+ timeout:: TimeoutLayer ,
1919 trace:: { DefaultMakeSpan , DefaultOnResponse , TraceLayer } ,
2020 LatencyUnit , ServiceBuilderExt ,
2121} ;
@@ -29,7 +29,7 @@ struct Config {
2929}
3030
3131#[ derive( Clone , Debug ) ]
32- struct State {
32+ struct AppState {
3333 db : Arc < RwLock < HashMap < String , Bytes > > > ,
3434}
3535
@@ -42,31 +42,17 @@ async fn main() {
4242 let config = Config :: parse ( ) ;
4343
4444 // Run our service
45- let addr = SocketAddr :: from ( ( [ 0 , 0 , 0 , 0 ] , config. port ) ) ;
45+ let addr = SocketAddr :: from ( ( Ipv4Addr :: UNSPECIFIED , config. port ) ) ;
4646 tracing:: info!( "Listening on {}" , addr) ;
4747 axum:: Server :: bind ( & addr)
4848 . serve ( app ( ) . into_make_service ( ) )
4949 . await
5050 . expect ( "server error" ) ;
5151}
5252
53- async fn handle_errors ( err : BoxError ) -> impl IntoResponse {
54- if err. is :: < tower:: timeout:: error:: Elapsed > ( ) {
55- (
56- StatusCode :: REQUEST_TIMEOUT ,
57- "Request took too long" . to_string ( ) ,
58- )
59- } else {
60- (
61- StatusCode :: INTERNAL_SERVER_ERROR ,
62- format ! ( "Unhandled internal error: {}" , err) ,
63- )
64- }
65- }
66-
6753fn app ( ) -> Router {
6854 // Build our database for holding the key/value pairs
69- let state = State {
55+ let state = AppState {
7056 db : Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ,
7157 } ;
7258
@@ -86,12 +72,10 @@ fn app() -> Router {
8672 . on_response ( DefaultOnResponse :: new ( ) . include_headers ( true ) . latency_unit ( LatencyUnit :: Micros ) ) ,
8773 )
8874 . sensitive_response_headers ( sensitive_headers)
89- // Handle errors
90- . layer ( HandleErrorLayer :: new ( handle_errors) )
9175 // Set a timeout
92- . timeout ( Duration :: from_secs ( 10 ) )
93- // Share the state with each handler via a request extension
94- . add_extension ( state )
76+ . layer ( TimeoutLayer :: new ( Duration :: from_secs ( 10 ) ) )
77+ // Box the response body so it implements `Default` which is required by axum
78+ . map_response_body ( axum :: body :: boxed )
9579 // Compress responses
9680 . compression ( )
9781 // Set a `Content-Type` if there isn't one already.
@@ -103,10 +87,11 @@ fn app() -> Router {
10387 // Build route service
10488 Router :: new ( )
10589 . route ( "/:key" , get ( get_key) . post ( set_key) )
106- . layer ( middleware. into_inner ( ) )
90+ . layer ( middleware)
91+ . with_state ( state)
10792}
10893
109- async fn get_key ( path : Path < String > , state : Extension < State > ) -> impl IntoResponse {
94+ async fn get_key ( path : Path < String > , state : State < AppState > ) -> impl IntoResponse {
11095 let state = state. db . read ( ) . unwrap ( ) ;
11196
11297 if let Some ( value) = state. get ( & * path) . cloned ( ) {
@@ -116,7 +101,7 @@ async fn get_key(path: Path<String>, state: Extension<State>) -> impl IntoRespon
116101 }
117102}
118103
119- async fn set_key ( Path ( path) : Path < String > , state : Extension < State > , value : Bytes ) {
104+ async fn set_key ( Path ( path) : Path < String > , state : State < AppState > , value : Bytes ) {
120105 let mut state = state. db . write ( ) . unwrap ( ) ;
121106 state. insert ( path, value) ;
122107}
0 commit comments