1#![forbid(unsafe_code)]
5#![deny(
6 clippy::all,
7 absolute_paths_not_starting_with_crate,
8 deprecated_in_future,
9 missing_copy_implementations,
10 missing_debug_implementations,
11 noop_method_call,
12 rust_2018_compatibility,
13 rust_2018_idioms,
14 rust_2021_compatibility,
15 single_use_lifetimes,
16 trivial_bounds,
17 trivial_casts,
18 trivial_numeric_casts,
19 unreachable_code,
20 unreachable_patterns,
21 unreachable_pub,
22 unstable_features,
23 unused,
24 unused_crate_dependencies,
25 unused_import_braces,
26 unused_lifetimes,
27 unused_results,
28 variant_size_differences
29)]
30
31mod builder;
32mod handle;
33
34pub mod auth;
35pub mod repos;
36pub mod store;
37pub mod tags;
38pub mod trees;
39pub mod users;
40
41pub use auth::{OidcClaims, ScopeContext, ScopeLevel, TlsConfig, TrustedCertificate};
42pub use builder::*;
43pub(crate) use handle::*;
44pub(crate) use store::*;
45
46pub use openidconnect::url;
47
48use anyhow::Context as _;
49use async_std::path::Path;
50use axum::extract::Extension;
51use axum::routing::IntoMakeService;
52use axum::Router;
53use futures::lock::Mutex;
54use futures::{AsyncRead, AsyncWrite};
55use futures_rustls::TlsAcceptor;
56use hyper::server::conn::Http;
57use tokio_util::compat::FuturesAsyncReadCompatExt;
58use tower::MakeService;
59use tracing::trace;
60
61#[allow(missing_debug_implementations)] pub struct App {
63 make_service: Mutex<IntoMakeService<Router>>,
64 tls: TlsAcceptor,
65}
66
67impl App {
68 pub fn builder<S: AsRef<Path>>(store: S, tls: TlsConfig, oidc: OidcConfig) -> Builder<S> {
69 Builder::new(store, tls, oidc)
70 }
71
72 pub async fn new(
73 store: impl AsRef<Path>,
74 tls: TlsConfig,
75 oidc: OidcConfig,
76 ) -> anyhow::Result<Self> {
77 Self::builder(store, tls, oidc).build().await
78 }
79
80 pub async fn handle(
81 &self,
82 stream: impl 'static + Unpin + AsyncRead + AsyncWrite,
83 ) -> anyhow::Result<()> {
84 trace!(target: "app::App::handle", "begin TLS handshake");
85 let stream = self
86 .tls
87 .accept(stream)
88 .await
89 .context("failed to accept TLS connection")?;
90 trace!(target: "app::App::handle", "completed TLS handshake");
91
92 let mut svc = self
93 .make_service
94 .lock()
95 .await
96 .make_service(())
97 .await
98 .context("failed to create app service")?;
99 let (_, conn) = stream.get_ref();
100 if conn.peer_certificates().is_some() {
101 svc = svc.layer(Extension(TrustedCertificate));
102 trace!(target: "app::App::handle", "add TrustedCertificate to extensions");
103 }
104 trace!(target: "app::App::handle", "begin HTTP request serving");
105 Http::new()
106 .serve_connection(stream.compat(), svc)
107 .await
108 .context("failed to handle request")
109 }
110}