diff options
author | Vika <vika@fireburn.ru> | 2024-08-01 20:01:12 +0300 |
---|---|---|
committer | Vika <vika@fireburn.ru> | 2024-08-01 20:40:30 +0300 |
commit | 4ca0c24b1989fcd12c453d428af70f58456f7651 (patch) | |
tree | 19f480107cc6491b832a7a2d7198cee48f205b85 /src/lib.rs | |
parent | 7e8e688e2e58f9c944b941e768ab7b034a348a1f (diff) | |
download | kittybox-4ca0c24b1989fcd12c453d428af70f58456f7651.tar.zst |
Migrate from axum::Extension to axum::extract::State
This somehow allowed me to shrink the construction phase of Kittybox by a huge amount of code.
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 118 |
1 files changed, 116 insertions, 2 deletions
diff --git a/src/lib.rs b/src/lib.rs index 04b3298..1cc01c2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,17 @@ #![forbid(unsafe_code)] #![warn(clippy::todo)] +use std::sync::Arc; + +use axum::extract::FromRef; +use axum_extra::extract::cookie::Key; +use database::{FileStorage, PostgresStorage, Storage}; +use indieauth::backend::{AuthBackend, FileBackend as FileAuthBackend}; +use kittybox_util::queue::{JobItem, JobQueue}; +use media::storage::{MediaStore, file::FileStore as FileMediaStore}; +use tokio::{sync::Mutex, task::JoinSet}; +use webmentions::queue::{PostgresJobItem, PostgresJobQueue}; + /// Database abstraction layer for Kittybox, allowing the CMS to work with any kind of database. pub mod database; pub mod frontend; @@ -9,6 +20,110 @@ pub mod micropub; pub mod indieauth; pub mod webmentions; pub mod login; +//pub mod admin; + +#[derive(Clone)] +pub struct AppState<A, S, M, Q> +where +A: AuthBackend + Sized + 'static, +S: Storage + Sized + 'static, +M: MediaStore + Sized + 'static, +Q: JobQueue<webmentions::Webmention> + Sized +{ + pub auth_backend: A, + pub storage: S, + pub media_store: M, + pub job_queue: Q, + pub http: reqwest::Client, + pub background_jobs: Arc<Mutex<JoinSet<()>>>, + pub cookie_key: Key +} + +// This is really regrettable, but I can't write: +// +// ```compile-error +// impl <A, S, M> FromRef<AppState<A, S, M>> for A +// where A: AuthBackend, S: Storage, M: MediaStore { +// fn from_ref(input: &AppState<A, S, M>) -> A { +// input.auth_backend.clone() +// } +// } +// ``` +// +// ...because of the orphan rule. +// +// I wonder if this would stifle external implementations. I think it +// shouldn't, because my AppState type is generic, and since the +// target type is local, the orphan rule will not kick in. You just +// have to repeat this magic invocation. + +impl<S, M, Q> FromRef<AppState<Self, S, M, Q>> for FileAuthBackend +// where S: Storage, M: MediaStore +where S: Storage, M: MediaStore, Q: JobQueue<webmentions::Webmention> +{ + fn from_ref(input: &AppState<Self, S, M, Q>) -> Self { + input.auth_backend.clone() + } +} + +impl<A, M, Q> FromRef<AppState<A, Self, M, Q>> for PostgresStorage +// where A: AuthBackend, M: MediaStore +where A: AuthBackend, M: MediaStore, Q: JobQueue<webmentions::Webmention> +{ + fn from_ref(input: &AppState<A, Self, M, Q>) -> Self { + input.storage.clone() + } +} + +impl<A, M, Q> FromRef<AppState<A, Self, M, Q>> for FileStorage +where A: AuthBackend, M: MediaStore, Q: JobQueue<webmentions::Webmention> +{ + fn from_ref(input: &AppState<A, Self, M, Q>) -> Self { + input.storage.clone() + } +} + +impl<A, S, Q> FromRef<AppState<A, S, Self, Q>> for FileMediaStore +// where A: AuthBackend, S: Storage +where A: AuthBackend, S: Storage, Q: JobQueue<webmentions::Webmention> +{ + fn from_ref(input: &AppState<A, S, Self, Q>) -> Self { + input.media_store.clone() + } +} + +impl<A, S, M, Q> FromRef<AppState<A, S, M, Q>> for Key +where A: AuthBackend, S: Storage, M: MediaStore, Q: JobQueue<webmentions::Webmention> +{ + fn from_ref(input: &AppState<A, S, M, Q>) -> Self { + input.cookie_key.clone() + } +} + +impl<A, S, M, Q> FromRef<AppState<A, S, M, Q>> for reqwest::Client +where A: AuthBackend, S: Storage, M: MediaStore, Q: JobQueue<webmentions::Webmention> +{ + fn from_ref(input: &AppState<A, S, M, Q>) -> Self { + input.http.clone() + } +} + +impl<A, S, M, Q> FromRef<AppState<A, S, M, Q>> for Arc<Mutex<JoinSet<()>>> +where A: AuthBackend, S: Storage, M: MediaStore, Q: JobQueue<webmentions::Webmention> +{ + fn from_ref(input: &AppState<A, S, M, Q>) -> Self { + input.background_jobs.clone() + } +} + +#[cfg(feature = "sqlx")] +impl<A, S, M> FromRef<AppState<A, S, M, Self>> for PostgresJobQueue<webmentions::Webmention> +where A: AuthBackend, S: Storage, M: MediaStore +{ + fn from_ref(input: &AppState<A, S, M, Self>) -> Self { + input.job_queue.clone() + } +} pub mod companion { use std::{collections::HashMap, sync::Arc}; @@ -52,8 +167,7 @@ pub mod companion { } } - #[must_use] - pub fn router() -> axum::Router { + pub fn router<St: Clone + Send + Sync + 'static>() -> axum::Router<St> { let resources: ResourceTable = { let mut map = HashMap::new(); |