drawbridge_server/
builder.rs1use super::{handle, App, Store, TlsConfig};
5use std::ops::Deref;
6
7use anyhow::{anyhow, Context};
8use async_std::fs::File;
9use async_std::path::Path;
10use async_std::sync::Arc;
11use axum::handler::Handler;
12use axum::routing::any;
13use axum::{Extension, Router};
14use cap_async_std::fs_utf8::Dir;
15use futures::lock::Mutex;
16use futures::TryFutureExt;
17use futures_rustls::TlsAcceptor;
18use openidconnect::url::Url;
19use tower_http::{
20 trace::{
21 DefaultOnBodyChunk, DefaultOnEos, DefaultOnFailure, DefaultOnRequest, DefaultOnResponse,
22 TraceLayer,
23 },
24 LatencyUnit,
25};
26use tracing::Level;
27
28#[derive(Debug)]
30pub struct OidcConfig {
31 pub audience: String,
32 pub issuer: Url,
33}
34
35#[derive(Debug, Clone, Default)]
36struct SpanMaker;
37
38impl<B> tower_http::trace::MakeSpan<B> for SpanMaker {
39 fn make_span(&mut self, request: &axum::http::request::Request<B>) -> tracing::span::Span {
40 let reqid = uuid::Uuid::new_v4();
41 tracing::span!(
42 Level::INFO,
43 "request",
44 method = %request.method(),
45 uri = %request.uri(),
46 version = ?request.version(),
47 headers = ?request.headers(),
48 request_id = %reqid,
49 )
50 }
51}
52
53pub struct Builder<S> {
55 store: S,
56 tls: TlsConfig,
57 oidc: OidcConfig,
58}
59
60impl<S: std::fmt::Debug> std::fmt::Debug for Builder<S> {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 f.debug_struct("Builder")
63 .field("store", &self.store)
64 .field("oidc", &self.oidc)
65 .finish()
66 }
67}
68
69impl<S: AsRef<Path>> Builder<S> {
70 pub fn new(store: S, tls: TlsConfig, oidc: OidcConfig) -> Self {
72 Self { store, tls, oidc }
73 }
74
75 pub async fn build(self) -> anyhow::Result<App> {
77 let Self { store, tls, oidc } = self;
78 let store_path = store.as_ref();
79 let store = File::open(store_path)
80 .and_then(|f| Store::new(Dir::from_std_file(f)))
81 .await
82 .context(anyhow!(
83 "failed to open store at `{}`",
84 store_path.to_string_lossy()
85 ))?;
86
87 let oidc_verifier =
88 crate::auth::OidcVerifier::new(oidc).context("failed to create OIDC verifier")?;
89
90 Ok(App {
91 make_service: Mutex::new(
92 Router::new()
93 .fallback(handle.into_service())
94 .route("/health", any(|| async {}))
95 .layer(Extension(Arc::new(store)))
96 .layer(Extension(Arc::new(oidc_verifier)))
97 .layer(
98 TraceLayer::new_for_http()
99 .make_span_with(SpanMaker)
100 .on_request(DefaultOnRequest::new().level(Level::INFO))
101 .on_response(
102 DefaultOnResponse::new()
103 .level(Level::INFO)
104 .latency_unit(LatencyUnit::Micros),
105 )
106 .on_body_chunk(DefaultOnBodyChunk::new())
107 .on_eos(
108 DefaultOnEos::new()
109 .level(Level::INFO)
110 .latency_unit(LatencyUnit::Micros),
111 )
112 .on_failure(
113 DefaultOnFailure::new()
114 .level(Level::INFO)
115 .latency_unit(LatencyUnit::Micros),
116 ),
117 )
118 .into_make_service(),
119 ),
120 tls: TlsAcceptor::from(Arc::new(tls.deref().clone())),
121 })
122 }
123}