objectstore_server/web/
app.rs1use std::net::SocketAddr;
2
3use anyhow::Result;
4use axum::ServiceExt;
5use axum::extract::Request;
6use objectstore_log::Level;
7use sentry::integrations::tower::{NewSentryLayer, SentryHttpLayer};
8use tokio::net::TcpListener;
9use tower::ServiceBuilder;
10use tower_http::catch_panic::CatchPanicLayer;
11use tower_http::trace::{DefaultOnFailure, TraceLayer};
12
13use crate::endpoints;
14use crate::state::ServiceState;
15use crate::web::middleware as m;
16
17#[derive(Debug)]
19pub struct App {
20 router: axum::Router,
21 graceful_shutdown: bool,
22}
23
24impl App {
25 pub fn new(state: ServiceState) -> Self {
30 let middleware = ServiceBuilder::new()
35 .layer(axum::middleware::from_fn(m::capture_request_time))
36 .layer(NewSentryLayer::new_from_top())
37 .layer(SentryHttpLayer::new().enable_transaction())
38 .layer(axum::middleware::from_fn(m::emit_request_metrics))
39 .layer(axum::middleware::from_fn(m::bind_sentry_body))
40 .layer(axum::middleware::from_fn_with_state(
41 state.request_counter.clone(),
42 m::limit_web_concurrency,
43 ))
44 .layer(state.request_counter.layer())
45 .layer(CatchPanicLayer::custom(m::handle_panic))
46 .layer(m::set_server_header())
47 .layer(
48 TraceLayer::new_for_http()
49 .make_span_with(m::make_http_span)
50 .on_failure(DefaultOnFailure::new().level(Level::DEBUG)),
51 );
52
53 let router = endpoints::routes()
54 .layer(middleware)
55 .with_state(state.clone());
56
57 App {
58 router,
59 graceful_shutdown: false,
60 }
61 }
62
63 pub fn graceful_shutdown(mut self, enable: bool) -> Self {
67 self.graceful_shutdown = enable;
68 self
69 }
70
71 pub async fn serve(self, listener: TcpListener) -> Result<()> {
76 let Self {
77 router,
78 graceful_shutdown,
79 } = self;
80
81 let service =
82 ServiceExt::<Request>::into_make_service_with_connect_info::<SocketAddr>(router);
83
84 if graceful_shutdown {
85 let guard = elegant_departure::get_shutdown_guard();
86 axum::serve(listener, service)
87 .with_graceful_shutdown(guard.wait_owned())
88 .await?;
89 } else {
90 axum::serve(listener, service).await?;
91 }
92
93 Ok(())
94 }
95}