pub mod auth;
pub mod comment;
pub mod extract;
pub mod image;
pub mod mailing;
pub mod user;
#[cfg(feature = "askama")]
pub mod askama;
#[cfg(feature = "stripe")]
pub mod stripe;
mod error;
pub use extract::user::User;
use std::{net::ToSocketAddrs, sync::Arc};
use axum::Extension;
use crate::Result;
use crate::{Config, Database};
pub type Router = axum::Router<cookie::Key>;
pub type ConfigExt<C = Config> = Extension<Arc<C>>;
pub type DbExt = Extension<Arc<Database>>;
#[cfg(feature = "stripe")]
pub type StripeExt = Extension<Arc<::stripe::Client>>;
pub fn router(mut router: Router, config: &Config) -> Router {
#[cfg(feature = "stripe")]
{
router = conditional_merge("stripe", router, stripe::router(), config);
}
router = conditional_merge("user", router, user::router(), config);
router = conditional_merge("comment", router, comment::router(), config);
router = conditional_merge("mailing", router, mailing::router(), config);
router = conditional_merge("auth", router, auth::router(config), config);
conditional_merge("image", router, image::router(), config)
}
fn conditional_merge(route: &str, routera: Router, routerb: Router, config: &Config) -> Router {
if config.routes.enable.contains(&route.to_string())
|| !config.routes.disable.contains(&route.to_string())
{
routera.merge(routerb)
} else {
routera
}
}
pub async fn start(mut router: Router, config: Config) -> Result<()> {
start_with(Database::new()?, router, config).await
}
pub async fn start_with(db: Database, mut router: Router, config: Config) -> Result<()> {
crate::tracing::init(&config).unwrap_or_else(|e| {
log::warn!("failed to initialize tracing (perhaps it was already initialized?): {e}")
});
if config.init.enabled {
crate::init::initialize(&config, &db)?;
}
if config.dev.enabled && config.dev.mock {
crate::mock::generate(&config, &db)?;
}
let key = if config.dev.enabled {
cookie::Key::generate()
} else {
match db.get_at::<Vec<u8>>("cookie_keys", uuid::Uuid::nil()) {
Ok(k) => cookie::Key::from(&k),
Err(_) => {
let k = cookie::Key::generate();
db.set_raw_at("cookie_keys", &k.master(), uuid::Uuid::nil())?;
k
}
}
};
if config.assets.serve {
router = router.nest_service(
"/assets",
tower_http::services::ServeDir::new(&config.assets.path),
);
}
let addr = config.address;
#[cfg(feature = "stripe")]
let mut router = {
let secret = if cfg!(debug_assertions) {
&config.payments.stripe.test_secret
} else {
&config.payments.stripe.secret
};
router.layer(Extension(Arc::new(::stripe::Client::new(secret))))
};
let mut router = router
.layer(Extension(Arc::new(config)))
.layer(Extension(Arc::new(db)))
.with_state(key);
tracing::info!("starting server at {addr}");
let listener = tokio::net::TcpListener::bind(addr)
.await
.expect("failed binding to addr: {addr}");
axum::serve(listener, router).await.map_err(|e| e.into())
}