diff options
author | Vika <vika@fireburn.ru> | 2025-04-19 13:30:07 +0300 |
---|---|---|
committer | Vika <vika@fireburn.ru> | 2025-04-19 13:30:07 +0300 |
commit | 8d4b697863a338e843a28707c7f9cd7c863ccca5 (patch) | |
tree | bbd869923e27e034f1cec17b750d5b13466d248b | |
parent | e3c845d8f563d75618e237cdf16bd4ad4a00dcb8 (diff) | |
download | kittybox-8d4b697863a338e843a28707c7f9cd7c863ccca5.tar.zst |
Extract various modules to their own files for convenience
Change-Id: I571ec98b760a583300a810abd756e5f6f2bca25a
-rw-r--r-- | src/companion.rs | 84 | ||||
-rw-r--r-- | src/database/mod.rs | 66 | ||||
-rw-r--r-- | src/database/settings.rs | 63 | ||||
-rw-r--r-- | src/lib.rs | 87 |
4 files changed, 149 insertions, 151 deletions
diff --git a/src/companion.rs b/src/companion.rs new file mode 100644 index 0000000..debc266 --- /dev/null +++ b/src/companion.rs @@ -0,0 +1,84 @@ +use axum::{ + extract::{Extension, Path}, + response::{IntoResponse, Response}, +}; +use std::{collections::HashMap, sync::Arc}; + +#[derive(Debug, Clone, Copy)] +struct Resource { + data: &'static [u8], + mime: &'static str, +} + +impl IntoResponse for &Resource { + fn into_response(self) -> Response { + ( + axum::http::StatusCode::OK, + [("Content-Type", self.mime)], + self.data, + ) + .into_response() + } +} + +// TODO replace with the "phf" crate someday +type ResourceTable = Arc<HashMap<&'static str, Resource>>; + +#[tracing::instrument] +async fn map_to_static( + Path(name): Path<String>, + Extension(resources): Extension<ResourceTable>, +) -> Response { + tracing::debug!("Searching for {} in the resource table...", name); + match resources.get(name.as_str()) { + Some(res) => res.into_response(), + None => { + #[cfg(debug_assertions)] + tracing::error!("Not found"); + + ( + axum::http::StatusCode::NOT_FOUND, + [("Content-Type", "text/plain")], + "Not found. Sorry.".as_bytes(), + ) + .into_response() + } + } +} + +pub fn router<St: Clone + Send + Sync + 'static>() -> axum::Router<St> { + let resources: ResourceTable = { + let mut map = HashMap::new(); + + macro_rules! register_resource { + ($map:ident, $prefix:expr, ($filename:literal, $mime:literal)) => {{ + $map.insert($filename, Resource { + data: include_bytes!(concat!($prefix, $filename)), + mime: $mime + }) + }}; + ($map:ident, $prefix:expr, ($filename:literal, $mime:literal), $( ($f:literal, $m:literal) ),+) => {{ + register_resource!($map, $prefix, ($filename, $mime)); + register_resource!($map, $prefix, $(($f, $m)),+); + }}; + } + + register_resource! { + map, + concat!(env!("OUT_DIR"), "/", "companion", "/"), + ("index.html", "text/html; charset=\"utf-8\""), + ("main.js", "text/javascript"), + ("micropub_api.js", "text/javascript"), + ("indieauth.js", "text/javascript"), + ("base64.js", "text/javascript"), + ("style.css", "text/css") + }; + + Arc::new(map) + }; + + axum::Router::new().route( + "/{filename}", + axum::routing::get(map_to_static).layer(Extension(resources)), + ) +} diff --git a/src/database/mod.rs b/src/database/mod.rs index de51c2c..fb6f43c 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -43,71 +43,7 @@ pub enum ErrorKind { } /// Settings that can be stored in the database. -pub mod settings { - mod private { - pub trait Sealed {} - } - - /// A trait for various settings that should be contained here. - /// - /// **Note**: this trait is sealed to prevent external - /// implementations, as it wouldn't make sense to add new settings - /// that aren't used by Kittybox itself. - pub trait Setting: private::Sealed + std::fmt::Debug + Default + Clone + serde::Serialize + serde::de::DeserializeOwned + /*From<Settings> +*/ Send + Sync + 'static { - /// The data that the setting carries. - type Data: std::fmt::Debug + Send + Sync; - /// The string ID for the setting, usable as an identifier in the database. - const ID: &'static str; - - /// Unwrap the setting type, returning owned data contained within. - fn into_inner(self) -> Self::Data; - /// Create a new instance of this type containing certain data. - fn new(data: Self::Data) -> Self; - } - - /// A website's title, shown in the header. - #[derive(Debug, serde::Deserialize, serde::Serialize, Clone, PartialEq, Eq)] - pub struct SiteName(pub(crate) String); - impl Default for SiteName { - fn default() -> Self { - Self("Kittybox".to_string()) - } - } - impl AsRef<str> for SiteName { - fn as_ref(&self) -> &str { - self.0.as_str() - } - } - impl private::Sealed for SiteName {} - impl Setting for SiteName { - type Data = String; - const ID: &'static str = "site_name"; - - fn into_inner(self) -> String { - self.0 - } - fn new(data: Self::Data) -> Self { - Self(data) - } - } - - /// Participation status in the IndieWeb Webring: https://πΈπ.ws/dashboard - #[derive(Debug, Default, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)] - pub struct Webring(bool); - impl private::Sealed for Webring {} - impl Setting for Webring { - type Data = bool; - const ID: &'static str = "webring"; - - fn into_inner(self) -> Self::Data { - self.0 - } - - fn new(data: Self::Data) -> Self { - Self(data) - } - } -} +pub mod settings; /// Error signalled from the database. #[derive(Debug)] diff --git a/src/database/settings.rs b/src/database/settings.rs new file mode 100644 index 0000000..792a155 --- /dev/null +++ b/src/database/settings.rs @@ -0,0 +1,63 @@ +mod private { + pub trait Sealed {} +} + +/// A trait for various settings that should be contained here. +/// +/// **Note**: this trait is sealed to prevent external +/// implementations, as it wouldn't make sense to add new settings +/// that aren't used by Kittybox itself. +pub trait Setting: private::Sealed + std::fmt::Debug + Default + Clone + serde::Serialize + serde::de::DeserializeOwned + /*From<Settings> +*/ Send + Sync + 'static { + /// The data that the setting carries. + type Data: std::fmt::Debug + Send + Sync; + /// The string ID for the setting, usable as an identifier in the database. + const ID: &'static str; + + /// Unwrap the setting type, returning owned data contained within. + fn into_inner(self) -> Self::Data; + /// Create a new instance of this type containing certain data. + fn new(data: Self::Data) -> Self; +} + +/// A website's title, shown in the header. +#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, PartialEq, Eq)] +pub struct SiteName(pub(crate) String); +impl Default for SiteName { + fn default() -> Self { + Self("Kittybox".to_string()) + } +} +impl AsRef<str> for SiteName { + fn as_ref(&self) -> &str { + self.0.as_str() + } +} +impl private::Sealed for SiteName {} +impl Setting for SiteName { + type Data = String; + const ID: &'static str = "site_name"; + + fn into_inner(self) -> String { + self.0 + } + fn new(data: Self::Data) -> Self { + Self(data) + } +} + +/// Participation status in the IndieWeb Webring: https://πΈπ.ws/dashboard +#[derive(Debug, Default, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)] +pub struct Webring(bool); +impl private::Sealed for Webring {} +impl Setting for Webring { + type Data = bool; + const ID: &'static str = "webring"; + + fn into_inner(self) -> Self::Data { + self.0 + } + + fn new(data: Self::Data) -> Self { + Self(data) + } +} diff --git a/src/lib.rs b/src/lib.rs index cf81dc9..0df5e5d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -223,92 +223,7 @@ where } } -pub mod companion { - use axum::{ - extract::{Extension, Path}, - response::{IntoResponse, Response}, - }; - use std::{collections::HashMap, sync::Arc}; - - #[derive(Debug, Clone, Copy)] - struct Resource { - data: &'static [u8], - mime: &'static str, - } - - impl IntoResponse for &Resource { - fn into_response(self) -> Response { - ( - axum::http::StatusCode::OK, - [("Content-Type", self.mime)], - self.data, - ) - .into_response() - } - } - - // TODO replace with the "phf" crate someday - type ResourceTable = Arc<HashMap<&'static str, Resource>>; - - #[tracing::instrument] - async fn map_to_static( - Path(name): Path<String>, - Extension(resources): Extension<ResourceTable>, - ) -> Response { - tracing::debug!("Searching for {} in the resource table...", name); - match resources.get(name.as_str()) { - Some(res) => res.into_response(), - None => { - #[cfg(debug_assertions)] - tracing::error!("Not found"); - - ( - axum::http::StatusCode::NOT_FOUND, - [("Content-Type", "text/plain")], - "Not found. Sorry.".as_bytes(), - ) - .into_response() - } - } - } - - pub fn router<St: Clone + Send + Sync + 'static>() -> axum::Router<St> { - let resources: ResourceTable = { - let mut map = HashMap::new(); - - macro_rules! register_resource { - ($map:ident, $prefix:expr, ($filename:literal, $mime:literal)) => {{ - $map.insert($filename, Resource { - data: include_bytes!(concat!($prefix, $filename)), - mime: $mime - }) - }}; - ($map:ident, $prefix:expr, ($filename:literal, $mime:literal), $( ($f:literal, $m:literal) ),+) => {{ - register_resource!($map, $prefix, ($filename, $mime)); - register_resource!($map, $prefix, $(($f, $m)),+); - }}; - } - - register_resource! { - map, - concat!(env!("OUT_DIR"), "/", "companion", "/"), - ("index.html", "text/html; charset=\"utf-8\""), - ("main.js", "text/javascript"), - ("micropub_api.js", "text/javascript"), - ("indieauth.js", "text/javascript"), - ("base64.js", "text/javascript"), - ("style.css", "text/css") - }; - - Arc::new(map) - }; - - axum::Router::new().route( - "/{filename}", - axum::routing::get(map_to_static).layer(Extension(resources)), - ) - } -} +pub mod companion; async fn teapot_route() -> impl axum::response::IntoResponse { use axum::http::{header, StatusCode}; |