use std::sync::{Arc, OnceLock}; use crate::{observability::FilterReloadHandles, Config, Result}; pub(crate) mod account_data; pub(crate) mod admin; pub(crate) mod appservice; pub(crate) mod globals; pub(crate) mod key_backups; pub(crate) mod media; pub(crate) mod pdu; pub(crate) mod pusher; pub(crate) mod rooms; pub(crate) mod sending; pub(crate) mod server_backoff; pub(crate) mod transaction_ids; pub(crate) mod uiaa; pub(crate) mod users; static SERVICES: OnceLock<&'static Services> = OnceLock::new(); /// Convenient access to the global [`Services`] instance pub(crate) fn services() -> &'static Services { SERVICES.get().expect("`Services::install` should have been called first") } pub(crate) struct Services { pub(crate) appservice: appservice::Service, pub(crate) pusher: pusher::Service, pub(crate) rooms: rooms::Service, pub(crate) transaction_ids: transaction_ids::Service, pub(crate) uiaa: uiaa::Service, pub(crate) users: users::Service, pub(crate) account_data: account_data::Service, pub(crate) admin: Arc, pub(crate) globals: globals::Service, pub(crate) key_backups: key_backups::Service, pub(crate) media: media::Service, pub(crate) server_backoff: Arc, pub(crate) sending: Arc, } impl Services { #[allow(clippy::too_many_lines)] pub(crate) fn new< D: appservice::Data + pusher::Data + rooms::Data + transaction_ids::Data + uiaa::Data + users::Data + account_data::Data + globals::Data + key_backups::Data + media::Data + sending::Data + 'static, >( db: &'static D, config: Config, reload_handles: Option, ) -> Result { Ok(Self { appservice: appservice::Service::new(db)?, pusher: pusher::Service { db, }, rooms: rooms::Service { alias: rooms::alias::Service::new(db), auth_chain: rooms::auth_chain::Service::new( db, config.cache.auth_chain, ), directory: db, edus: rooms::edus::Service { read_receipt: db, typing: rooms::edus::typing::Service::new(), }, event_handler: rooms::event_handler::Service, lazy_loading: rooms::lazy_loading::Service::new(db), metadata: db, outlier: db, pdu_metadata: rooms::pdu_metadata::Service { db, }, search: db, short: rooms::short::Service::new( db, config.cache.short_eventid, config.cache.eventid_short, config.cache.statekey_short, config.cache.short_statekey, ), state: rooms::state::Service { db, }, state_accessor: rooms::state_accessor::Service::new( db, config.cache.server_visibility, config.cache.user_visibility, ), state_cache: rooms::state_cache::Service::new(db), state_compressor: rooms::state_compressor::Service::new( db, config.cache.state_info, ), timeline: rooms::timeline::Service::new(db, config.cache.pdu), threads: rooms::threads::Service { db, }, spaces: rooms::spaces::Service::new( config.cache.roomid_spacechunk, ), user: db, }, transaction_ids: db, uiaa: uiaa::Service::new(db), users: users::Service::new(db), account_data: db, admin: admin::Service::new(), key_backups: db, media: media::Service { db, }, server_backoff: server_backoff::Service::build(), sending: sending::Service::new(db, &config), globals: globals::Service::new(db, config, reload_handles)?, }) } /// Installs `self` to be globally accessed via [`services`] pub(crate) fn install(self) { assert!( SERVICES.set(Box::leak(Box::new(self))).is_ok(), "Services::install was called more than once" ); } }