22
33use std:: any:: Any ;
44use std:: io;
5+ use std:: net:: SocketAddr ;
56use std:: sync:: Arc ;
67
8+ use anyhow:: Result ;
79use axum:: body:: { Body , to_bytes} ;
810use axum:: extract:: { Path , Request , State } ;
911use axum:: http:: { HeaderMap , StatusCode } ;
@@ -16,34 +18,81 @@ use objectstore_service::{ObjectKey, StorageService};
1618use objectstore_types:: Metadata ;
1719use sentry:: integrations:: tower as sentry_tower;
1820use serde:: Serialize ;
21+ use tokio:: net:: { TcpListener , TcpSocket } ;
22+ use tower:: ServiceBuilder ;
23+ use tower_http:: catch_panic:: CatchPanicLayer ;
24+ use tower_http:: trace:: { DefaultOnFailure , TraceLayer } ;
25+ use tracing:: Level ;
1926use uuid:: Uuid ;
2027
2128use crate :: authentication:: { Claim , ExtractScope , Permission } ;
2229use crate :: config:: Config ;
2330use crate :: state:: ServiceState ;
2431
25- pub async fn start_server ( state : ServiceState ) {
26- let sentry_tower_service = state. config . sentry_dsn . as_ref ( ) . map ( |_| {
27- tower:: ServiceBuilder :: new ( )
28- . layer ( sentry_tower:: NewSentryLayer :: < Request > :: new_from_top ( ) )
29- . layer ( sentry_tower:: SentryHttpLayer :: new ( ) . enable_transaction ( ) )
30- } ) ;
31- let http_addr = state. config . http_addr ;
32+ const TCP_LISTEN_BACKLOG : u32 = 1024 ;
33+
34+ fn make_app ( state : ServiceState ) -> axum:: Router {
35+ let middleware = ServiceBuilder :: new ( )
36+ . layer ( CatchPanicLayer :: custom ( handle_panic) )
37+ . layer ( sentry_tower:: NewSentryLayer :: < Request > :: new_from_top ( ) )
38+ . layer ( sentry_tower:: SentryHttpLayer :: new ( ) . enable_transaction ( ) )
39+ . layer ( TraceLayer :: new_for_http ( ) . on_failure ( DefaultOnFailure :: new ( ) . level ( Level :: DEBUG ) ) ) ;
3240
33- let app = Router :: new ( )
41+ let routes = Router :: new ( )
3442 . route ( "/" , put ( put_blob) )
35- . route ( "/{*key}" , get ( get_blob) . delete ( delete_blob) )
36- . layer ( option_layer ( sentry_tower_service) )
37- . with_state ( state)
38- . into_make_service ( ) ;
43+ . route ( "/{*key}" , get ( get_blob) . delete ( delete_blob) ) ;
44+
45+ routes. layer ( middleware) . with_state ( state)
46+ }
47+
48+ /// Handler function for the [`CatchPanicLayer`] middleware.
49+ fn handle_panic ( err : Box < dyn Any + Send + ' static > ) -> Response {
50+ let detail = if let Some ( s) = err. downcast_ref :: < String > ( ) {
51+ s. clone ( )
52+ } else if let Some ( s) = err. downcast_ref :: < & str > ( ) {
53+ s. to_string ( )
54+ } else {
55+ "no error details" . to_owned ( )
56+ } ;
57+
58+ tracing:: error!( "panic in web handler: {detail}" ) ;
59+
60+ let response = ( StatusCode :: INTERNAL_SERVER_ERROR , detail) ;
61+ response. into_response ( )
62+ }
63+
64+ fn listen ( config : & Config ) -> Result < TcpListener > {
65+ let addr = config. http_addr ;
66+ let socket = match addr {
67+ SocketAddr :: V4 ( _) => TcpSocket :: new_v4 ( ) ,
68+ SocketAddr :: V6 ( _) => TcpSocket :: new_v6 ( ) ,
69+ } ?;
3970
40- tracing:: info!( "HTTP server listening on {http_addr}" ) ;
71+ #[ cfg( all( unix, not( target_os = "solaris" ) , not( target_os = "illumos" ) ) ) ]
72+ socket. set_reuseport ( true ) ?;
73+ socket. bind ( addr) ?;
74+
75+ let listener = socket. listen ( TCP_LISTEN_BACKLOG ) ?;
76+ tracing:: info!( "HTTP server listening on {addr}" ) ;
77+
78+ Ok ( listener)
79+ }
80+
81+ async fn serve ( listener : TcpListener , app : axum:: Router ) -> Result < ( ) > {
4182 let guard = elegant_departure:: get_shutdown_guard ( ) . shutdown_on_drop ( ) ;
42- let listener = tokio:: net:: TcpListener :: bind ( http_addr) . await . unwrap ( ) ;
43- axum:: serve ( listener, app)
83+ axum:: serve ( listener, app. into_make_service ( ) )
4484 . with_graceful_shutdown ( guard. wait_owned ( ) )
45- . await
46- . unwrap ( ) ;
85+ . await ?;
86+
87+ Ok ( ( ) )
88+ }
89+
90+ pub async fn server ( state : ServiceState ) -> Result < ( ) > {
91+ let http_addr = state. config . http_addr ;
92+ let listener = listen ( & state. config ) ?;
93+
94+ let app = make_app ( state) ;
95+ serve ( listener, app) . await
4796}
4897
4998#[ derive( Debug , Serialize ) ]
0 commit comments