use std::sync::Arc;
#[cfg(feature = "database")]
use crate::traits::database::DatabasePool;
#[cfg(feature = "cache")]
use crate::traits::cache::Cache;
#[cfg(feature = "sessions")]
use crate::traits::session::SessionStore;
#[cfg(feature = "jobs")]
use crate::traits::job::JobQueue;
#[cfg(feature = "websocket")]
use crate::websocket::ConnectionManager;
#[derive(Clone)]
pub struct AppContext {
#[cfg(feature = "database")]
pub database: Option<Arc<dyn DatabasePool>>,
#[cfg(feature = "cache")]
pub cache: Option<Arc<dyn Cache>>,
#[cfg(feature = "sessions")]
pub sessions: Option<Arc<dyn SessionStore>>,
#[cfg(feature = "jobs")]
pub jobs: Option<Arc<dyn JobQueue>>,
#[cfg(feature = "websocket")]
pub websocket_manager: Option<Arc<ConnectionManager>>,
pub auth_provider: Option<Arc<dyn std::any::Any + Send + Sync>>,
}
impl AppContext {
pub fn new() -> Self {
Self {
#[cfg(feature = "database")]
database: None,
#[cfg(feature = "cache")]
cache: None,
#[cfg(feature = "sessions")]
sessions: None,
#[cfg(feature = "jobs")]
jobs: None,
#[cfg(feature = "websocket")]
websocket_manager: None,
auth_provider: None,
}
}
pub fn builder() -> AppContextBuilder {
AppContextBuilder::new()
}
#[cfg(feature = "database")]
pub fn database(&self) -> crate::error::Result<&Arc<dyn DatabasePool>> {
self.database.as_ref().ok_or_else(|| {
crate::error::TidewayError::internal("Database pool not configured")
})
}
#[cfg(feature = "database")]
pub fn database_opt(&self) -> Option<&Arc<dyn DatabasePool>> {
self.database.as_ref()
}
#[cfg(feature = "cache")]
pub fn cache(&self) -> crate::error::Result<&Arc<dyn Cache>> {
self.cache.as_ref().ok_or_else(|| {
crate::error::TidewayError::internal("Cache not configured")
})
}
#[cfg(feature = "cache")]
pub fn cache_opt(&self) -> Option<&Arc<dyn Cache>> {
self.cache.as_ref()
}
#[cfg(feature = "sessions")]
pub fn sessions(&self) -> crate::error::Result<&Arc<dyn SessionStore>> {
self.sessions.as_ref().ok_or_else(|| {
crate::error::TidewayError::internal("Session store not configured")
})
}
#[cfg(feature = "sessions")]
pub fn sessions_opt(&self) -> Option<&Arc<dyn SessionStore>> {
self.sessions.as_ref()
}
#[cfg(feature = "jobs")]
pub fn jobs(&self) -> crate::error::Result<&Arc<dyn JobQueue>> {
self.jobs.as_ref().ok_or_else(|| {
crate::error::TidewayError::internal("Job queue not configured")
})
}
#[cfg(feature = "jobs")]
pub fn jobs_opt(&self) -> Option<&Arc<dyn JobQueue>> {
self.jobs.as_ref()
}
#[cfg(feature = "websocket")]
pub fn websocket_manager(&self) -> crate::error::Result<Arc<ConnectionManager>> {
self.websocket_manager.clone().ok_or_else(|| {
crate::error::TidewayError::internal("WebSocket manager not configured")
})
}
#[cfg(feature = "websocket")]
pub fn websocket_manager_opt(&self) -> Option<Arc<ConnectionManager>> {
self.websocket_manager.clone()
}
pub fn auth_provider_opt<T: 'static>(&self) -> Option<&T> {
self.auth_provider
.as_ref()
.and_then(|p| p.downcast_ref::<T>())
}
pub fn auth_provider<T: 'static>(&self) -> crate::error::Result<&T> {
self.auth_provider_opt::<T>().ok_or_else(|| {
crate::error::TidewayError::internal("Auth provider not configured or wrong type")
})
}
#[cfg(feature = "database")]
pub fn sea_orm_connection(&self) -> crate::error::Result<sea_orm::DatabaseConnection> {
use crate::database::SeaOrmPool;
let pool = self.database()?;
let sea_orm_pool = pool
.as_any()
.downcast_ref::<SeaOrmPool>()
.ok_or_else(|| crate::error::TidewayError::internal("Database pool is not SeaOrmPool"))?;
Ok(sea_orm_pool.as_ref().clone())
}
}
impl Default for AppContext {
fn default() -> Self {
Self::new()
}
}
#[must_use = "builder does nothing until you call build()"]
pub struct AppContextBuilder {
#[cfg(feature = "database")]
database: Option<Arc<dyn DatabasePool>>,
#[cfg(feature = "cache")]
cache: Option<Arc<dyn Cache>>,
#[cfg(feature = "sessions")]
sessions: Option<Arc<dyn SessionStore>>,
#[cfg(feature = "jobs")]
jobs: Option<Arc<dyn JobQueue>>,
#[cfg(feature = "websocket")]
websocket_manager: Option<Arc<ConnectionManager>>,
auth_provider: Option<Arc<dyn std::any::Any + Send + Sync>>,
}
impl AppContextBuilder {
pub fn new() -> Self {
Self {
#[cfg(feature = "database")]
database: None,
#[cfg(feature = "cache")]
cache: None,
#[cfg(feature = "sessions")]
sessions: None,
#[cfg(feature = "jobs")]
jobs: None,
#[cfg(feature = "websocket")]
websocket_manager: None,
auth_provider: None,
}
}
#[cfg(feature = "database")]
pub fn with_database(mut self, pool: Arc<dyn DatabasePool>) -> Self {
self.database = Some(pool);
self
}
#[cfg(feature = "cache")]
pub fn with_cache(mut self, cache: Arc<dyn Cache>) -> Self {
self.cache = Some(cache);
self
}
#[cfg(feature = "sessions")]
pub fn with_sessions(mut self, sessions: Arc<dyn SessionStore>) -> Self {
self.sessions = Some(sessions);
self
}
#[cfg(feature = "jobs")]
pub fn with_job_queue(mut self, queue: Arc<dyn JobQueue>) -> Self {
self.jobs = Some(queue);
self
}
#[cfg(feature = "websocket")]
pub fn with_websocket_manager(mut self, manager: Arc<ConnectionManager>) -> Self {
self.websocket_manager = Some(manager);
self
}
pub fn with_auth_provider<T: Send + Sync + 'static>(mut self, provider: Arc<T>) -> Self {
self.auth_provider = Some(provider as Arc<dyn std::any::Any + Send + Sync>);
self
}
pub fn build(self) -> AppContext {
AppContext {
#[cfg(feature = "database")]
database: self.database,
#[cfg(feature = "cache")]
cache: self.cache,
#[cfg(feature = "sessions")]
sessions: self.sessions,
#[cfg(feature = "jobs")]
jobs: self.jobs,
#[cfg(feature = "websocket")]
websocket_manager: self.websocket_manager,
auth_provider: self.auth_provider,
}
}
}
impl Default for AppContextBuilder {
fn default() -> Self {
Self::new()
}
}