diff options
| author | Owen Jacobson <owen@grimoire.ca> | 2025-10-27 18:15:25 -0400 |
|---|---|---|
| committer | Owen Jacobson <owen@grimoire.ca> | 2025-10-28 01:43:26 -0400 |
| commit | d66728889105f6f1ef5113d9ceb223e362df0008 (patch) | |
| tree | 5102813fbaa222276dcabd15a736838f9641d71f | |
| parent | c2a3a010c67776b9a459d7ba0930630ff25a3a51 (diff) | |
Convert the `Setup` component into a freestanding struct.
The changes to the setup-requiring middleware are probably more general than was strictly needed, but they will make it work with anything that can provide a `Setup` component rather than being bolted to `App` specifically, which feels tidier.
| -rw-r--r-- | src/app.rs | 10 | ||||
| -rw-r--r-- | src/setup/app.rs | 13 | ||||
| -rw-r--r-- | src/setup/handlers/setup/mod.rs | 14 | ||||
| -rw-r--r-- | src/setup/handlers/setup/test.rs | 6 | ||||
| -rw-r--r-- | src/setup/required.rs | 31 | ||||
| -rw-r--r-- | src/ui/handlers/setup.rs | 7 |
6 files changed, 48 insertions, 33 deletions
@@ -58,8 +58,8 @@ impl App { Messages::new(self.db.clone(), self.events.clone()) } - pub const fn setup(&self) -> Setup<'_> { - Setup::new(&self.db, &self.events) + pub fn setup(&self) -> Setup { + Setup::new(self.db.clone(), self.events.clone()) } pub const fn tokens(&self) -> Tokens<'_> { @@ -101,3 +101,9 @@ impl FromRef<App> for Messages { app.messages() } } + +impl FromRef<App> for Setup { + fn from_ref(app: &App) -> Self { + app.setup() + } +} diff --git a/src/setup/app.rs b/src/setup/app.rs index 2a8ec30..9539406 100644 --- a/src/setup/app.rs +++ b/src/setup/app.rs @@ -10,13 +10,14 @@ use crate::{ user::create::{self, Create}, }; -pub struct Setup<'a> { - db: &'a SqlitePool, - events: &'a Broadcaster, +#[derive(Clone)] +pub struct Setup { + db: SqlitePool, + events: Broadcaster, } -impl<'a> Setup<'a> { - pub const fn new(db: &'a SqlitePool, events: &'a Broadcaster) -> Self { +impl Setup { + pub const fn new(db: SqlitePool, events: Broadcaster) -> Self { Self { db, events } } @@ -41,7 +42,7 @@ impl<'a> Setup<'a> { tx.tokens().create(&token, &secret).await?; tx.commit().await?; - stored.publish(self.events); + stored.publish(&self.events); Ok(secret) } diff --git a/src/setup/handlers/setup/mod.rs b/src/setup/handlers/setup/mod.rs index fe24798..2977da8 100644 --- a/src/setup/handlers/setup/mod.rs +++ b/src/setup/handlers/setup/mod.rs @@ -5,21 +5,25 @@ use axum::{ }; use crate::{ - app::App, clock::RequestedAt, empty::Empty, error::Internal, name::Name, password::Password, - setup::app, token::extract::IdentityCookie, + clock::RequestedAt, + empty::Empty, + error::Internal, + name::Name, + password::Password, + setup::{app, app::Setup}, + token::extract::IdentityCookie, }; #[cfg(test)] mod test; pub async fn handler( - State(app): State<App>, + State(setup): State<Setup>, RequestedAt(setup_at): RequestedAt, identity: IdentityCookie, Json(request): Json<Request>, ) -> Result<(IdentityCookie, Empty), Error> { - let secret = app - .setup() + let secret = setup .initial(&request.name, &request.password, &setup_at) .await .map_err(Error)?; diff --git a/src/setup/handlers/setup/test.rs b/src/setup/handlers/setup/test.rs index 283fe8b..670c111 100644 --- a/src/setup/handlers/setup/test.rs +++ b/src/setup/handlers/setup/test.rs @@ -20,7 +20,7 @@ async fn fresh_instance() { password: password.clone(), }; let (identity, Empty) = - super::handler(State(app.clone()), fixtures::now(), identity, Json(request)) + super::handler(State(app.setup()), fixtures::now(), identity, Json(request)) .await .expect("setup in a fresh app succeeds"); @@ -43,7 +43,7 @@ async fn login_exists() { let (name, password) = fixtures::user::propose(); let request = super::Request { name, password }; let super::Error(error) = - super::handler(State(app.clone()), fixtures::now(), identity, Json(request)) + super::handler(State(app.setup()), fixtures::now(), identity, Json(request)) .await .expect_err("setup in a populated app fails"); @@ -68,7 +68,7 @@ async fn invalid_name() { password: password.clone(), }; let super::Error(error) = - super::handler(State(app.clone()), fixtures::now(), identity, Json(request)) + super::handler(State(app.setup()), fixtures::now(), identity, Json(request)) .await .expect_err("setup with an invalid name fails"); diff --git a/src/setup/required.rs b/src/setup/required.rs index a2aed18..e475381 100644 --- a/src/setup/required.rs +++ b/src/setup/required.rs @@ -4,26 +4,29 @@ use std::{ }; use axum::{ - extract::Request, + extract::{FromRef, Request}, http::StatusCode, response::{IntoResponse, Response}, }; use tower::{Layer, Service}; -use crate::{app::App, error::Internal}; +use crate::{error::Internal, setup::app::Setup}; #[derive(Clone)] -pub struct Required(pub App); +pub struct Required<App>(pub App); -impl Required { - pub fn with_fallback<F>(self, fallback: F) -> WithFallback<F> { +impl<App> Required<App> { + pub fn with_fallback<F>(self, fallback: F) -> WithFallback<App, F> { let Self(app) = self; WithFallback { app, fallback } } } -impl<S> Layer<S> for Required { - type Service = Middleware<S, Unavailable>; +impl<S, App> Layer<S> for Required<App> +where + Self: Clone, +{ + type Service = Middleware<S, App, Unavailable>; fn layer(&self, inner: S) -> Self::Service { let Self(app) = self.clone(); @@ -36,16 +39,16 @@ impl<S> Layer<S> for Required { } #[derive(Clone)] -pub struct WithFallback<F> { +pub struct WithFallback<App, F> { app: App, fallback: F, } -impl<S, F> Layer<S> for WithFallback<F> +impl<S, App, F> Layer<S> for WithFallback<App, F> where Self: Clone, { - type Service = Middleware<S, F>; + type Service = Middleware<S, App, F>; fn layer(&self, inner: S) -> Self::Service { let Self { app, fallback } = self.clone(); @@ -58,17 +61,19 @@ where } #[derive(Clone)] -pub struct Middleware<S, F> { +pub struct Middleware<S, App, F> { inner: S, app: App, fallback: F, } -impl<S, F> Service<Request> for Middleware<S, F> +impl<S, App, F> Service<Request> for Middleware<S, App, F> where + Setup: FromRef<App>, Self: Clone, S: Service<Request, Response = Response> + Send + 'static, S::Future: Send, + App: Send + 'static, F: IntoResponse + Clone + Send + 'static, { type Response = S::Response; @@ -87,7 +92,7 @@ where } = self.clone(); Box::pin(async move { - match app.setup().completed().await { + match Setup::from_ref(&app).completed().await { Ok(true) => inner.call(req).await, Ok(false) => Ok(fallback.into_response()), Err(error) => Ok(Internal::from(error).into_response()), diff --git a/src/ui/handlers/setup.rs b/src/ui/handlers/setup.rs index 49821cf..5707765 100644 --- a/src/ui/handlers/setup.rs +++ b/src/ui/handlers/setup.rs @@ -4,14 +4,13 @@ use axum::{ }; use crate::{ - app::App, error::Internal, + setup::app::Setup, ui::assets::{Asset, Assets}, }; -pub async fn handler(State(app): State<App>) -> Result<Asset, Error> { - if app - .setup() +pub async fn handler(State(setup): State<Setup>) -> Result<Asset, Error> { + if setup .completed() .await .map_err(Internal::from) |
