use std::{ collections::{BTreeMap, HashMap}, sync::{Arc, Mutex as StdMutex}, }; use lru_cache::LruCache; use tokio::sync::{broadcast, Mutex, RwLock}; use crate::{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 transaction_ids; pub(crate) mod uiaa; pub(crate) mod users; 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) sending: Arc, } impl Services { pub(crate) fn build< 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, ) -> Result { Ok(Self { appservice: appservice::Service::build(db)?, pusher: pusher::Service { db, }, rooms: rooms::Service { alias: db, auth_chain: rooms::auth_chain::Service { db, }, directory: db, edus: rooms::edus::Service { read_receipt: db, typing: rooms::edus::typing::Service { typing: RwLock::new(BTreeMap::new()), last_typing_update: RwLock::new(BTreeMap::new()), typing_update_sender: broadcast::channel(100).0, }, }, event_handler: rooms::event_handler::Service, lazy_loading: rooms::lazy_loading::Service { db, lazy_load_waiting: Mutex::new(HashMap::new()), }, metadata: db, outlier: db, pdu_metadata: rooms::pdu_metadata::Service { db, }, search: db, short: db, state: rooms::state::Service { db, }, state_accessor: rooms::state_accessor::Service { db, #[allow( clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation )] server_visibility_cache: StdMutex::new(LruCache::new( (100.0 * config.cache_capacity_modifier) as usize, )), #[allow( clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation )] user_visibility_cache: StdMutex::new(LruCache::new( (100.0 * config.cache_capacity_modifier) as usize, )), }, state_cache: rooms::state_cache::Service { db, }, state_compressor: rooms::state_compressor::Service { db, #[allow( clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation )] stateinfo_cache: StdMutex::new(LruCache::new( (100.0 * config.cache_capacity_modifier) as usize, )), }, timeline: rooms::timeline::Service { db, }, threads: rooms::threads::Service { db, }, spaces: rooms::spaces::Service { roomid_spacechunk_cache: Mutex::new(LruCache::new(200)), }, user: db, }, transaction_ids: db, uiaa: uiaa::Service { db, }, users: users::Service { db, connections: StdMutex::new(BTreeMap::new()), }, account_data: db, admin: admin::Service::build(), key_backups: db, media: media::Service { db, }, sending: sending::Service::build(db, &config), globals: globals::Service::load(db, config)?, }) } async fn memory_usage(&self) -> String { let lazy_load_waiting = self.rooms.lazy_loading.lazy_load_waiting.lock().await.len(); let server_visibility_cache = self .rooms .state_accessor .server_visibility_cache .lock() .unwrap() .len(); let user_visibility_cache = self .rooms .state_accessor .user_visibility_cache .lock() .unwrap() .len(); let stateinfo_cache = self.rooms.state_compressor.stateinfo_cache.lock().unwrap().len(); let roomid_spacechunk_cache = self.rooms.spaces.roomid_spacechunk_cache.lock().await.len(); format!( "\ lazy_load_waiting: {lazy_load_waiting} server_visibility_cache: {server_visibility_cache} user_visibility_cache: {user_visibility_cache} stateinfo_cache: {stateinfo_cache} roomid_spacechunk_cache: {roomid_spacechunk_cache}" ) } async fn clear_caches(&self, amount: u32) { if amount > 0 { self.rooms.lazy_loading.lazy_load_waiting.lock().await.clear(); } if amount > 1 { self.rooms .state_accessor .server_visibility_cache .lock() .unwrap() .clear(); } if amount > 2 { self.rooms .state_accessor .user_visibility_cache .lock() .unwrap() .clear(); } if amount > 3 { self.rooms.state_compressor.stateinfo_cache.lock().unwrap().clear(); } if amount > 5 { self.rooms.spaces.roomid_spacechunk_cache.lock().await.clear(); } } }