1- use axum:: { routing:: get, serve, Router } ;
1+ use axum:: { extract :: State , routing:: get, serve, Router } ;
22use hyper:: header:: HeaderMap ;
33use redb:: { Database , ReadableTable , TableDefinition } ;
44use serde:: { Deserialize , Serialize } ;
@@ -17,6 +17,13 @@ use crate::lib::http;
1717
1818static GLOBALS : TableDefinition < u64 , u64 > = TableDefinition :: new ( "globals" ) ;
1919
20+ #[ derive( Clone ) ]
21+ struct AppState {
22+ redb : Arc < Database > ,
23+ counter_runs : u64 ,
24+ shutdown_tx : mpsc:: Sender < ( ) > ,
25+ }
26+
2027#[ derive( Serialize , Deserialize , Debug ) ]
2128#[ serde( tag = "type" ) ]
2229enum JSONResponse {
@@ -25,13 +32,24 @@ enum JSONResponse {
2532 Counters { counter_runs : u64 , counter_requests : u64 } ,
2633}
2734
28- #[ tokio:: main]
29- async fn main ( ) -> Result < ( ) , Box < dyn Error > > {
30- fs:: create_dir_all ( & Path :: new ( "./.db" ) ) ?;
31- let redb = Arc :: new ( Database :: create ( "./.db/demo.redb" ) ?) ;
32- let initial_counter_runs_value = inc_counter ( & redb, 1 ) . await ?;
33- run_main ( redb, initial_counter_runs_value) . await ;
34- Ok ( ( ) )
35+ async fn health_handler ( ) -> & ' static str {
36+ "OK\n "
37+ }
38+
39+ async fn hello_handler ( ) -> & ' static str {
40+ "hello this is a rust http server\n "
41+ }
42+
43+ async fn quit_handler ( State ( state) : State < AppState > ) -> & ' static str {
44+ let _ = state. shutdown_tx . send ( ( ) ) . await ;
45+ "yes i am shutting down\n "
46+ }
47+
48+ async fn json_handler ( State ( state) : State < AppState > , headers : HeaderMap ) -> impl axum:: response:: IntoResponse {
49+ let counter_requests = inc_counter ( & state. redb , 2 ) . await . unwrap_or ( 0 ) ;
50+ let response = JSONResponse :: Counters { counter_runs : state. counter_runs , counter_requests } ;
51+ let json_string = serde_json:: to_string ( & response) . unwrap ( ) ;
52+ http:: json_or_html ( headers, & json_string) . await
3553}
3654
3755async fn inc_counter ( redb : & Database , idx : u64 ) -> Result < u64 , Box < dyn Error > > {
@@ -50,34 +68,25 @@ async fn inc_counter(redb: &Database, idx: u64) -> Result<u64, Box<dyn Error>> {
5068 Ok ( counter_runs)
5169}
5270
53- async fn run_main ( redb : Arc < Database > , counter_runs : u64 ) {
71+ #[ tokio:: main]
72+ async fn main ( ) -> Result < ( ) , Box < dyn Error > > {
73+ fs:: create_dir_all ( & Path :: new ( "./.db" ) ) ?;
74+ let redb = Arc :: new ( Database :: create ( "./.db/demo.redb" ) ?) ;
75+ let initial_counter_runs_value = inc_counter ( & redb, 1 ) . await ?;
76+
5477 let ( shutdown_tx, mut shutdown_rx) = mpsc:: channel :: < ( ) > ( 1 ) ;
78+ let state = AppState {
79+ redb : redb. clone ( ) ,
80+ counter_runs : initial_counter_runs_value,
81+ shutdown_tx : shutdown_tx. clone ( ) ,
82+ } ;
5583
5684 let app = Router :: new ( )
57- . route ( "/healthz" , get ( || async { "OK\n " } ) )
58- . route ( "/" , get ( || async { "hello this is a rust http server\n " } ) )
59- . route (
60- "/quit" ,
61- get ( {
62- let shutdown_tx = shutdown_tx. clone ( ) ;
63- || async move {
64- let _ = shutdown_tx. send ( ( ) ) . await ;
65- "yes i am shutting down\n "
66- }
67- } ) ,
68- )
69- . route (
70- "/json" ,
71- get ( move |headers : HeaderMap | {
72- let counter_runs = counter_runs;
73- async move {
74- let counter_requests = inc_counter ( & redb, 2 ) . await . unwrap_or ( 0 ) ;
75- let response = JSONResponse :: Counters { counter_runs, counter_requests } ;
76- let json_string = serde_json:: to_string ( & response) . unwrap ( ) ;
77- http:: json_or_html ( headers, & json_string) . await
78- }
79- } ) ,
80- ) ;
85+ . route ( "/healthz" , get ( health_handler) )
86+ . route ( "/" , get ( hello_handler) )
87+ . route ( "/quit" , get ( quit_handler) )
88+ . route ( "/json" , get ( json_handler) )
89+ . with_state ( state) ;
8190
8291 let addr = SocketAddr :: from ( ( [ 0 , 0 , 0 , 0 ] , 3000 ) ) ;
8392 let listener = TcpListener :: bind ( addr) . await . unwrap ( ) ;
@@ -90,11 +99,12 @@ async fn run_main(redb: Arc<Database>, counter_runs: u64) {
9099 let mut int_signal = signal ( SignalKind :: interrupt ( ) ) . expect ( "failed to register SIGINT handler" ) ;
91100
92101 tokio:: select! {
93- _ = server. with_graceful_shutdown( async move { shutdown_rx. recv( ) . await ; } ) => { println! ( "done" ) ; }
102+ _ = server. with_graceful_shutdown( async move { shutdown_rx. recv( ) . await ; } ) => { println!( "done" ) ; }
94103 _ = tokio:: signal:: ctrl_c( ) => { println!( "terminating due to Ctrl+C" ) ; }
95104 _ = term_signal. recv( ) => { println!( "terminating due to SIGTERM" ) ; }
96105 _ = int_signal. recv( ) => { println!( "terminating due to SIGINT" ) ; }
97106 }
98107
99108 println ! ( "rust http server down" ) ;
109+ Ok ( ( ) )
100110}
0 commit comments