use std::{any::Any, sync::Arc};
use axum::Router;
use tokio::sync::RwLock;
use crate::{
builder::RawDb,
internal::{
database::provider::Connection, division::Division, locales::Localizations,
router::RouterState, settings::Settings, templates::Templates,
},
upload_provider::EitherUploadProvider,
Result, UploadProvider,
};
pub struct RunContext<'a, U: UploadProvider> {
pub upload_provider: &'a U,
pub templates: &'a mut Templates,
pub localizations: &'a mut Localizations,
pub rawdb: &'a RawDb,
pub settings: Arc<RwLock<Settings>>,
pub db: Connection,
pub divisions: &'a mut Vec<Division>,
}
pub struct UploadProviderContext<'a> {
pub settings: &'a Settings,
pub db: Connection,
}
pub struct DatabaseProviderContext<'a> {
pub settings: &'a mut Settings,
}
#[allow(async_fn_in_trait)]
pub trait Plugin {
async fn upload_provider(
&self,
context: &UploadProviderContext<'_>,
) -> Option<impl UploadProvider + Send + Sync> {
_ = context;
None::<()>
}
async fn database_provider(
&self,
_context: &mut DatabaseProviderContext<'_>,
) -> Option<(Connection, Box<dyn Any + Send + Sync>)> {
None
}
async fn run<U: UploadProvider>(
&self,
context: &mut RunContext<'_, U>,
) -> Result<Router<RouterState>> {
_ = context;
Ok(Router::new())
}
}
impl Plugin for () {}
impl<P: Plugin> Plugin for (P,) {
async fn upload_provider(
&self,
context: &UploadProviderContext<'_>,
) -> Option<impl UploadProvider + Send + Sync> {
self.0.upload_provider(context).await
}
async fn database_provider(
&self,
context: &mut DatabaseProviderContext<'_>,
) -> Option<(Connection, Box<dyn Any + Send + Sync>)> {
self.0.database_provider(context).await
}
async fn run<U: UploadProvider>(
&self,
context: &mut RunContext<'_, U>,
) -> Result<Router<RouterState>> {
self.0.run(context).await
}
}
impl<P, P2> Plugin for (P, P2)
where
P: Plugin,
P2: Plugin,
{
async fn upload_provider(
&self,
context: &UploadProviderContext<'_>,
) -> Option<impl UploadProvider + Send + Sync> {
match self.0.upload_provider(context).await {
Some(u) => Some(EitherUploadProvider::Left(u)),
None => self
.1
.upload_provider(context)
.await
.map(EitherUploadProvider::Right),
}
}
async fn database_provider(
&self,
context: &mut DatabaseProviderContext<'_>,
) -> Option<(Connection, Box<dyn Any + Send + Sync>)> {
match self.0.database_provider(context).await {
Some(u) => Some(u),
None => self.1.database_provider(context).await,
}
}
async fn run<U: UploadProvider>(
&self,
context: &mut RunContext<'_, U>,
) -> Result<Router<RouterState>> {
let mut router = self.1.run(context).await?;
router = router.merge(self.0.run(context).await?);
Ok(router)
}
}