impl crate::Service for Service

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk 2024-07-04 03:26:19 +00:00
parent 177c9e8bfa
commit e125af620e
44 changed files with 673 additions and 548 deletions

View file

@ -15,14 +15,18 @@ pub(super) async fn enable_room(_body: Vec<&str>, room_id: Box<RoomId>) -> Resul
} }
pub(super) async fn incoming_federation(_body: Vec<&str>) -> Result<RoomMessageEventContent> { pub(super) async fn incoming_federation(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
let map = services().globals.roomid_federationhandletime.read().await; let map = services()
.globals
.roomid_federationhandletime
.read()
.expect("locked");
let mut msg = format!("Handling {} incoming pdus:\n", map.len()); let mut msg = format!("Handling {} incoming pdus:\n", map.len());
for (r, (e, i)) in map.iter() { for (r, (e, i)) in map.iter() {
let elapsed = i.elapsed(); let elapsed = i.elapsed();
writeln!(msg, "{} {}: {}m{}s", r, e, elapsed.as_secs() / 60, elapsed.as_secs() % 60,) writeln!(msg, "{} {}: {}m{}s", r, e, elapsed.as_secs() / 60, elapsed.as_secs() % 60)?;
.expect("should be able to write to string buffer");
} }
Ok(RoomMessageEventContent::text_plain(&msg)) Ok(RoomMessageEventContent::text_plain(&msg))
} }

View file

@ -27,12 +27,12 @@ pub(super) async fn show_config(_body: Vec<&str>) -> Result<RoomMessageEventCont
} }
pub(super) async fn memory_usage(_body: Vec<&str>) -> Result<RoomMessageEventContent> { pub(super) async fn memory_usage(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
let response0 = services().memory_usage().await; let response0 = services().memory_usage().await?;
let response1 = services().globals.db.memory_usage(); let response1 = services().db.db.memory_usage()?;
let response2 = conduit::alloc::memory_usage(); let response2 = conduit::alloc::memory_usage();
Ok(RoomMessageEventContent::text_plain(format!( Ok(RoomMessageEventContent::text_plain(format!(
"Services:\n{response0}\n\nDatabase:\n{response1}\n{}", "Services:\n{response0}\nDatabase:\n{response1}\n{}",
if !response2.is_empty() { if !response2.is_empty() {
format!("Allocator:\n {response2}") format!("Allocator:\n {response2}")
} else { } else {
@ -41,14 +41,8 @@ pub(super) async fn memory_usage(_body: Vec<&str>) -> Result<RoomMessageEventCon
))) )))
} }
pub(super) async fn clear_database_caches(_body: Vec<&str>, amount: u32) -> Result<RoomMessageEventContent> { pub(super) async fn clear_caches(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
services().globals.db.clear_caches(amount); services().clear_cache().await;
Ok(RoomMessageEventContent::text_plain("Done."))
}
pub(super) async fn clear_service_caches(_body: Vec<&str>, amount: u32) -> Result<RoomMessageEventContent> {
services().clear_caches(amount).await;
Ok(RoomMessageEventContent::text_plain("Done.")) Ok(RoomMessageEventContent::text_plain("Done."))
} }

View file

@ -18,17 +18,8 @@ pub(super) enum ServerCommand {
/// - Print database memory usage statistics /// - Print database memory usage statistics
MemoryUsage, MemoryUsage,
/// - Clears all of Conduit's database caches with index smaller than the /// - Clears all of Conduwuit's caches
/// amount ClearCaches,
ClearDatabaseCaches {
amount: u32,
},
/// - Clears all of Conduit's service caches with index smaller than the
/// amount
ClearServiceCaches {
amount: u32,
},
/// - Performs an online backup of the database (only available for RocksDB /// - Performs an online backup of the database (only available for RocksDB
/// at the moment) /// at the moment)
@ -65,12 +56,7 @@ pub(super) async fn process(command: ServerCommand, body: Vec<&str>) -> Result<R
ServerCommand::Uptime => uptime(body).await?, ServerCommand::Uptime => uptime(body).await?,
ServerCommand::ShowConfig => show_config(body).await?, ServerCommand::ShowConfig => show_config(body).await?,
ServerCommand::MemoryUsage => memory_usage(body).await?, ServerCommand::MemoryUsage => memory_usage(body).await?,
ServerCommand::ClearDatabaseCaches { ServerCommand::ClearCaches => clear_caches(body).await?,
amount,
} => clear_database_caches(body, amount).await?,
ServerCommand::ClearServiceCaches {
amount,
} => clear_service_caches(body, amount).await?,
ServerCommand::ListBackups => list_backups(body).await?, ServerCommand::ListBackups => list_backups(body).await?,
ServerCommand::BackupDatabase => backup_database(body).await?, ServerCommand::BackupDatabase => backup_database(body).await?,
ServerCommand::ListDatabaseFiles => list_database_files(body).await?, ServerCommand::ListDatabaseFiles => list_database_files(body).await?,

View file

@ -334,7 +334,7 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool + Send>(
.globals .globals
.bad_query_ratelimiter .bad_query_ratelimiter
.write() .write()
.await .expect("locked")
.entry(id) .entry(id)
{ {
hash_map::Entry::Vacant(e) => { hash_map::Entry::Vacant(e) => {
@ -353,7 +353,7 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool + Send>(
.globals .globals
.bad_query_ratelimiter .bad_query_ratelimiter
.read() .read()
.await .expect("locked")
.get(server) .get(server)
{ {
// Exponential backoff // Exponential backoff

View file

@ -1343,7 +1343,7 @@ pub async fn validate_and_add_event_id(
.globals .globals
.bad_event_ratelimiter .bad_event_ratelimiter
.write() .write()
.await .expect("locked")
.entry(id) .entry(id)
{ {
Entry::Vacant(e) => { Entry::Vacant(e) => {
@ -1359,7 +1359,7 @@ pub async fn validate_and_add_event_id(
.globals .globals
.bad_event_ratelimiter .bad_event_ratelimiter
.read() .read()
.await .expect("locked")
.get(&event_id) .get(&event_id)
{ {
// Exponential backoff // Exponential backoff

View file

@ -19,7 +19,7 @@ pub fn memory_usage() -> String {
let resident = stats::resident::read().unwrap_or_default() as f64 / 1024.0 / 1024.0; let resident = stats::resident::read().unwrap_or_default() as f64 / 1024.0 / 1024.0;
let retained = stats::retained::read().unwrap_or_default() as f64 / 1024.0 / 1024.0; let retained = stats::retained::read().unwrap_or_default() as f64 / 1024.0 / 1024.0;
format!( format!(
" allocated: {allocated:.2} MiB\n active: {active:.2} MiB\n mapped: {mapped:.2} MiB\n metadata: {metadata:.2} \ "allocated: {allocated:.2} MiB\n active: {active:.2} MiB\n mapped: {mapped:.2} MiB\n metadata: {metadata:.2} \
MiB\n resident: {resident:.2} MiB\n retained: {retained:.2} MiB\n " MiB\n resident: {resident:.2} MiB\n retained: {retained:.2} MiB\n "
) )
} }

View file

@ -2,9 +2,8 @@ mod data;
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, sync::Arc};
use conduit::{Result, Server}; use conduit::Result;
use data::Data; use data::Data;
use database::Database;
use ruma::{ use ruma::{
events::{AnyEphemeralRoomEvent, RoomAccountDataEventType}, events::{AnyEphemeralRoomEvent, RoomAccountDataEventType},
serde::Raw, serde::Raw,
@ -15,13 +14,17 @@ pub struct Service {
db: Data, db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
/// Places one event in the account data of the user and removes the /// Places one event in the account data of the user and removes the
/// previous entry. /// previous entry.
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]

View file

@ -4,9 +4,9 @@ mod grant;
use std::{future::Future, pin::Pin, sync::Arc}; use std::{future::Future, pin::Pin, sync::Arc};
use conduit::{error, utils::mutex_map, Error, Result, Server}; use async_trait::async_trait;
use conduit::{error, utils::mutex_map, Error, Result};
pub use create::create_admin_room; pub use create::create_admin_room;
use database::Database;
pub use grant::make_user_admin; pub use grant::make_user_admin;
use loole::{Receiver, Sender}; use loole::{Receiver, Sender};
use ruma::{ use ruma::{
@ -43,8 +43,9 @@ pub struct Command {
pub reply_id: Option<OwnedEventId>, pub reply_id: Option<OwnedEventId>,
} }
impl Service { #[async_trait]
pub fn build(_server: &Arc<Server>, _db: &Arc<Database>) -> Result<Arc<Self>> { impl crate::Service for Service {
fn build(_args: crate::Args<'_>) -> Result<Arc<Self>> {
let (sender, receiver) = loole::bounded(COMMAND_QUEUE_LIMIT); let (sender, receiver) = loole::bounded(COMMAND_QUEUE_LIMIT);
Ok(Arc::new(Self { Ok(Arc::new(Self {
sender, sender,
@ -56,8 +57,8 @@ impl Service {
})) }))
} }
pub async fn start_handler(self: &Arc<Self>) { async fn start(self: Arc<Self>) -> Result<()> {
let self_ = Arc::clone(self); let self_ = Arc::clone(&self);
let handle = services().server.runtime().spawn(async move { let handle = services().server.runtime().spawn(async move {
self_ self_
.handler() .handler()
@ -66,9 +67,11 @@ impl Service {
}); });
_ = self.handler_join.lock().await.insert(handle); _ = self.handler_join.lock().await.insert(handle);
Ok(())
} }
pub fn interrupt(&self) { fn interrupt(&self) {
#[cfg(feature = "console")] #[cfg(feature = "console")]
self.console.interrupt(); self.console.interrupt();
@ -77,7 +80,7 @@ impl Service {
} }
} }
pub async fn close(&self) { async fn stop(&self) {
self.interrupt(); self.interrupt();
#[cfg(feature = "console")] #[cfg(feature = "console")]
@ -90,6 +93,10 @@ impl Service {
} }
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
pub async fn send_text(&self, body: &str) { pub async fn send_text(&self, body: &str) {
self.send_message(RoomMessageEventContent::text_markdown(body)) self.send_message(RoomMessageEventContent::text_markdown(body))
.await; .await;

View file

@ -2,9 +2,8 @@ mod data;
use std::{collections::BTreeMap, sync::Arc}; use std::{collections::BTreeMap, sync::Arc};
use conduit::{Result, Server}; use conduit::Result;
use data::Data; use data::Data;
use database::Database;
use futures_util::Future; use futures_util::Future;
use regex::RegexSet; use regex::RegexSet;
use ruma::{ use ruma::{
@ -119,10 +118,10 @@ pub struct Service {
registration_info: RwLock<BTreeMap<String, RegistrationInfo>>, registration_info: RwLock<BTreeMap<String, RegistrationInfo>>,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
let mut registration_info = BTreeMap::new(); let mut registration_info = BTreeMap::new();
let db = Data::new(db); let db = Data::new(args.db);
// Inserting registrations into cache // Inserting registrations into cache
for appservice in iter_ids(&db)? { for appservice in iter_ids(&db)? {
registration_info.insert( registration_info.insert(
@ -134,12 +133,16 @@ impl Service {
); );
} }
Ok(Self { Ok(Arc::new(Self {
db, db,
registration_info: RwLock::new(registration_info), registration_info: RwLock::new(registration_info),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
pub fn all(&self) -> Result<Vec<(String, Registration)>> { iter_ids(&self.db) } pub fn all(&self) -> Result<Vec<(String, Registration)>> { iter_ids(&self.db) }
/// Registers an appservice and returns the ID to the caller /// Registers an appservice and returns the ID to the caller

View file

@ -208,41 +208,6 @@ impl Data {
pub fn cleanup(&self) -> Result<()> { self.db.db.cleanup() } pub fn cleanup(&self) -> Result<()> { self.db.db.cleanup() }
pub fn memory_usage(&self) -> String {
let (auth_chain_cache, max_auth_chain_cache) = services().rooms.auth_chain.get_cache_usage();
let (appservice_in_room_cache, max_appservice_in_room_cache) = services()
.rooms
.state_cache
.get_appservice_in_room_cache_usage();
let (lasttimelinecount_cache, max_lasttimelinecount_cache) = services()
.rooms
.timeline
.get_lasttimelinecount_cache_usage();
format!(
"auth_chain_cache: {auth_chain_cache} / {max_auth_chain_cache}\nappservice_in_room_cache: \
{appservice_in_room_cache} / {max_appservice_in_room_cache}\nlasttimelinecount_cache: \
{lasttimelinecount_cache} / {max_lasttimelinecount_cache}\n\n{}",
self.db.db.memory_usage().unwrap_or_default()
)
}
#[allow(clippy::unused_self)]
pub fn clear_caches(&self, amount: u32) {
if amount > 1 {
services().rooms.auth_chain.clear_cache();
}
if amount > 2 {
services()
.rooms
.state_cache
.clear_appservice_in_room_cache();
}
if amount > 3 {
services().rooms.timeline.clear_lasttimelinecount_cache();
}
}
pub fn load_keypair(&self) -> Result<Ed25519KeyPair> { pub fn load_keypair(&self) -> Result<Ed25519KeyPair> {
let keypair_bytes = self.global.get(b"keypair")?.map_or_else( let keypair_bytes = self.global.get(b"keypair")?.map_or_else(
|| { || {

View file

@ -7,13 +7,13 @@ pub(super) mod updates;
use std::{ use std::{
collections::{BTreeMap, HashMap}, collections::{BTreeMap, HashMap},
sync::Arc, fmt::Write,
sync::{Arc, RwLock},
time::Instant, time::Instant,
}; };
use conduit::{error, trace, utils::MutexMap, Config, Result, Server}; use conduit::{error, trace, utils::MutexMap, Config, Result};
use data::Data; use data::Data;
use database::Database;
use ipaddress::IPAddress; use ipaddress::IPAddress;
use regex::RegexSet; use regex::RegexSet;
use ruma::{ use ruma::{
@ -25,10 +25,7 @@ use ruma::{
DeviceId, OwnedEventId, OwnedRoomAliasId, OwnedRoomId, OwnedServerName, OwnedServerSigningKeyId, OwnedUserId, DeviceId, OwnedEventId, OwnedRoomAliasId, OwnedRoomId, OwnedServerName, OwnedServerSigningKeyId, OwnedUserId,
RoomAliasId, RoomVersionId, ServerName, UserId, RoomAliasId, RoomVersionId, ServerName, UserId,
}; };
use tokio::{ use tokio::{sync::Mutex, task::JoinHandle};
sync::{Mutex, RwLock},
task::JoinHandle,
};
use url::Url; use url::Url;
use crate::services; use crate::services;
@ -59,10 +56,10 @@ pub struct Service {
pub admin_alias: OwnedRoomAliasId, pub admin_alias: OwnedRoomAliasId,
} }
impl Service { impl crate::Service for Service {
pub fn build(server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
let config = &server.config; let config = &args.server.config;
let db = Data::new(db); let db = Data::new(args.db);
let keypair = db.load_keypair(); let keypair = db.load_keypair();
let keypair = match keypair { let keypair = match keypair {
@ -133,9 +130,59 @@ impl Service {
s.config.default_room_version = crate::config::default_default_room_version(); s.config.default_room_version = crate::config::default_default_room_version();
}; };
Ok(s) Ok(Arc::new(s))
} }
fn memory_usage(&self, out: &mut dyn Write) -> Result<()> {
self.resolver.memory_usage(out)?;
let bad_event_ratelimiter = self
.bad_event_ratelimiter
.read()
.expect("locked for reading")
.len();
writeln!(out, "bad_event_ratelimiter: {bad_event_ratelimiter}")?;
let bad_query_ratelimiter = self
.bad_query_ratelimiter
.read()
.expect("locked for reading")
.len();
writeln!(out, "bad_query_ratelimiter: {bad_query_ratelimiter}")?;
let bad_signature_ratelimiter = self
.bad_signature_ratelimiter
.read()
.expect("locked for reading")
.len();
writeln!(out, "bad_signature_ratelimiter: {bad_signature_ratelimiter}")?;
Ok(())
}
fn clear_cache(&self) {
self.resolver.clear_cache();
self.bad_event_ratelimiter
.write()
.expect("locked for writing")
.clear();
self.bad_query_ratelimiter
.write()
.expect("locked for writing")
.clear();
self.bad_signature_ratelimiter
.write()
.expect("locked for writing")
.clear();
}
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
/// Returns this server's keypair. /// Returns this server's keypair.
pub fn keypair(&self) -> &ruma::signatures::Ed25519KeyPair { &self.keypair } pub fn keypair(&self) -> &ruma::signatures::Ed25519KeyPair { &self.keypair }

View file

@ -1,12 +1,13 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
fmt::Write,
future, iter, future, iter,
net::{IpAddr, SocketAddr}, net::{IpAddr, SocketAddr},
sync::{Arc, RwLock}, sync::{Arc, RwLock},
time::Duration, time::Duration,
}; };
use conduit::{error, Config, Error}; use conduit::{error, Config, Error, Result};
use hickory_resolver::TokioAsyncResolver; use hickory_resolver::TokioAsyncResolver;
use reqwest::dns::{Addrs, Name, Resolve, Resolving}; use reqwest::dns::{Addrs, Name, Resolve, Resolving};
use ruma::OwnedServerName; use ruma::OwnedServerName;
@ -30,7 +31,7 @@ pub struct Hooked {
impl Resolver { impl Resolver {
#[allow(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)] #[allow(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)]
pub fn new(config: &Config) -> Self { pub(super) fn new(config: &Config) -> Self {
let (sys_conf, mut opts) = hickory_resolver::system_conf::read_system_conf() let (sys_conf, mut opts) = hickory_resolver::system_conf::read_system_conf()
.map_err(|e| { .map_err(|e| {
error!("Failed to set up hickory dns resolver with system config: {e}"); error!("Failed to set up hickory dns resolver with system config: {e}");
@ -92,6 +93,22 @@ impl Resolver {
}), }),
} }
} }
pub(super) fn memory_usage(&self, out: &mut dyn Write) -> Result<()> {
let resolver_overrides_cache = self.overrides.read().expect("locked for reading").len();
writeln!(out, "resolver_overrides_cache: {resolver_overrides_cache}")?;
let resolver_destinations_cache = self.destinations.read().expect("locked for reading").len();
writeln!(out, "resolver_destinations_cache: {resolver_destinations_cache}")?;
Ok(())
}
pub(super) fn clear_cache(&self) {
self.overrides.write().expect("write locked").clear();
self.destinations.write().expect("write locked").clear();
self.resolver.clear_cache();
}
} }
impl Resolve for Resolver { impl Resolve for Resolver {

View file

@ -2,9 +2,8 @@ mod data;
use std::{collections::BTreeMap, sync::Arc}; use std::{collections::BTreeMap, sync::Arc};
use conduit::{Result, Server}; use conduit::Result;
use data::Data; use data::Data;
use database::Database;
use ruma::{ use ruma::{
api::client::backup::{BackupAlgorithm, KeyBackupData, RoomKeyBackup}, api::client::backup::{BackupAlgorithm, KeyBackupData, RoomKeyBackup},
serde::Raw, serde::Raw,
@ -15,13 +14,17 @@ pub struct Service {
db: Data, db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
pub fn create_backup(&self, user_id: &UserId, backup_metadata: &Raw<BackupAlgorithm>) -> Result<String> { pub fn create_backup(&self, user_id: &UserId, backup_metadata: &Raw<BackupAlgorithm>) -> Result<String> {
self.db.create_backup(user_id, backup_metadata) self.db.create_backup(user_id, backup_metadata)
} }

View file

@ -6,7 +6,6 @@ use std::{collections::HashMap, io::Cursor, path::PathBuf, sync::Arc, time::Syst
use base64::{engine::general_purpose, Engine as _}; use base64::{engine::general_purpose, Engine as _};
use conduit::{debug, debug_error, error, utils, Error, Result, Server}; use conduit::{debug, debug_error, error, utils, Error, Result, Server};
use data::Data; use data::Data;
use database::Database;
use image::imageops::FilterType; use image::imageops::FilterType;
use ruma::{OwnedMxcUri, OwnedUserId}; use ruma::{OwnedMxcUri, OwnedUserId};
use serde::Serialize; use serde::Serialize;
@ -48,15 +47,19 @@ pub struct Service {
pub url_preview_mutex: RwLock<HashMap<String, Arc<Mutex<()>>>>, pub url_preview_mutex: RwLock<HashMap<String, Arc<Mutex<()>>>>,
} }
impl Service { impl crate::Service for Service {
pub fn build(server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
server: server.clone(), server: args.server.clone(),
db: Data::new(db), db: Data::new(args.db),
url_preview_mutex: RwLock::new(HashMap::new()), url_preview_mutex: RwLock::new(HashMap::new()),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
/// Uploads a file. /// Uploads a file.
pub async fn create( pub async fn create(
&self, sender_user: Option<OwnedUserId>, mxc: &str, content_disposition: Option<&str>, &self, sender_user: Option<OwnedUserId>, mxc: &str, content_disposition: Option<&str>,

View file

@ -1,3 +1,6 @@
#![allow(refining_impl_trait)]
mod service;
pub mod services; pub mod services;
pub mod account_data; pub mod account_data;
@ -22,6 +25,7 @@ use std::sync::{Arc, RwLock};
pub(crate) use conduit::{config, debug_error, debug_info, debug_warn, utils, Config, Error, Result, Server}; pub(crate) use conduit::{config, debug_error, debug_info, debug_warn, utils, Config, Error, Result, Server};
pub use conduit::{pdu, PduBuilder, PduCount, PduEvent}; pub use conduit::{pdu, PduBuilder, PduCount, PduEvent};
use database::Database; use database::Database;
pub(crate) use service::{Args, Service};
pub use crate::{ pub use crate::{
globals::{server_is_ours, user_is_local}, globals::{server_is_ours, user_is_local},
@ -36,7 +40,7 @@ static SERVICES: RwLock<Option<&Services>> = RwLock::new(None);
#[allow(clippy::let_underscore_must_use)] #[allow(clippy::let_underscore_must_use)]
pub async fn init(server: &Arc<Server>) -> Result<()> { pub async fn init(server: &Arc<Server>) -> Result<()> {
let d = Arc::new(Database::open(server).await?); let d = Arc::new(Database::open(server).await?);
let s = Box::new(Services::build(server.clone(), d.clone()).await?); let s = Box::new(Services::build(server.clone(), d)?);
_ = SERVICES.write().expect("write locked").insert(Box::leak(s)); _ = SERVICES.write().expect("write locked").insert(Box::leak(s));
Ok(()) Ok(())

View file

@ -2,9 +2,9 @@ mod data;
use std::{sync::Arc, time::Duration}; use std::{sync::Arc, time::Duration};
use conduit::{debug, error, utils, Error, Result, Server}; use async_trait::async_trait;
use conduit::{debug, error, utils, Error, Result};
use data::Data; use data::Data;
use database::Database;
use futures_util::{stream::FuturesUnordered, StreamExt}; use futures_util::{stream::FuturesUnordered, StreamExt};
use ruma::{ use ruma::{
events::presence::{PresenceEvent, PresenceEventContent}, events::presence::{PresenceEvent, PresenceEventContent},
@ -81,12 +81,13 @@ pub struct Service {
timeout_remote_users: bool, timeout_remote_users: bool,
} }
impl Service { #[async_trait]
pub fn build(server: &Arc<Server>, db: &Arc<Database>) -> Result<Arc<Self>> { impl crate::Service for Service {
let config = &server.config; fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
let config = &args.server.config;
let (timer_sender, timer_receiver) = loole::unbounded(); let (timer_sender, timer_receiver) = loole::unbounded();
Ok(Arc::new(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
timer_sender, timer_sender,
timer_receiver: Mutex::new(timer_receiver), timer_receiver: Mutex::new(timer_receiver),
handler_join: Mutex::new(None), handler_join: Mutex::new(None),
@ -94,8 +95,10 @@ impl Service {
})) }))
} }
pub async fn start_handler(self: &Arc<Self>) { async fn start(self: Arc<Self>) -> Result<()> {
let self_ = Arc::clone(self); //TODO: if self.globals.config.allow_local_presence { return; }
let self_ = Arc::clone(&self);
let handle = services().server.runtime().spawn(async move { let handle = services().server.runtime().spawn(async move {
self_ self_
.handler() .handler()
@ -104,9 +107,11 @@ impl Service {
}); });
_ = self.handler_join.lock().await.insert(handle); _ = self.handler_join.lock().await.insert(handle);
Ok(())
} }
pub async fn close(&self) { async fn stop(&self) {
self.interrupt(); self.interrupt();
if let Some(handler_join) = self.handler_join.lock().await.take() { if let Some(handler_join) = self.handler_join.lock().await.take() {
if let Err(e) = handler_join.await { if let Err(e) = handler_join.await {
@ -115,12 +120,16 @@ impl Service {
} }
} }
pub fn interrupt(&self) { fn interrupt(&self) {
if !self.timer_sender.is_closed() { if !self.timer_sender.is_closed() {
self.timer_sender.close(); self.timer_sender.close();
} }
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
/// Returns the latest presence event for the given user. /// Returns the latest presence event for the given user.
pub fn get_presence(&self, user_id: &UserId) -> Result<Option<PresenceEvent>> { pub fn get_presence(&self, user_id: &UserId) -> Result<Option<PresenceEvent>> {
if let Some((_, presence)) = self.db.get_presence(user_id)? { if let Some((_, presence)) = self.db.get_presence(user_id)? {

View file

@ -3,9 +3,8 @@ mod data;
use std::{fmt::Debug, mem, sync::Arc}; use std::{fmt::Debug, mem, sync::Arc};
use bytes::BytesMut; use bytes::BytesMut;
use conduit::{debug_info, info, trace, warn, Error, Result, Server}; use conduit::{debug_info, info, trace, warn, Error, Result};
use data::Data; use data::Data;
use database::Database;
use ipaddress::IPAddress; use ipaddress::IPAddress;
use ruma::{ use ruma::{
api::{ api::{
@ -30,13 +29,17 @@ pub struct Service {
db: Data, db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
pub fn set_pusher(&self, sender: &UserId, pusher: &set_pusher::v3::PusherAction) -> Result<()> { pub fn set_pusher(&self, sender: &UserId, pusher: &set_pusher::v3::PusherAction) -> Result<()> {
self.db.set_pusher(sender, pusher) self.db.set_pusher(sender, pusher)
} }

View file

@ -3,9 +3,8 @@ mod remote;
use std::sync::Arc; use std::sync::Arc;
use conduit::{Error, Result, Server}; use conduit::{Error, Result};
use data::Data; use data::Data;
use database::Database;
use ruma::{ use ruma::{
api::{appservice, client::error::ErrorKind}, api::{appservice, client::error::ErrorKind},
events::{ events::{
@ -21,13 +20,17 @@ pub struct Service {
db: Data, db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
#[tracing::instrument(skip(self))] #[tracing::instrument(skip(self))]
pub fn set_alias(&self, alias: &RoomAliasId, room_id: &RoomId, user_id: &UserId) -> Result<()> { pub fn set_alias(&self, alias: &RoomAliasId, room_id: &RoomId, user_id: &UserId) -> Result<()> {
if alias == services().globals.admin_alias && user_id != services().globals.server_user { if alias == services().globals.admin_alias && user_id != services().globals.server_user {

View file

@ -5,9 +5,8 @@ use std::{
sync::Arc, sync::Arc,
}; };
use conduit::{debug, error, trace, warn, Error, Result, Server}; use conduit::{debug, error, trace, warn, Error, Result};
use data::Data; use data::Data;
use database::Database;
use ruma::{api::client::error::ErrorKind, EventId, RoomId}; use ruma::{api::client::error::ErrorKind, EventId, RoomId};
use crate::services; use crate::services;
@ -16,13 +15,17 @@ pub struct Service {
db: Data, db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(server, db), db: Data::new(args.server, args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
pub async fn event_ids_iter<'a>( pub async fn event_ids_iter<'a>(
&self, room_id: &RoomId, starting_events_: Vec<Arc<EventId>>, &self, room_id: &RoomId, starting_events_: Vec<Arc<EventId>>,
) -> Result<impl Iterator<Item = Arc<EventId>> + 'a> { ) -> Result<impl Iterator<Item = Arc<EventId>> + 'a> {

View file

@ -2,9 +2,7 @@ mod data;
use std::sync::Arc; use std::sync::Arc;
use conduit::Server;
use data::Data; use data::Data;
use database::Database;
use ruma::{OwnedRoomId, RoomId}; use ruma::{OwnedRoomId, RoomId};
use crate::Result; use crate::Result;
@ -13,13 +11,17 @@ pub struct Service {
db: Data, db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
#[tracing::instrument(skip(self))] #[tracing::instrument(skip(self))]
pub fn set_public(&self, room_id: &RoomId) -> Result<()> { self.db.set_public(room_id) } pub fn set_public(&self, room_id: &RoomId) -> Result<()> { self.db.set_public(room_id) }

View file

@ -9,8 +9,7 @@ use std::{
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use conduit::{debug_error, debug_info, Error, Result, Server}; use conduit::{debug_error, debug_info, Error, Result};
use database::Database;
use futures_util::Future; use futures_util::Future;
pub use parse_incoming_pdu::parse_incoming_pdu; pub use parse_incoming_pdu::parse_incoming_pdu;
use ruma::{ use ruma::{
@ -45,9 +44,13 @@ type AsyncRecursiveCanonicalJsonVec<'a> =
type AsyncRecursiveCanonicalJsonResult<'a> = type AsyncRecursiveCanonicalJsonResult<'a> =
AsyncRecursiveType<'a, Result<(Arc<PduEvent>, BTreeMap<String, CanonicalJsonValue>)>>; AsyncRecursiveType<'a, Result<(Arc<PduEvent>, BTreeMap<String, CanonicalJsonValue>)>>;
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, _db: &Arc<Database>) -> Result<Self> { Ok(Self {}) } fn build(_args: crate::Args<'_>) -> Result<Arc<Self>> { Ok(Arc::new(Self {})) }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
/// When receiving an event one needs to: /// When receiving an event one needs to:
/// 0. Check the server is in the room /// 0. Check the server is in the room
/// 1. Skip the PDU if we already know about it /// 1. Skip the PDU if we already know about it
@ -180,7 +183,7 @@ impl Service {
.globals .globals
.bad_event_ratelimiter .bad_event_ratelimiter
.write() .write()
.await .expect("locked")
.entry((*prev_id).to_owned()) .entry((*prev_id).to_owned())
{ {
hash_map::Entry::Vacant(e) => { hash_map::Entry::Vacant(e) => {
@ -200,7 +203,7 @@ impl Service {
.globals .globals
.roomid_federationhandletime .roomid_federationhandletime
.write() .write()
.await .expect("locked")
.insert(room_id.to_owned(), (event_id.to_owned(), start_time)); .insert(room_id.to_owned(), (event_id.to_owned(), start_time));
let r = self let r = self
@ -211,7 +214,7 @@ impl Service {
.globals .globals
.roomid_federationhandletime .roomid_federationhandletime
.write() .write()
.await .expect("locked")
.remove(&room_id.to_owned()); .remove(&room_id.to_owned());
r r
@ -245,7 +248,7 @@ impl Service {
.globals .globals
.bad_event_ratelimiter .bad_event_ratelimiter
.read() .read()
.await .expect("locked")
.get(prev_id) .get(prev_id)
{ {
// Exponential backoff // Exponential backoff
@ -274,7 +277,7 @@ impl Service {
.globals .globals
.roomid_federationhandletime .roomid_federationhandletime
.write() .write()
.await .expect("locked")
.insert(room_id.to_owned(), ((*prev_id).to_owned(), start_time)); .insert(room_id.to_owned(), ((*prev_id).to_owned(), start_time));
self.upgrade_outlier_to_timeline_pdu(pdu, json, create_event, origin, room_id, pub_key_map) self.upgrade_outlier_to_timeline_pdu(pdu, json, create_event, origin, room_id, pub_key_map)
@ -284,7 +287,7 @@ impl Service {
.globals .globals
.roomid_federationhandletime .roomid_federationhandletime
.write() .write()
.await .expect("locked")
.remove(&room_id.to_owned()); .remove(&room_id.to_owned());
debug!( debug!(
@ -1043,7 +1046,7 @@ impl Service {
.globals .globals
.bad_event_ratelimiter .bad_event_ratelimiter
.write() .write()
.await .expect("locked")
.entry(id) .entry(id)
{ {
hash_map::Entry::Vacant(e) => { hash_map::Entry::Vacant(e) => {
@ -1076,7 +1079,7 @@ impl Service {
.globals .globals
.bad_event_ratelimiter .bad_event_ratelimiter
.read() .read()
.await .expect("locked")
.get(&*next_id) .get(&*next_id)
{ {
// Exponential backoff // Exponential backoff
@ -1184,7 +1187,7 @@ impl Service {
.globals .globals
.bad_event_ratelimiter .bad_event_ratelimiter
.read() .read()
.await .expect("locked")
.get(&**next_id) .get(&**next_id)
{ {
// Exponential backoff // Exponential backoff

View file

@ -2,14 +2,12 @@ mod data;
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
sync::Arc, fmt::Write,
sync::{Arc, Mutex},
}; };
use conduit::Server;
use data::Data; use data::Data;
use database::Database;
use ruma::{DeviceId, OwnedDeviceId, OwnedRoomId, OwnedUserId, RoomId, UserId}; use ruma::{DeviceId, OwnedDeviceId, OwnedRoomId, OwnedUserId, RoomId, UserId};
use tokio::sync::Mutex;
use crate::{PduCount, Result}; use crate::{PduCount, Result};
@ -20,14 +18,27 @@ pub struct Service {
pub lazy_load_waiting: Mutex<HashMap<(OwnedUserId, OwnedDeviceId, OwnedRoomId, PduCount), HashSet<OwnedUserId>>>, pub lazy_load_waiting: Mutex<HashMap<(OwnedUserId, OwnedDeviceId, OwnedRoomId, PduCount), HashSet<OwnedUserId>>>,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
lazy_load_waiting: Mutex::new(HashMap::new()), lazy_load_waiting: Mutex::new(HashMap::new()),
}) }))
} }
fn memory_usage(&self, out: &mut dyn Write) -> Result<()> {
let lazy_load_waiting = self.lazy_load_waiting.lock().expect("locked").len();
writeln!(out, "lazy_load_waiting: {lazy_load_waiting}")?;
Ok(())
}
fn clear_cache(&self) { self.lazy_load_waiting.lock().expect("locked").clear(); }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
#[tracing::instrument(skip(self))] #[tracing::instrument(skip(self))]
pub fn lazy_load_was_sent_before( pub fn lazy_load_was_sent_before(
&self, user_id: &UserId, device_id: &DeviceId, room_id: &RoomId, ll_user: &UserId, &self, user_id: &UserId, device_id: &DeviceId, room_id: &RoomId, ll_user: &UserId,
@ -43,7 +54,7 @@ impl Service {
) { ) {
self.lazy_load_waiting self.lazy_load_waiting
.lock() .lock()
.await .expect("locked")
.insert((user_id.to_owned(), device_id.to_owned(), room_id.to_owned(), count), lazy_load); .insert((user_id.to_owned(), device_id.to_owned(), room_id.to_owned(), count), lazy_load);
} }
@ -51,7 +62,7 @@ impl Service {
pub async fn lazy_load_confirm_delivery( pub async fn lazy_load_confirm_delivery(
&self, user_id: &UserId, device_id: &DeviceId, room_id: &RoomId, since: PduCount, &self, user_id: &UserId, device_id: &DeviceId, room_id: &RoomId, since: PduCount,
) -> Result<()> { ) -> Result<()> {
if let Some(user_ids) = self.lazy_load_waiting.lock().await.remove(&( if let Some(user_ids) = self.lazy_load_waiting.lock().expect("locked").remove(&(
user_id.to_owned(), user_id.to_owned(),
device_id.to_owned(), device_id.to_owned(),
room_id.to_owned(), room_id.to_owned(),

View file

@ -2,22 +2,25 @@ mod data;
use std::sync::Arc; use std::sync::Arc;
use conduit::{Result, Server}; use conduit::Result;
use data::Data; use data::Data;
use database::Database;
use ruma::{OwnedRoomId, RoomId}; use ruma::{OwnedRoomId, RoomId};
pub struct Service { pub struct Service {
db: Data, db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
/// Checks if a room exists. /// Checks if a room exists.
#[tracing::instrument(skip(self))] #[tracing::instrument(skip(self))]
pub fn exists(&self, room_id: &RoomId) -> Result<bool> { self.db.exists(room_id) } pub fn exists(&self, room_id: &RoomId) -> Result<bool> { self.db.exists(room_id) }

View file

@ -19,25 +19,27 @@ pub mod timeline;
pub mod typing; pub mod typing;
pub mod user; pub mod user;
use std::sync::Arc;
pub struct Service { pub struct Service {
pub alias: alias::Service, pub alias: Arc<alias::Service>,
pub auth_chain: auth_chain::Service, pub auth_chain: Arc<auth_chain::Service>,
pub directory: directory::Service, pub directory: Arc<directory::Service>,
pub event_handler: event_handler::Service, pub event_handler: Arc<event_handler::Service>,
pub lazy_loading: lazy_loading::Service, pub lazy_loading: Arc<lazy_loading::Service>,
pub metadata: metadata::Service, pub metadata: Arc<metadata::Service>,
pub outlier: outlier::Service, pub outlier: Arc<outlier::Service>,
pub pdu_metadata: pdu_metadata::Service, pub pdu_metadata: Arc<pdu_metadata::Service>,
pub read_receipt: read_receipt::Service, pub read_receipt: Arc<read_receipt::Service>,
pub search: search::Service, pub search: Arc<search::Service>,
pub short: short::Service, pub short: Arc<short::Service>,
pub state: state::Service, pub state: Arc<state::Service>,
pub state_accessor: state_accessor::Service, pub state_accessor: Arc<state_accessor::Service>,
pub state_cache: state_cache::Service, pub state_cache: Arc<state_cache::Service>,
pub state_compressor: state_compressor::Service, pub state_compressor: Arc<state_compressor::Service>,
pub timeline: timeline::Service, pub timeline: Arc<timeline::Service>,
pub threads: threads::Service, pub threads: Arc<threads::Service>,
pub typing: typing::Service, pub typing: Arc<typing::Service>,
pub spaces: spaces::Service, pub spaces: Arc<spaces::Service>,
pub user: user::Service, pub user: Arc<user::Service>,
} }

View file

@ -2,9 +2,8 @@ mod data;
use std::sync::Arc; use std::sync::Arc;
use conduit::{Result, Server}; use conduit::Result;
use data::Data; use data::Data;
use database::Database;
use ruma::{CanonicalJsonObject, EventId}; use ruma::{CanonicalJsonObject, EventId};
use crate::PduEvent; use crate::PduEvent;
@ -13,13 +12,17 @@ pub struct Service {
db: Data, db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
/// Returns the pdu from the outlier tree. /// Returns the pdu from the outlier tree.
pub fn get_outlier_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>> { pub fn get_outlier_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>> {
self.db.get_outlier_pdu_json(event_id) self.db.get_outlier_pdu_json(event_id)

View file

@ -2,9 +2,8 @@ mod data;
use std::sync::Arc; use std::sync::Arc;
use conduit::{Result, Server}; use conduit::Result;
use data::Data; use data::Data;
use database::Database;
use ruma::{ use ruma::{
api::{client::relations::get_relating_events, Direction}, api::{client::relations::get_relating_events, Direction},
events::{relation::RelationType, TimelineEventType}, events::{relation::RelationType, TimelineEventType},
@ -28,13 +27,17 @@ struct ExtractRelatesToEventId {
relates_to: ExtractRelType, relates_to: ExtractRelType,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
#[tracing::instrument(skip(self, from, to))] #[tracing::instrument(skip(self, from, to))]
pub fn add_relation(&self, from: PduCount, to: PduCount) -> Result<()> { pub fn add_relation(&self, from: PduCount, to: PduCount) -> Result<()> {
match (from, to) { match (from, to) {

View file

@ -2,9 +2,8 @@ mod data;
use std::sync::Arc; use std::sync::Arc;
use conduit::{Result, Server}; use conduit::Result;
use data::Data; use data::Data;
use database::Database;
use ruma::{events::receipt::ReceiptEvent, serde::Raw, OwnedUserId, RoomId, UserId}; use ruma::{events::receipt::ReceiptEvent, serde::Raw, OwnedUserId, RoomId, UserId};
use crate::services; use crate::services;
@ -13,13 +12,17 @@ pub struct Service {
db: Data, db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
/// Replaces the previous read receipt. /// Replaces the previous read receipt.
pub fn readreceipt_update(&self, user_id: &UserId, room_id: &RoomId, event: &ReceiptEvent) -> Result<()> { pub fn readreceipt_update(&self, user_id: &UserId, room_id: &RoomId, event: &ReceiptEvent) -> Result<()> {
self.db.readreceipt_update(user_id, room_id, event)?; self.db.readreceipt_update(user_id, room_id, event)?;

View file

@ -2,22 +2,25 @@ mod data;
use std::sync::Arc; use std::sync::Arc;
use conduit::{Result, Server}; use conduit::Result;
use data::Data; use data::Data;
use database::Database;
use ruma::RoomId; use ruma::RoomId;
pub struct Service { pub struct Service {
db: Data, db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
#[tracing::instrument(skip(self))] #[tracing::instrument(skip(self))]
pub fn index_pdu(&self, shortroomid: u64, pdu_id: &[u8], message_body: &str) -> Result<()> { pub fn index_pdu(&self, shortroomid: u64, pdu_id: &[u8], message_body: &str) -> Result<()> {
self.db.index_pdu(shortroomid, pdu_id, message_body) self.db.index_pdu(shortroomid, pdu_id, message_body)

View file

@ -2,22 +2,25 @@ mod data;
use std::sync::Arc; use std::sync::Arc;
use conduit::{Result, Server}; use conduit::Result;
use data::Data; use data::Data;
use database::Database;
use ruma::{events::StateEventType, EventId, RoomId}; use ruma::{events::StateEventType, EventId, RoomId};
pub struct Service { pub struct Service {
db: Data, db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
pub fn get_or_create_shorteventid(&self, event_id: &EventId) -> Result<u64> { pub fn get_or_create_shorteventid(&self, event_id: &EventId) -> Result<u64> {
self.db.get_or_create_shorteventid(event_id) self.db.get_or_create_shorteventid(event_id)
} }

View file

@ -7,8 +7,7 @@ use std::{
sync::Arc, sync::Arc,
}; };
use conduit::{debug_info, Server}; use conduit::debug_info;
use database::Database;
use lru_cache::LruCache; use lru_cache::LruCache;
use ruma::{ use ruma::{
api::{ api::{
@ -159,17 +158,21 @@ impl From<CachedSpaceHierarchySummary> for SpaceHierarchyRoomsChunk {
} }
} }
impl Service { impl crate::Service for Service {
pub fn build(server: &Arc<Server>, _db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
let config = &server.config; let config = &args.server.config;
Ok(Self { Ok(Arc::new(Self {
roomid_spacehierarchy_cache: Mutex::new(LruCache::new( roomid_spacehierarchy_cache: Mutex::new(LruCache::new(
(f64::from(config.roomid_spacehierarchy_cache_capacity) * config.conduit_cache_capacity_modifier) (f64::from(config.roomid_spacehierarchy_cache_capacity) * config.conduit_cache_capacity_modifier)
as usize, as usize,
)), )),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
/// Gets the response for the space hierarchy over federation request /// Gets the response for the space hierarchy over federation request
/// ///
/// Errors if the room does not exist, so a check if the room exists should /// Errors if the room does not exist, so a check if the room exists should

View file

@ -7,10 +7,9 @@ use std::{
use conduit::{ use conduit::{
utils::{calculate_hash, mutex_map}, utils::{calculate_hash, mutex_map},
warn, Error, Result, Server, warn, Error, Result,
}; };
use data::Data; use data::Data;
use database::Database;
use ruma::{ use ruma::{
api::client::error::ErrorKind, api::client::error::ErrorKind,
events::{ events::{
@ -29,13 +28,17 @@ pub struct Service {
db: Data, db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
/// Set the room to the given statehash and update caches. /// Set the room to the given statehash and update caches.
pub async fn force_state( pub async fn force_state(
&self, &self,

View file

@ -2,12 +2,12 @@ mod data;
use std::{ use std::{
collections::HashMap, collections::HashMap,
fmt::Write,
sync::{Arc, Mutex as StdMutex, Mutex}, sync::{Arc, Mutex as StdMutex, Mutex},
}; };
use conduit::{error, utils::mutex_map, warn, Error, Result, Server}; use conduit::{error, utils::mutex_map, warn, Error, Result};
use data::Data; use data::Data;
use database::Database;
use lru_cache::LruCache; use lru_cache::LruCache;
use ruma::{ use ruma::{
events::{ events::{
@ -41,20 +41,39 @@ pub struct Service {
pub user_visibility_cache: Mutex<LruCache<(OwnedUserId, u64), bool>>, pub user_visibility_cache: Mutex<LruCache<(OwnedUserId, u64), bool>>,
} }
impl Service { impl crate::Service for Service {
pub fn build(server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
let config = &server.config; let config = &args.server.config;
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
server_visibility_cache: StdMutex::new(LruCache::new( server_visibility_cache: StdMutex::new(LruCache::new(
(f64::from(config.server_visibility_cache_capacity) * config.conduit_cache_capacity_modifier) as usize, (f64::from(config.server_visibility_cache_capacity) * config.conduit_cache_capacity_modifier) as usize,
)), )),
user_visibility_cache: StdMutex::new(LruCache::new( user_visibility_cache: StdMutex::new(LruCache::new(
(f64::from(config.user_visibility_cache_capacity) * config.conduit_cache_capacity_modifier) as usize, (f64::from(config.user_visibility_cache_capacity) * config.conduit_cache_capacity_modifier) as usize,
)), )),
}) }))
} }
fn memory_usage(&self, out: &mut dyn Write) -> Result<()> {
let server_visibility_cache = self.server_visibility_cache.lock().expect("locked").len();
writeln!(out, "server_visibility_cache: {server_visibility_cache}")?;
let user_visibility_cache = self.user_visibility_cache.lock().expect("locked").len();
writeln!(out, "user_visibility_cache: {user_visibility_cache}")?;
Ok(())
}
fn clear_cache(&self) {
self.server_visibility_cache.lock().expect("locked").clear();
self.user_visibility_cache.lock().expect("locked").clear();
}
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
/// Builds a StateMap by iterating over all keys that start /// Builds a StateMap by iterating over all keys that start
/// with state_hash, this gives the full state for the given state_hash. /// with state_hash, this gives the full state for the given state_hash.
#[tracing::instrument(skip(self))] #[tracing::instrument(skip(self))]

View file

@ -2,9 +2,8 @@ mod data;
use std::sync::Arc; use std::sync::Arc;
use conduit::{error, warn, Error, Result, Server}; use conduit::{error, warn, Error, Result};
use data::Data; use data::Data;
use database::Database;
use itertools::Itertools; use itertools::Itertools;
use ruma::{ use ruma::{
events::{ events::{
@ -28,13 +27,17 @@ pub struct Service {
db: Data, db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
/// Update current membership data. /// Update current membership data.
#[tracing::instrument(skip(self, last_state))] #[tracing::instrument(skip(self, last_state))]
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]

View file

@ -2,13 +2,13 @@ mod data;
use std::{ use std::{
collections::HashSet, collections::HashSet,
fmt::Write,
mem::size_of, mem::size_of,
sync::{Arc, Mutex as StdMutex, Mutex}, sync::{Arc, Mutex as StdMutex, Mutex},
}; };
use conduit::{utils, Result, Server}; use conduit::{utils, Result};
use data::Data; use data::Data;
use database::Database;
use lru_cache::LruCache; use lru_cache::LruCache;
use ruma::{EventId, RoomId}; use ruma::{EventId, RoomId};
@ -52,17 +52,30 @@ pub struct Service {
pub stateinfo_cache: StateInfoLruCache, pub stateinfo_cache: StateInfoLruCache,
} }
impl Service { impl crate::Service for Service {
pub fn build(server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
let config = &server.config; let config = &args.server.config;
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
stateinfo_cache: StdMutex::new(LruCache::new( stateinfo_cache: StdMutex::new(LruCache::new(
(f64::from(config.stateinfo_cache_capacity) * config.conduit_cache_capacity_modifier) as usize, (f64::from(config.stateinfo_cache_capacity) * config.conduit_cache_capacity_modifier) as usize,
)), )),
}) }))
} }
fn memory_usage(&self, out: &mut dyn Write) -> Result<()> {
let stateinfo_cache = self.stateinfo_cache.lock().expect("locked").len();
writeln!(out, "stateinfo_cache: {stateinfo_cache}")?;
Ok(())
}
fn clear_cache(&self) { self.stateinfo_cache.lock().expect("locked").clear(); }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
/// Returns a stack with info on shortstatehash, full state, added diff and /// Returns a stack with info on shortstatehash, full state, added diff and
/// removed diff for the selected shortstatehash and each parent layer. /// removed diff for the selected shortstatehash and each parent layer.
#[tracing::instrument(skip(self))] #[tracing::instrument(skip(self))]

View file

@ -2,9 +2,8 @@ mod data;
use std::{collections::BTreeMap, sync::Arc}; use std::{collections::BTreeMap, sync::Arc};
use conduit::{Error, Result, Server}; use conduit::{Error, Result};
use data::Data; use data::Data;
use database::Database;
use ruma::{ use ruma::{
api::client::{error::ErrorKind, threads::get_threads::v1::IncludeThreads}, api::client::{error::ErrorKind, threads::get_threads::v1::IncludeThreads},
events::relation::BundledThread, events::relation::BundledThread,
@ -18,13 +17,17 @@ pub struct Service {
db: Data, db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
pub fn threads_until<'a>( pub fn threads_until<'a>(
&'a self, user_id: &'a UserId, room_id: &'a RoomId, until: u64, include: &'a IncludeThreads, &'a self, user_id: &'a UserId, room_id: &'a RoomId, until: u64, include: &'a IncludeThreads,
) -> Result<impl Iterator<Item = Result<(u64, PduEvent)>> + 'a> { ) -> Result<impl Iterator<Item = Result<(u64, PduEvent)>> + 'a> {

View file

@ -2,12 +2,12 @@ mod data;
use std::{ use std::{
collections::{BTreeMap, HashSet}, collections::{BTreeMap, HashSet},
fmt::Write,
sync::Arc, sync::Arc,
}; };
use conduit::{debug, error, info, utils, utils::mutex_map, warn, Error, Result, Server}; use conduit::{debug, error, info, utils, utils::mutex_map, warn, Error, Result};
use data::Data; use data::Data;
use database::Database;
use itertools::Itertools; use itertools::Itertools;
use rand::prelude::SliceRandom; use rand::prelude::SliceRandom;
use ruma::{ use ruma::{
@ -68,13 +68,37 @@ pub struct Service {
db: Data, db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn memory_usage(&self, out: &mut dyn Write) -> Result<()> {
let lasttimelinecount_cache = self
.db
.lasttimelinecount_cache
.lock()
.expect("locked")
.len();
writeln!(out, "lasttimelinecount_cache: {lasttimelinecount_cache}")?;
Ok(())
}
fn clear_cache(&self) {
self.db
.lasttimelinecount_cache
.lock()
.expect("locked")
.clear();
}
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
#[tracing::instrument(skip(self))] #[tracing::instrument(skip(self))]
pub fn first_pdu_in_room(&self, room_id: &RoomId) -> Result<Option<Arc<PduEvent>>> { pub fn first_pdu_in_room(&self, room_id: &RoomId) -> Result<Option<Arc<PduEvent>>> {
self.all_pdus(user_id!("@doesntmatter:conduit.rs"), room_id)? self.all_pdus(user_id!("@doesntmatter:conduit.rs"), room_id)?
@ -1238,19 +1262,6 @@ impl Service {
debug!("Prepended backfill pdu"); debug!("Prepended backfill pdu");
Ok(()) Ok(())
} }
pub fn get_lasttimelinecount_cache_usage(&self) -> (usize, usize) {
let cache = self.db.lasttimelinecount_cache.lock().expect("locked");
(cache.len(), cache.capacity())
}
pub fn clear_lasttimelinecount_cache(&self) {
self.db
.lasttimelinecount_cache
.lock()
.expect("locked")
.clear();
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -1,7 +1,6 @@
use std::{collections::BTreeMap, sync::Arc}; use std::{collections::BTreeMap, sync::Arc};
use conduit::{debug_info, trace, utils, Result, Server}; use conduit::{debug_info, trace, utils, Result};
use database::Database;
use ruma::{ use ruma::{
api::federation::transactions::edu::{Edu, TypingContent}, api::federation::transactions::edu::{Edu, TypingContent},
events::SyncEphemeralRoomEvent, events::SyncEphemeralRoomEvent,
@ -19,15 +18,19 @@ pub struct Service {
pub typing_update_sender: broadcast::Sender<OwnedRoomId>, pub typing_update_sender: broadcast::Sender<OwnedRoomId>,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, _db: &Arc<Database>) -> Result<Self> { fn build(_args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
typing: RwLock::new(BTreeMap::new()), typing: RwLock::new(BTreeMap::new()),
last_typing_update: RwLock::new(BTreeMap::new()), last_typing_update: RwLock::new(BTreeMap::new()),
typing_update_sender: broadcast::channel(100).0, typing_update_sender: broadcast::channel(100).0,
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
/// Sets a user as typing until the timeout timestamp is reached or /// Sets a user as typing until the timeout timestamp is reached or
/// roomtyping_remove is called. /// roomtyping_remove is called.
pub async fn typing_add(&self, user_id: &UserId, room_id: &RoomId, timeout: u64) -> Result<()> { pub async fn typing_add(&self, user_id: &UserId, room_id: &RoomId, timeout: u64) -> Result<()> {

View file

@ -2,22 +2,25 @@ mod data;
use std::sync::Arc; use std::sync::Arc;
use conduit::{Result, Server}; use conduit::Result;
use data::Data; use data::Data;
use database::Database;
use ruma::{OwnedRoomId, OwnedUserId, RoomId, UserId}; use ruma::{OwnedRoomId, OwnedUserId, RoomId, UserId};
pub struct Service { pub struct Service {
db: Data, db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
pub fn reset_notification_counts(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> { pub fn reset_notification_counts(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
self.db.reset_notification_counts(user_id, room_id) self.db.reset_notification_counts(user_id, room_id)
} }

View file

@ -6,9 +6,9 @@ mod sender;
use std::{fmt::Debug, sync::Arc}; use std::{fmt::Debug, sync::Arc};
use conduit::{Error, Result, Server}; use async_trait::async_trait;
use conduit::{Error, Result};
use data::Data; use data::Data;
use database::Database;
pub use resolve::FedDest; pub use resolve::FedDest;
use ruma::{ use ruma::{
api::{appservice::Registration, OutgoingRequest}, api::{appservice::Registration, OutgoingRequest},
@ -53,12 +53,13 @@ pub enum SendingEvent {
Flush, // none Flush, // none
} }
impl Service { #[async_trait]
pub fn build(server: &Arc<Server>, db: &Arc<Database>) -> Result<Arc<Self>> { impl crate::Service for Service {
let config = &server.config; fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
let config = &args.server.config;
let (sender, receiver) = loole::unbounded(); let (sender, receiver) = loole::unbounded();
Ok(Arc::new(Self { Ok(Arc::new(Self {
db: Data::new(db.clone()), db: Data::new(args.db.clone()),
sender, sender,
receiver: Mutex::new(receiver), receiver: Mutex::new(receiver),
handler_join: Mutex::new(None), handler_join: Mutex::new(None),
@ -67,7 +68,13 @@ impl Service {
})) }))
} }
pub async fn close(&self) { async fn start(self: Arc<Self>) -> Result<()> {
self.start_handler().await;
Ok(())
}
async fn stop(&self) {
self.interrupt(); self.interrupt();
if let Some(handler_join) = self.handler_join.lock().await.take() { if let Some(handler_join) = self.handler_join.lock().await.take() {
if let Err(e) = handler_join.await { if let Err(e) = handler_join.await {
@ -76,12 +83,16 @@ impl Service {
} }
} }
pub fn interrupt(&self) { fn interrupt(&self) {
if !self.sender.is_closed() { if !self.sender.is_closed() {
self.sender.close(); self.sender.close();
} }
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
#[tracing::instrument(skip(self, pdu_id, user, pushkey))] #[tracing::instrument(skip(self, pdu_id, user, pushkey))]
pub fn send_pdu_push(&self, pdu_id: &[u8], user: &UserId, pushkey: String) -> Result<()> { pub fn send_pdu_push(&self, pdu_id: &[u8], user: &UserId, pushkey: String) -> Result<()> {
let dest = Destination::Push(user.to_owned(), pushkey); let dest = Destination::Push(user.to_owned(), pushkey);

53
src/service/service.rs Normal file
View file

@ -0,0 +1,53 @@
use std::{collections::BTreeMap, fmt::Write, sync::Arc};
use async_trait::async_trait;
use conduit::{utils::string::split_once_infallible, Result, Server};
use database::Database;
#[async_trait]
pub(crate) trait Service: Send + Sync {
/// Implement the construction of the service instance. Services are
/// generally singletons so expect this to only be called once for a
/// service type. Note that it may be called again after a server reload,
/// but the prior instance will have been dropped first. Failure will
/// shutdown the server with an error.
fn build(args: Args<'_>) -> Result<Arc<impl Service>>
where
Self: Sized;
/// Start the service. Implement the spawning of any service workers. This
/// is called after all other services have been constructed. Failure will
/// shutdown the server with an error.
async fn start(self: Arc<Self>) -> Result<()> { Ok(()) }
/// Stop the service. Implement the joining of any service workers and
/// cleanup of any other state. This function is asynchronous to allow that
/// gracefully, but errors cannot propagate.
async fn stop(&self) {}
/// Interrupt the service. This may be sent prior to `stop()` as a
/// notification to improve the shutdown sequence. Implementations must be
/// robust to this being called multiple times.
fn interrupt(&self) {}
/// Clear any caches or similar runtime state.
fn clear_cache(&self) {}
/// Memory usage report in a markdown string.
fn memory_usage(&self, _out: &mut dyn Write) -> Result<()> { Ok(()) }
/// Return the name of the service.
/// i.e. `crate::service::make_name(std::module_path!())`
fn name(&self) -> &str;
}
pub(crate) struct Args<'a> {
pub(crate) server: &'a Arc<Server>,
pub(crate) db: &'a Arc<Database>,
pub(crate) _service: &'a Map,
}
pub(crate) type Map = BTreeMap<String, Arc<dyn Service>>;
#[inline]
pub(crate) fn make_name(module_path: &str) -> &str { split_once_infallible(module_path, "::").1 }

View file

@ -1,101 +1,97 @@
use std::sync::Arc; use std::{collections::BTreeMap, fmt::Write, sync::Arc};
use conduit::{debug_info, Result, Server}; use conduit::{debug, debug_info, info, trace, Result, Server};
use database::Database; use database::Database;
use tracing::{debug, info, trace};
use crate::{ use crate::{
account_data, admin, appservice, globals, key_backups, media, presence, pusher, rooms, sending, transaction_ids, account_data, admin, appservice, globals, key_backups, media, presence, pusher, rooms, sending,
uiaa, users, service::{Args, Map, Service},
transaction_ids, uiaa, users,
}; };
pub struct Services { pub struct Services {
pub rooms: rooms::Service, pub rooms: rooms::Service,
pub appservice: appservice::Service, pub appservice: Arc<appservice::Service>,
pub pusher: pusher::Service, pub pusher: Arc<pusher::Service>,
pub transaction_ids: transaction_ids::Service, pub transaction_ids: Arc<transaction_ids::Service>,
pub uiaa: uiaa::Service, pub uiaa: Arc<uiaa::Service>,
pub users: users::Service, pub users: Arc<users::Service>,
pub account_data: account_data::Service, pub account_data: Arc<account_data::Service>,
pub presence: Arc<presence::Service>, pub presence: Arc<presence::Service>,
pub admin: Arc<admin::Service>, pub admin: Arc<admin::Service>,
pub globals: globals::Service, pub globals: Arc<globals::Service>,
pub key_backups: key_backups::Service, pub key_backups: Arc<key_backups::Service>,
pub media: media::Service, pub media: Arc<media::Service>,
pub sending: Arc<sending::Service>, pub sending: Arc<sending::Service>,
pub(crate) service: Map,
pub server: Arc<Server>, pub server: Arc<Server>,
pub db: Arc<Database>, pub db: Arc<Database>,
} }
impl Services { impl Services {
pub async fn build(server: Arc<Server>, db: Arc<Database>) -> Result<Self> { pub fn build(server: Arc<Server>, db: Arc<Database>) -> Result<Self> {
let mut service: Map = BTreeMap::new();
macro_rules! build {
($tyname:ty) => {{
let built = <$tyname>::build(Args {
server: &server,
db: &db,
_service: &service,
})?;
service.insert(built.name().to_owned(), built.clone());
built
}};
}
Ok(Self { Ok(Self {
rooms: rooms::Service { rooms: rooms::Service {
alias: rooms::alias::Service::build(&server, &db)?, alias: build!(rooms::alias::Service),
auth_chain: rooms::auth_chain::Service::build(&server, &db)?, auth_chain: build!(rooms::auth_chain::Service),
directory: rooms::directory::Service::build(&server, &db)?, directory: build!(rooms::directory::Service),
event_handler: rooms::event_handler::Service::build(&server, &db)?, event_handler: build!(rooms::event_handler::Service),
lazy_loading: rooms::lazy_loading::Service::build(&server, &db)?, lazy_loading: build!(rooms::lazy_loading::Service),
metadata: rooms::metadata::Service::build(&server, &db)?, metadata: build!(rooms::metadata::Service),
outlier: rooms::outlier::Service::build(&server, &db)?, outlier: build!(rooms::outlier::Service),
pdu_metadata: rooms::pdu_metadata::Service::build(&server, &db)?, pdu_metadata: build!(rooms::pdu_metadata::Service),
read_receipt: rooms::read_receipt::Service::build(&server, &db)?, read_receipt: build!(rooms::read_receipt::Service),
search: rooms::search::Service::build(&server, &db)?, search: build!(rooms::search::Service),
short: rooms::short::Service::build(&server, &db)?, short: build!(rooms::short::Service),
state: rooms::state::Service::build(&server, &db)?, state: build!(rooms::state::Service),
state_accessor: rooms::state_accessor::Service::build(&server, &db)?, state_accessor: build!(rooms::state_accessor::Service),
state_cache: rooms::state_cache::Service::build(&server, &db)?, state_cache: build!(rooms::state_cache::Service),
state_compressor: rooms::state_compressor::Service::build(&server, &db)?, state_compressor: build!(rooms::state_compressor::Service),
timeline: rooms::timeline::Service::build(&server, &db)?, timeline: build!(rooms::timeline::Service),
threads: rooms::threads::Service::build(&server, &db)?, threads: build!(rooms::threads::Service),
typing: rooms::typing::Service::build(&server, &db)?, typing: build!(rooms::typing::Service),
spaces: rooms::spaces::Service::build(&server, &db)?, spaces: build!(rooms::spaces::Service),
user: rooms::user::Service::build(&server, &db)?, user: build!(rooms::user::Service),
}, },
appservice: appservice::Service::build(&server, &db)?, appservice: build!(appservice::Service),
pusher: pusher::Service::build(&server, &db)?, pusher: build!(pusher::Service),
transaction_ids: transaction_ids::Service::build(&server, &db)?, transaction_ids: build!(transaction_ids::Service),
uiaa: uiaa::Service::build(&server, &db)?, uiaa: build!(uiaa::Service),
users: users::Service::build(&server, &db)?, users: build!(users::Service),
account_data: account_data::Service::build(&server, &db)?, account_data: build!(account_data::Service),
presence: presence::Service::build(&server, &db)?, presence: build!(presence::Service),
admin: admin::Service::build(&server, &db)?, admin: build!(admin::Service),
key_backups: key_backups::Service::build(&server, &db)?, key_backups: build!(key_backups::Service),
media: media::Service::build(&server, &db)?, media: build!(media::Service),
sending: sending::Service::build(&server, &db)?, sending: build!(sending::Service),
globals: globals::Service::build(&server, &db)?, globals: build!(globals::Service),
service,
server, server,
db, db,
}) })
} }
pub async fn memory_usage(&self) -> String { pub async fn memory_usage(&self) -> Result<String> {
let lazy_load_waiting = self.rooms.lazy_loading.lazy_load_waiting.lock().await.len(); let mut out = String::new();
let server_visibility_cache = self for service in self.service.values() {
.rooms service.memory_usage(&mut out)?;
.state_accessor }
.server_visibility_cache
.lock() //TODO
.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 lasttimelinecount_cache = self
.rooms
.timeline
.get_lasttimelinecount_cache_usage().0;
let roomid_spacehierarchy_cache = self let roomid_spacehierarchy_cache = self
.rooms .rooms
.spaces .spaces
@ -103,113 +99,23 @@ impl Services {
.lock() .lock()
.await .await
.len(); .len();
let resolver_overrides_cache = self writeln!(out, "roomid_spacehierarchy_cache: {roomid_spacehierarchy_cache}")?;
.globals
.resolver
.overrides
.read()
.expect("locked for reading")
.len();
let resolver_destinations_cache = self
.globals
.resolver
.destinations
.read()
.expect("locked for reading")
.len();
let bad_event_ratelimiter = self.globals.bad_event_ratelimiter.read().await.len();
let bad_query_ratelimiter = self.globals.bad_query_ratelimiter.read().await.len();
let bad_signature_ratelimiter = self.globals.bad_signature_ratelimiter.read().await.len();
format!( Ok(out)
"\
lazy_load_waiting: {lazy_load_waiting}
server_visibility_cache: {server_visibility_cache}
user_visibility_cache: {user_visibility_cache}
stateinfo_cache: {stateinfo_cache}
lasttimelinecount_cache: {lasttimelinecount_cache}
roomid_spacehierarchy_cache: {roomid_spacehierarchy_cache}
resolver_overrides_cache: {resolver_overrides_cache}
resolver_destinations_cache: {resolver_destinations_cache}
bad_event_ratelimiter: {bad_event_ratelimiter}
bad_query_ratelimiter: {bad_query_ratelimiter}
bad_signature_ratelimiter: {bad_signature_ratelimiter}
"
)
} }
pub async fn clear_caches(&self, amount: u32) { pub async fn clear_cache(&self) {
if amount > 0 { for service in self.service.values() {
self.rooms service.clear_cache();
.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 > 4 {
self.rooms
.timeline
.clear_lasttimelinecount_cache();
}
if amount > 5 {
self.rooms
.spaces
.roomid_spacehierarchy_cache
.lock()
.await
.clear();
}
if amount > 6 {
self.globals
.resolver
.overrides
.write()
.expect("locked for writing")
.clear();
self.globals
.resolver
.destinations
.write()
.expect("locked for writing")
.clear();
}
if amount > 7 {
self.globals.resolver.resolver.clear_cache();
}
if amount > 8 {
self.globals.bad_event_ratelimiter.write().await.clear();
}
if amount > 9 {
self.globals.bad_query_ratelimiter.write().await.clear();
}
if amount > 10 {
self.globals.bad_signature_ratelimiter.write().await.clear();
} }
//TODO
self.rooms
.spaces
.roomid_spacehierarchy_cache
.lock()
.await
.clear();
} }
pub async fn start(&self) -> Result<()> { pub async fn start(&self) -> Result<()> {
@ -219,10 +125,9 @@ bad_signature_ratelimiter: {bad_signature_ratelimiter}
globals::migrations::migrations(&self.db, &self.globals.config).await?; globals::migrations::migrations(&self.db, &self.globals.config).await?;
globals::emerg_access::init_emergency_access(); globals::emerg_access::init_emergency_access();
self.admin.start_handler().await; for (name, service) in &self.service {
self.sending.start_handler().await; debug!("Starting {name}");
if self.globals.config.allow_local_presence { service.clone().start().await?;
self.presence.start_handler().await;
} }
if self.globals.allow_check_for_updates() { if self.globals.allow_check_for_updates() {
@ -238,18 +143,18 @@ bad_signature_ratelimiter: {bad_signature_ratelimiter}
Ok(()) Ok(())
} }
pub async fn interrupt(&self) { pub fn interrupt(&self) {
trace!("Interrupting services..."); debug!("Interrupting services...");
self.sending.interrupt();
self.presence.interrupt();
self.admin.interrupt();
trace!("Services interrupt complete."); for (name, service) in &self.service {
trace!("Interrupting {name}");
service.interrupt();
}
} }
pub async fn stop(&self) { pub async fn stop(&self) {
info!("Shutting down services"); info!("Shutting down services");
self.interrupt().await; self.interrupt();
debug!("Waiting for update worker..."); debug!("Waiting for update worker...");
if let Some(updates_handle) = self.globals.updates_handle.lock().await.take() { if let Some(updates_handle) = self.globals.updates_handle.lock().await.take() {
@ -261,14 +166,10 @@ bad_signature_ratelimiter: {bad_signature_ratelimiter}
} }
} }
debug!("Waiting for admin worker..."); for (name, service) in &self.service {
self.admin.close().await; debug!("Waiting for {name} ...");
service.stop().await;
debug!("Waiting for presence worker..."); }
self.presence.close().await;
debug!("Waiting for sender...");
self.sending.close().await;
debug_info!("Services shutdown complete."); debug_info!("Services shutdown complete.");
} }

View file

@ -2,22 +2,25 @@ mod data;
use std::sync::Arc; use std::sync::Arc;
use conduit::{Result, Server}; use conduit::Result;
use data::Data; use data::Data;
use database::Database;
use ruma::{DeviceId, TransactionId, UserId}; use ruma::{DeviceId, TransactionId, UserId};
pub struct Service { pub struct Service {
pub db: Data, pub db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
pub fn add_txnid( pub fn add_txnid(
&self, user_id: &UserId, device_id: Option<&DeviceId>, txn_id: &TransactionId, data: &[u8], &self, user_id: &UserId, device_id: Option<&DeviceId>, txn_id: &TransactionId, data: &[u8],
) -> Result<()> { ) -> Result<()> {

View file

@ -2,9 +2,8 @@ mod data;
use std::sync::Arc; use std::sync::Arc;
use conduit::{utils, utils::hash, Error, Result, Server}; use conduit::{utils, utils::hash, Error, Result};
use data::Data; use data::Data;
use database::Database;
use ruma::{ use ruma::{
api::client::{ api::client::{
error::ErrorKind, error::ErrorKind,
@ -22,13 +21,17 @@ pub struct Service {
pub db: Data, pub db: Data,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db), db: Data::new(args.db),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
/// Creates a new Uiaa session. Make sure the session token is unique. /// Creates a new Uiaa session. Make sure the session token is unique.
pub fn create( pub fn create(
&self, user_id: &UserId, device_id: &DeviceId, uiaainfo: &UiaaInfo, json_body: &CanonicalJsonValue, &self, user_id: &UserId, device_id: &DeviceId, uiaainfo: &UiaaInfo, json_body: &CanonicalJsonValue,

View file

@ -6,9 +6,8 @@ use std::{
sync::{Arc, Mutex, Mutex as StdMutex}, sync::{Arc, Mutex, Mutex as StdMutex},
}; };
use conduit::{Error, Result, Server}; use conduit::{Error, Result};
use data::Data; use data::Data;
use database::Database;
use ruma::{ use ruma::{
api::client::{ api::client::{
device::Device, device::Device,
@ -41,14 +40,18 @@ pub struct Service {
pub connections: DbConnections, pub connections: DbConnections,
} }
impl Service { impl crate::Service for Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> { fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Self { Ok(Arc::new(Self {
db: Data::new(db.clone()), db: Data::new(args.db.clone()),
connections: StdMutex::new(BTreeMap::new()), connections: StdMutex::new(BTreeMap::new()),
}) }))
} }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
/// Check if a user has an account on this homeserver. /// Check if a user has an account on this homeserver.
pub fn exists(&self, user_id: &UserId) -> Result<bool> { self.db.exists(user_id) } pub fn exists(&self, user_id: &UserId) -> Result<bool> { self.db.exists(user_id) }