mod api_error; pub mod auth_api; pub mod database; pub mod error; pub mod health; pub mod http; pub mod identity_client; pub mod imaging; pub mod middleware; pub mod notify; pub mod pagination; pub mod push; pub mod redis; pub mod rest; pub mod serde_datetime; pub mod serde_patch; pub mod urls; pub mod users; use std::sync::Arc; pub use api_error::is_unique_violation; pub use auth_api::{AuthApi, KenAuthError}; use config::AppConfig; pub use database::{AppDatabase, Database, DatabaseRole}; pub use error::ExportError; pub use redis::{AppRedis, RedisConnection}; pub use storage::{BlobStore, S3Client}; pub use urls::{resolve_space_image_url, resolve_user_avatar_url}; #[derive(Clone)] pub struct AppState { pub database: Arc, pub redis: AppRedis, pub cache: ::cache::Cache, pub storage: Arc, pub config: AppConfig, pub kenauth: Option>, pub mail: Option<::email::MailPublisher>, pub events: Option<::events::EventHandler>, } impl AppState { pub async fn load() -> Result { let config = config::AppConfig::load().map_err(|e| ExportError::InvalidConfig(e.to_string()))?; Self::with_config(config).await } pub async fn with_config(config: AppConfig) -> Result { let database: Arc = Arc::new(AppDatabase::connect(config.database.clone()).await?); Self::with_identity(config, database, None, None, None).await } pub async fn with_identity( config: AppConfig, database: Arc, identity: Option>, mail: Option<::email::MailPublisher>, events: Option<::events::EventHandler>, ) -> Result { let mut redis = AppRedis::connect(config.redis.clone()).await?; let cache = ::cache::Cache::connect(&config.redis) .await .map_err(|error| ExportError::Connection(error.to_string()))?; // 入队点遍布各业务 crate,但只有这里有配置:把开关写进句柄,让 // `export::push::enqueue` 能自己判断该不该产生任务。 redis.set_push_enabled(config.push.enabled); let storage: Arc = Arc::new(S3Client::new(&config.s3).map_err(ExportError::from)?); let kenauth = identity; if let Some(client) = &kenauth { identity_client::install(client.clone()); } Ok(Self::from_parts( database, redis, cache, storage, config, kenauth, mail, events, )) } #[allow(clippy::too_many_arguments)] pub fn from_parts( database: Arc, redis: AppRedis, cache: ::cache::Cache, storage: Arc, config: AppConfig, kenauth: Option>, mail: Option<::email::MailPublisher>, events: Option<::events::EventHandler>, ) -> Self { Self { database, redis, cache, storage, config, kenauth, mail, events, } } }