Jump to…
snowinitial commitqoxwzsukwmkx1mo
Matt W1//! Shared application state and request-scoped context.
Matt W2
Matt W3use std::sync::Arc;
Matt W4
Matt W5use axum::extract::FromRequestParts;
Matt W6use axum::http::request::Parts;
Matt W7use df_auth::Oidc;
Matt W8use df_db::models::User;
Matt W9use df_db::PgPool;
Matt W10
Matt W11use crate::config::Config;
Matt W12
Matt W13pub struct Inner {
Matt W14 pub db: PgPool,
Matt W15 pub oidc: Oidc,
Matt W16 pub config: Config,
Matt W17 /// Repository storage, behind the trait so nothing here knows it is Git.
Matt W18 pub store: Arc<dyn df_store::RepoStore>,
Matt W19 /// Per-identity rate and concurrency limits (spec §9).
Matt W20 pub limiter: crate::ratelimit::Limiter,
Matt W21}
Matt W22
Matt W23#[derive(Clone)]
Matt W24pub struct AppState(pub Arc<Inner>);
Matt W25
Matt W26impl std::ops::Deref for AppState {
Matt W27 type Target = Inner;
Matt W28 fn deref(&self) -> &Inner {
Matt W29 &self.0
Matt W30 }
Matt W31}
Matt W32
Matt W33/// The signed-in user, resolved once per request by the session middleware and
Matt W34/// stashed in request extensions.
Matt W35///
Matt W36/// Handlers take `CurrentUser` (optional) or `RequireUser` (enforced) rather
Matt W37/// than reading cookies themselves.
Matt W38#[derive(Clone)]
Matt W39pub struct CurrentUser(pub Option<Arc<User>>);
Matt W40
Matt W41impl<S: Send + Sync> FromRequestParts<S> for CurrentUser {
Matt W42 type Rejection = std::convert::Infallible;
Matt W43
Matt W44 async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
Matt W45 Ok(parts
Matt W46 .extensions
Matt W47 .get::<CurrentUser>()
Matt W48 .cloned()
Matt W49 .unwrap_or(CurrentUser(None)))
Matt W50 }
Matt W51}
Matt W52
Matt W53/// The per-request CSRF token, minted or echoed by middleware.
Matt W54#[derive(Clone)]
Matt W55pub struct CsrfToken(pub String);
Matt W56
Matt W57impl<S: Send + Sync> FromRequestParts<S> for CsrfToken {
Matt W58 type Rejection = std::convert::Infallible;
Matt W59
Matt W60 async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
Matt W61 Ok(parts
Matt W62 .extensions
Matt W63 .get::<CsrfToken>()
Matt W64 .cloned()
Matt W65 .unwrap_or_else(|| CsrfToken(String::new())))
Matt W66 }
Matt W67}
Matt W68
Matt W69/// The connecting peer's address, when one is known.
Matt W70///
Matt W71/// `ConnectInfo<SocketAddr>` itself is not an optional extractor, so a handler
Matt W72/// that took it directly would 500 on any request that arrived without it —
Matt W73/// which is every request in a test, and any request at all if the server is
Matt W74/// ever served without `into_make_service_with_connect_info`. This wrapper makes
Matt W75/// absence a value the handler decides about rather than an error.
Matt W76#[derive(Clone, Copy, Debug)]
Matt W77pub struct PeerAddr(pub Option<std::net::SocketAddr>);
Matt W78
Matt W79impl PeerAddr {
Matt W80 /// Whether the peer is provably local. Absence is not local.
Matt W81 pub fn is_loopback(&self) -> bool {
Matt W82 self.0.is_some_and(|a| a.ip().is_loopback())
Matt W83 }
Matt W84
Matt W85 pub fn ip(&self) -> Option<std::net::IpAddr> {
Matt W86 self.0.map(|a| a.ip())
Matt W87 }
Matt W88}
Matt W89
Matt W90impl<S: Send + Sync> FromRequestParts<S> for PeerAddr {
Matt W91 type Rejection = std::convert::Infallible;
Matt W92
Matt W93 async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
Matt W94 Ok(PeerAddr(
Matt W95 parts
Matt W96 .extensions
Matt W97 .get::<axum::extract::ConnectInfo<std::net::SocketAddr>>()
Matt W98 .map(|c| c.0),
Matt W99 ))
Matt W100 }
Matt W101}
Matt W102
Matt W103/// Per-request CSP nonce.
Matt W104#[derive(Clone)]
Matt W105pub struct Nonce(pub String);
Matt W106
Matt W107impl<S: Send + Sync> FromRequestParts<S> for Nonce {
Matt W108 type Rejection = std::convert::Infallible;
Matt W109
Matt W110 async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
Matt W111 Ok(parts
Matt W112 .extensions
Matt W113 .get::<Nonce>()
Matt W114 .cloned()
Matt W115 .unwrap_or_else(|| Nonce(String::new())))
Matt W116 }
Matt W117}

117 lines · Rust