use std::sync::Arc; use export::AppState; /// Everything a request handler needs, built once at startup. /// /// The actix worker closure only clones this value; no pool, client or /// service handle is created per worker thread. #[derive(Clone)] pub struct Deps { pub state: AppState, pub accounts: auth::Accounts, pub access: space::Access, pub notifications: export::notify::Notifications, pub auth: auth::AuthService, pub chat: chat::services::service::ChatService, pub issues: issues::services::service::IssueService, pub space: space::services::service::SpaceService, pub user: user::services::service::UserService, pub git: git::service::GitService, pub pulls: pulls::services::service::PullService, pub internal_service_key: String, } impl Deps { pub fn new(state: AppState, sessions: auth::session::RedisStore) -> Self { let accounts = auth::Accounts::new(state.database.connection().clone(), state.cache.clone()); let access = space::Access::new(state.database.connection().clone(), state.cache.clone()); let notifications = export::notify::Notifications::new(state.database.clone(), state.redis.clone()); let auth = auth::AuthService::new( accounts.clone(), auth::services::AuthSettings::from_config(&state.config), state.mail.clone(), sessions, ); let issue_audience = issues::services::audience::Audience::new( accounts.clone(), notifications.clone(), state.mail.clone(), i18n::config_fallback(state.config.email.default_locale()), ); let issues = issues::services::service::IssueService::new( state.database.clone(), state.storage.clone(), issue_audience, issues::services::service::IssueSettings::from_config(&state.config), issues::services::admission::Admission::new( access.clone(), state.redis.clone(), state.config.quota.clone(), ), ); let space = space::services::service::SpaceService::new( access.clone(), space::services::images::SpaceImages::new( access.clone(), state.storage.clone(), state.redis.clone(), ), space::services::policy::SpacePolicy::new( space::services::service::SpaceSettings::from_config(&state.config), accounts.clone(), state.redis.clone(), ), notifications.clone(), ); let chat = build_chat_service(&state, &accounts, ¬ifications, &access, &space); let user = user::services::service::UserService::new( state.database.clone(), accounts.clone(), access.clone(), user::services::avatar::AvatarService::new( state.database.clone(), state.storage.clone(), state.redis.clone(), ), ); let git_config = state.config.git.clone(); let kenshell = proto::KenShellClient::connect_with_key( &git_config.kenshell_endpoint, &git_config.kenshell_rpc_key, std::time::Duration::from_secs(git_config.kenshell_timeout_secs.max(1)), ) .unwrap_or_else(|error| { panic!( "invalid git.kenshell_endpoint `{}`: {error}", git_config.kenshell_endpoint ) }) .with_request_id(export::middleware::request_id); let git = git::service::GitService::new( state.database.clone(), accounts.clone(), access.clone(), git::service::GitBackend::new(state.cache.clone(), git_config, Arc::new(kenshell)), ); let pulls = pulls::services::service::PullService::new( state.database.clone(), git.clone(), issues.clone(), pulls::services::actors::Actors::new( accounts.clone(), state.redis.clone(), state.config.quota.clone(), ), ); let internal_service_key = state.config.internal.service_key.clone(); Self { state, accounts, access, notifications, auth, chat, issues, space, user, git, pulls, internal_service_key, } } } fn build_chat_service( state: &AppState, accounts: &auth::Accounts, notifications: &export::notify::Notifications, access: &space::Access, space: &space::services::service::SpaceService, ) -> chat::services::service::ChatService { let audience = chat::services::audience::Audience::new( accounts.clone(), notifications.clone(), state.mail.clone(), chat::share::realtime::Realtime::new(state.database.clone()), i18n::config_fallback(state.config.email.default_locale()), ); let participants = chat::services::presence::Participants::new( state.database.clone(), state.redis.clone(), access.clone(), audience.clone(), chat::services::presence::ParticipantSettings::from_config(&state.config), ); chat::services::service::ChatService::new( state.database.clone(), chat::services::media::Media::new( state.storage.clone(), state.redis.clone(), state.database.clone(), ), audience, chat::services::service::ChatSettings::from_config(&state.config), participants, space.clone(), ) }