Files
continuwuity/src/database/mod.rs
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

574 lines
22 KiB
Rust
Raw Normal View History

2024-04-22 23:48:57 -04:00
mod cork;
mod key_value;
mod kvengine;
mod kvtree;
2024-04-06 01:24:08 -07:00
mod migrations;
#[cfg(feature = "rocksdb")]
2024-04-22 23:48:57 -04:00
mod rocksdb;
2024-04-06 01:24:08 -07:00
#[cfg(feature = "sqlite")]
2024-04-22 23:48:57 -04:00
mod sqlite;
2024-04-06 01:24:08 -07:00
#[cfg(any(feature = "sqlite", feature = "rocksdb"))]
pub(crate) mod watchers;
2021-06-08 18:10:00 +02:00
2023-02-20 22:59:45 +01:00
use std::{
collections::{BTreeMap, HashMap, HashSet},
fs::{self},
path::Path,
sync::{Arc, Mutex, RwLock},
time::Duration,
2023-02-20 22:59:45 +01:00
};
2024-03-05 19:48:54 -05:00
2024-04-06 01:24:08 -07:00
pub(crate) use cork::Cork;
pub(crate) use kvengine::KeyValueDatabaseEngine;
pub(crate) use kvtree::KvTree;
2021-06-30 09:52:01 +02:00
use lru_cache::LruCache;
2022-04-07 12:11:55 +00:00
use ruma::{
events::{
2024-04-06 01:24:08 -07:00
push_rules::PushRulesEventContent, room::message::RoomMessageEventContent, GlobalAccountDataEvent,
GlobalAccountDataEventType,
2022-04-07 12:11:55 +00:00
},
push::Ruleset,
CanonicalJsonValue, OwnedDeviceId, OwnedRoomId, OwnedUserId, UserId,
2022-04-07 12:11:55 +00:00
};
2023-07-29 20:01:38 +02:00
use serde::Deserialize;
2024-03-09 18:05:11 -05:00
#[cfg(unix)]
use tokio::signal::unix::{signal, SignalKind};
2024-04-01 20:48:40 -07:00
use tokio::time::{interval, Instant};
2024-04-06 01:24:08 -07:00
use tracing::{debug, error, warn};
2024-04-06 01:24:08 -07:00
use crate::{
2024-04-25 09:07:59 -07:00
database::migrations::migrations, service::rooms::timeline::PduCount, services, Config, Error,
LogLevelReloadHandles, Result, Services, SERVICES,
2024-04-06 01:24:08 -07:00
};
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
pub(crate) struct KeyValueDatabase {
2024-03-02 20:55:02 -05:00
db: Arc<dyn KeyValueDatabaseEngine>,
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
//pub(crate) globals: globals::Globals,
pub(crate) global: Arc<dyn KvTree>,
pub(crate) server_signingkeys: Arc<dyn KvTree>,
pub(crate) roomid_inviteviaservers: Arc<dyn KvTree>,
//pub(crate) users: users::Users,
pub(crate) userid_password: Arc<dyn KvTree>,
pub(crate) userid_displayname: Arc<dyn KvTree>,
pub(crate) userid_avatarurl: Arc<dyn KvTree>,
pub(crate) userid_blurhash: Arc<dyn KvTree>,
pub(crate) userdeviceid_token: Arc<dyn KvTree>,
pub(crate) userdeviceid_metadata: Arc<dyn KvTree>, // This is also used to check if a device exists
pub(crate) userid_devicelistversion: Arc<dyn KvTree>, // DevicelistVersion = u64
pub(crate) token_userdeviceid: Arc<dyn KvTree>,
pub(crate) onetimekeyid_onetimekeys: Arc<dyn KvTree>, // OneTimeKeyId = UserId + DeviceKeyId
pub(crate) userid_lastonetimekeyupdate: Arc<dyn KvTree>, // LastOneTimeKeyUpdate = Count
pub(crate) keychangeid_userid: Arc<dyn KvTree>, // KeyChangeId = UserId/RoomId + Count
pub(crate) keyid_key: Arc<dyn KvTree>, // KeyId = UserId + KeyId (depends on key type)
pub(crate) userid_masterkeyid: Arc<dyn KvTree>,
pub(crate) userid_selfsigningkeyid: Arc<dyn KvTree>,
pub(crate) userid_usersigningkeyid: Arc<dyn KvTree>,
pub(crate) userfilterid_filter: Arc<dyn KvTree>, // UserFilterId = UserId + FilterId
pub(crate) todeviceid_events: Arc<dyn KvTree>, // ToDeviceId = UserId + DeviceId + Count
pub(crate) userid_presenceid: Arc<dyn KvTree>, // UserId => Count
pub(crate) presenceid_presence: Arc<dyn KvTree>, // Count + UserId => Presence
//pub(crate) uiaa: uiaa::Uiaa,
pub(crate) userdevicesessionid_uiaainfo: Arc<dyn KvTree>, // User-interactive authentication
pub(crate) userdevicesessionid_uiaarequest:
2022-10-09 17:25:06 +02:00
RwLock<BTreeMap<(OwnedUserId, OwnedDeviceId, String), CanonicalJsonValue>>,
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
//pub(crate) edus: RoomEdus,
pub(crate) readreceiptid_readreceipt: Arc<dyn KvTree>, // ReadReceiptId = RoomId + Count + UserId
pub(crate) roomuserid_privateread: Arc<dyn KvTree>, // RoomUserId = Room + User, PrivateRead = Count
pub(crate) roomuserid_lastprivatereadupdate: Arc<dyn KvTree>, // LastPrivateReadUpdate = Count
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
//pub(crate) rooms: rooms::Rooms,
pub(crate) pduid_pdu: Arc<dyn KvTree>, // PduId = ShortRoomId + Count
pub(crate) eventid_pduid: Arc<dyn KvTree>,
pub(crate) roomid_pduleaves: Arc<dyn KvTree>,
pub(crate) alias_roomid: Arc<dyn KvTree>,
pub(crate) aliasid_alias: Arc<dyn KvTree>, // AliasId = RoomId + Count
pub(crate) publicroomids: Arc<dyn KvTree>,
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
pub(crate) threadid_userids: Arc<dyn KvTree>, // ThreadId = RoomId + Count
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
pub(crate) tokenids: Arc<dyn KvTree>, // TokenId = ShortRoomId + Token + PduIdCount
2024-03-05 19:48:54 -05:00
2022-09-06 23:15:09 +02:00
/// Participating servers in a room.
2024-04-22 23:48:57 -04:00
pub(crate) roomserverids: Arc<dyn KvTree>, // RoomServerId = RoomId + ServerName
pub(crate) serverroomids: Arc<dyn KvTree>, // ServerRoomId = ServerName + RoomId
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
pub(crate) userroomid_joined: Arc<dyn KvTree>,
pub(crate) roomuserid_joined: Arc<dyn KvTree>,
pub(crate) roomid_joinedcount: Arc<dyn KvTree>,
pub(crate) roomid_invitedcount: Arc<dyn KvTree>,
pub(crate) roomuseroncejoinedids: Arc<dyn KvTree>,
pub(crate) userroomid_invitestate: Arc<dyn KvTree>, // InviteState = Vec<Raw<Pdu>>
pub(crate) roomuserid_invitecount: Arc<dyn KvTree>, // InviteCount = Count
pub(crate) userroomid_leftstate: Arc<dyn KvTree>,
pub(crate) roomuserid_leftcount: Arc<dyn KvTree>,
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
pub(crate) disabledroomids: Arc<dyn KvTree>, // Rooms where incoming federation handling is disabled
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
pub(crate) bannedroomids: Arc<dyn KvTree>, // Rooms where local users are not allowed to join
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
pub(crate) lazyloadedids: Arc<dyn KvTree>, // LazyLoadedIds = UserId + DeviceId + RoomId + LazyLoadedUserId
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
pub(crate) userroomid_notificationcount: Arc<dyn KvTree>, // NotifyCount = u64
pub(crate) userroomid_highlightcount: Arc<dyn KvTree>, // HightlightCount = u64
pub(crate) roomuserid_lastnotificationread: Arc<dyn KvTree>, // LastNotificationRead = u64
2024-03-05 19:48:54 -05:00
2022-09-06 23:15:09 +02:00
/// Remember the current state hash of a room.
2024-04-22 23:48:57 -04:00
pub(crate) roomid_shortstatehash: Arc<dyn KvTree>,
pub(crate) roomsynctoken_shortstatehash: Arc<dyn KvTree>,
2022-09-06 23:15:09 +02:00
/// Remember the state hash at events in the past.
2024-04-22 23:48:57 -04:00
pub(crate) shorteventid_shortstatehash: Arc<dyn KvTree>,
pub(crate) statekey_shortstatekey: Arc<dyn KvTree>, /* StateKey = EventType + StateKey, ShortStateKey =
* Count */
2024-04-22 23:48:57 -04:00
pub(crate) shortstatekey_statekey: Arc<dyn KvTree>,
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
pub(crate) roomid_shortroomid: Arc<dyn KvTree>,
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
pub(crate) shorteventid_eventid: Arc<dyn KvTree>,
pub(crate) eventid_shorteventid: Arc<dyn KvTree>,
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
pub(crate) statehash_shortstatehash: Arc<dyn KvTree>,
pub(crate) shortstatehash_statediff: Arc<dyn KvTree>, /* StateDiff = parent (or 0) +
2022-09-06 23:15:09 +02:00
* (shortstatekey+shorteventid++) + 0_u64 +
* (shortstatekey+shorteventid--) */
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
pub(crate) shorteventid_authchain: Arc<dyn KvTree>,
2024-03-05 19:48:54 -05:00
2022-09-06 23:15:09 +02:00
/// RoomId + EventId -> outlier PDU.
/// Any pdu that has passed the steps 1-8 in the incoming event
/// /federation/send/txn.
2024-04-22 23:48:57 -04:00
pub(crate) eventid_outlierpdu: Arc<dyn KvTree>,
pub(crate) softfailedeventids: Arc<dyn KvTree>,
2024-03-05 19:48:54 -05:00
2023-06-25 19:31:40 +02:00
/// ShortEventId + ShortEventId -> ().
2024-04-22 23:48:57 -04:00
pub(crate) tofrom_relation: Arc<dyn KvTree>,
2022-09-06 23:15:09 +02:00
/// RoomId + EventId -> Parent PDU EventId.
2024-04-22 23:48:57 -04:00
pub(crate) referencedevents: Arc<dyn KvTree>,
//pub(crate) account_data: account_data::AccountData,
pub(crate) roomuserdataid_accountdata: Arc<dyn KvTree>, // RoomUserDataId = Room + User + Count + Type
pub(crate) roomusertype_roomuserdataid: Arc<dyn KvTree>, // RoomUserType = Room + User + Type
//pub(crate) media: media::Media,
pub(crate) mediaid_file: Arc<dyn KvTree>, // MediaId = MXC + WidthHeight + ContentDisposition + ContentType
pub(crate) url_previews: Arc<dyn KvTree>,
pub(crate) mediaid_user: Arc<dyn KvTree>,
//pub(crate) key_backups: key_backups::KeyBackups,
pub(crate) backupid_algorithm: Arc<dyn KvTree>, // BackupId = UserId + Version(Count)
pub(crate) backupid_etag: Arc<dyn KvTree>, // BackupId = UserId + Version(Count)
pub(crate) backupkeyid_backup: Arc<dyn KvTree>, // BackupKeyId = UserId + Version + RoomId + SessionId
//pub(crate) transaction_ids: transaction_ids::TransactionIds,
pub(crate) userdevicetxnid_response: Arc<dyn KvTree>, /* Response can be empty (/sendToDevice) or the event id
2022-09-06 23:15:09 +02:00
* (/send) */
2024-04-22 23:48:57 -04:00
//pub(crate) sending: sending::Sending,
pub(crate) servername_educount: Arc<dyn KvTree>, // EduCount: Count of last EDU sync
pub(crate) servernameevent_data: Arc<dyn KvTree>, /* ServernameEvent = (+ / $)SenderKey / ServerName / UserId +
2022-09-06 23:15:09 +02:00
* PduId / Id (for edus), Data = EDU content */
2024-04-22 23:48:57 -04:00
pub(crate) servercurrentevent_data: Arc<dyn KvTree>, /* ServerCurrentEvents = (+ / $)ServerName / UserId + PduId
2022-09-06 23:15:09 +02:00
* / Id (for edus), Data = EDU content */
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
//pub(crate) appservice: appservice::Appservice,
pub(crate) id_appserviceregistrations: Arc<dyn KvTree>,
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
//pub(crate) pusher: pusher::PushData,
pub(crate) senderkey_pusher: Arc<dyn KvTree>,
2024-03-05 19:48:54 -05:00
2024-04-22 23:48:57 -04:00
pub(crate) auth_chain_cache: Mutex<LruCache<Vec<u64>, Arc<[u64]>>>,
pub(crate) our_real_users_cache: RwLock<HashMap<OwnedRoomId, Arc<HashSet<OwnedUserId>>>>,
pub(crate) appservice_in_room_cache: RwLock<HashMap<OwnedRoomId, HashMap<String, bool>>>,
pub(crate) lasttimelinecount_cache: Mutex<HashMap<OwnedRoomId, PduCount>>,
2020-03-30 13:46:18 +02:00
}
#[derive(Deserialize)]
struct CheckForUpdatesResponseEntry {
id: u64,
date: String,
message: String,
}
#[derive(Deserialize)]
struct CheckForUpdatesResponse {
updates: Vec<CheckForUpdatesResponseEntry>,
}
impl KeyValueDatabase {
2020-03-30 13:46:18 +02:00
/// Load an existing database or create a new one.
2024-03-23 14:38:15 -04:00
#[allow(clippy::too_many_lines)]
2024-04-25 09:07:59 -07:00
pub(crate) async fn load_or_create(config: Config, tracing_reload_handler: LogLevelReloadHandles) -> Result<()> {
2022-10-05 18:36:12 +02:00
Self::check_db_setup(&config)?;
2024-03-05 19:48:54 -05:00
if !Path::new(&config.database_path).exists() {
debug!("Database path does not exist, assuming this is a new setup and creating it");
2024-03-08 09:25:47 -05:00
fs::create_dir_all(&config.database_path).map_err(|e| {
error!("Failed to create database path: {e}");
2024-04-03 20:33:47 -07:00
Error::bad_config(
"Database folder doesn't exists and couldn't be created (e.g. due to missing permissions). Please \
create the database folder yourself or allow conduwuit the permissions to create directories and \
files.",
2024-03-05 19:48:54 -05:00
)
})?;
}
2024-03-05 19:48:54 -05:00
let builder: Arc<dyn KeyValueDatabaseEngine> = match &*config.database_backend {
2022-01-09 16:44:44 +01:00
"sqlite" => {
debug!("Got sqlite database backend");
2022-01-09 16:44:44 +01:00
#[cfg(not(feature = "sqlite"))]
2024-04-03 20:33:47 -07:00
return Err(Error::bad_config("Database backend not found."));
2022-01-09 16:44:44 +01:00
#[cfg(feature = "sqlite")]
2024-04-06 01:24:08 -07:00
Arc::new(Arc::<sqlite::Engine>::open(&config)?)
2022-01-09 16:44:44 +01:00
},
"rocksdb" => {
debug!("Got rocksdb database backend");
2022-01-09 16:44:44 +01:00
#[cfg(not(feature = "rocksdb"))]
2024-04-03 20:33:47 -07:00
return Err(Error::bad_config("Database backend not found."));
2022-01-09 16:44:44 +01:00
#[cfg(feature = "rocksdb")]
2024-04-06 01:24:08 -07:00
Arc::new(Arc::<rocksdb::Engine>::open(&config)?)
2022-01-09 16:44:44 +01:00
},
_ => {
2024-04-03 20:33:47 -07:00
return Err(Error::bad_config(
"Database backend not found. sqlite (not recommended) and rocksdb are the only supported backends.",
));
},
2024-03-05 19:48:54 -05:00
};
2022-10-05 20:34:31 +02:00
let db_raw = Box::new(Self {
db: builder.clone(),
userid_password: builder.open_tree("userid_password")?,
userid_displayname: builder.open_tree("userid_displayname")?,
userid_avatarurl: builder.open_tree("userid_avatarurl")?,
userid_blurhash: builder.open_tree("userid_blurhash")?,
userdeviceid_token: builder.open_tree("userdeviceid_token")?,
userdeviceid_metadata: builder.open_tree("userdeviceid_metadata")?,
userid_devicelistversion: builder.open_tree("userid_devicelistversion")?,
token_userdeviceid: builder.open_tree("token_userdeviceid")?,
onetimekeyid_onetimekeys: builder.open_tree("onetimekeyid_onetimekeys")?,
userid_lastonetimekeyupdate: builder.open_tree("userid_lastonetimekeyupdate")?,
keychangeid_userid: builder.open_tree("keychangeid_userid")?,
keyid_key: builder.open_tree("keyid_key")?,
userid_masterkeyid: builder.open_tree("userid_masterkeyid")?,
userid_selfsigningkeyid: builder.open_tree("userid_selfsigningkeyid")?,
userid_usersigningkeyid: builder.open_tree("userid_usersigningkeyid")?,
2022-10-05 20:34:31 +02:00
userfilterid_filter: builder.open_tree("userfilterid_filter")?,
todeviceid_events: builder.open_tree("todeviceid_events")?,
2024-04-01 20:48:40 -07:00
userid_presenceid: builder.open_tree("userid_presenceid")?,
presenceid_presence: builder.open_tree("presenceid_presence")?,
2024-03-05 19:48:54 -05:00
userdevicesessionid_uiaainfo: builder.open_tree("userdevicesessionid_uiaainfo")?,
2022-10-05 20:34:31 +02:00
userdevicesessionid_uiaarequest: RwLock::new(BTreeMap::new()),
readreceiptid_readreceipt: builder.open_tree("readreceiptid_readreceipt")?,
roomuserid_privateread: builder.open_tree("roomuserid_privateread")?, // "Private" read receipt
2022-10-05 20:34:31 +02:00
roomuserid_lastprivatereadupdate: builder.open_tree("roomuserid_lastprivatereadupdate")?,
pduid_pdu: builder.open_tree("pduid_pdu")?,
eventid_pduid: builder.open_tree("eventid_pduid")?,
roomid_pduleaves: builder.open_tree("roomid_pduleaves")?,
2024-03-05 19:48:54 -05:00
2022-10-05 20:34:31 +02:00
alias_roomid: builder.open_tree("alias_roomid")?,
aliasid_alias: builder.open_tree("aliasid_alias")?,
publicroomids: builder.open_tree("publicroomids")?,
2024-03-05 19:48:54 -05:00
2022-10-05 20:34:31 +02:00
threadid_userids: builder.open_tree("threadid_userids")?,
2024-03-05 19:48:54 -05:00
2022-10-05 20:34:31 +02:00
tokenids: builder.open_tree("tokenids")?,
2024-03-05 19:48:54 -05:00
2022-10-05 20:34:31 +02:00
roomserverids: builder.open_tree("roomserverids")?,
serverroomids: builder.open_tree("serverroomids")?,
userroomid_joined: builder.open_tree("userroomid_joined")?,
roomuserid_joined: builder.open_tree("roomuserid_joined")?,
roomid_joinedcount: builder.open_tree("roomid_joinedcount")?,
roomid_invitedcount: builder.open_tree("roomid_invitedcount")?,
2024-02-18 18:57:17 -05:00
roomuseroncejoinedids: builder.open_tree("roomuseroncejoinedids")?,
2022-10-05 20:34:31 +02:00
userroomid_invitestate: builder.open_tree("userroomid_invitestate")?,
roomuserid_invitecount: builder.open_tree("roomuserid_invitecount")?,
userroomid_leftstate: builder.open_tree("userroomid_leftstate")?,
roomuserid_leftcount: builder.open_tree("roomuserid_leftcount")?,
2024-03-05 19:48:54 -05:00
disabledroomids: builder.open_tree("disabledroomids")?,
2024-03-05 19:48:54 -05:00
2022-10-05 20:34:31 +02:00
bannedroomids: builder.open_tree("bannedroomids")?,
2024-03-05 19:48:54 -05:00
2022-10-05 20:34:31 +02:00
lazyloadedids: builder.open_tree("lazyloadedids")?,
2024-03-05 19:48:54 -05:00
2022-10-05 20:34:31 +02:00
userroomid_notificationcount: builder.open_tree("userroomid_notificationcount")?,
userroomid_highlightcount: builder.open_tree("userroomid_highlightcount")?,
roomuserid_lastnotificationread: builder.open_tree("userroomid_highlightcount")?,
2024-03-05 19:48:54 -05:00
2022-10-05 20:34:31 +02:00
statekey_shortstatekey: builder.open_tree("statekey_shortstatekey")?,
shortstatekey_statekey: builder.open_tree("shortstatekey_statekey")?,
2024-03-05 19:48:54 -05:00
2022-10-05 20:34:31 +02:00
shorteventid_authchain: builder.open_tree("shorteventid_authchain")?,
2024-03-05 19:48:54 -05:00
2022-10-05 20:34:31 +02:00
roomid_shortroomid: builder.open_tree("roomid_shortroomid")?,
2024-03-05 19:48:54 -05:00
2022-10-05 20:34:31 +02:00
shortstatehash_statediff: builder.open_tree("shortstatehash_statediff")?,
eventid_shorteventid: builder.open_tree("eventid_shorteventid")?,
shorteventid_eventid: builder.open_tree("shorteventid_eventid")?,
shorteventid_shortstatehash: builder.open_tree("shorteventid_shortstatehash")?,
roomid_shortstatehash: builder.open_tree("roomid_shortstatehash")?,
roomsynctoken_shortstatehash: builder.open_tree("roomsynctoken_shortstatehash")?,
statehash_shortstatehash: builder.open_tree("statehash_shortstatehash")?,
2024-03-05 19:48:54 -05:00
2022-10-05 20:34:31 +02:00
eventid_outlierpdu: builder.open_tree("eventid_outlierpdu")?,
softfailedeventids: builder.open_tree("softfailedeventids")?,
2024-03-05 19:48:54 -05:00
2022-10-05 20:34:31 +02:00
tofrom_relation: builder.open_tree("tofrom_relation")?,
referencedevents: builder.open_tree("referencedevents")?,
roomuserdataid_accountdata: builder.open_tree("roomuserdataid_accountdata")?,
roomusertype_roomuserdataid: builder.open_tree("roomusertype_roomuserdataid")?,
mediaid_file: builder.open_tree("mediaid_file")?,
url_previews: builder.open_tree("url_previews")?,
2024-03-17 01:42:30 -04:00
mediaid_user: builder.open_tree("mediaid_user")?,
2022-10-05 20:34:31 +02:00
backupid_algorithm: builder.open_tree("backupid_algorithm")?,
backupid_etag: builder.open_tree("backupid_etag")?,
backupkeyid_backup: builder.open_tree("backupkeyid_backup")?,
userdevicetxnid_response: builder.open_tree("userdevicetxnid_response")?,
servername_educount: builder.open_tree("servername_educount")?,
servernameevent_data: builder.open_tree("servernameevent_data")?,
servercurrentevent_data: builder.open_tree("servercurrentevent_data")?,
id_appserviceregistrations: builder.open_tree("id_appserviceregistrations")?,
senderkey_pusher: builder.open_tree("senderkey_pusher")?,
global: builder.open_tree("global")?,
server_signingkeys: builder.open_tree("server_signingkeys")?,
2024-03-05 19:48:54 -05:00
2024-04-11 19:39:17 -04:00
roomid_inviteviaservers: builder.open_tree("roomid_inviteviaservers")?,
2024-05-04 09:45:37 -04:00
#[allow(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)]
auth_chain_cache: Mutex::new(LruCache::new(
(f64::from(config.auth_chain_cache_capacity) * config.conduit_cache_capacity_modifier) as usize,
)),
2022-10-08 13:02:52 +02:00
our_real_users_cache: RwLock::new(HashMap::new()),
appservice_in_room_cache: RwLock::new(HashMap::new()),
lasttimelinecount_cache: Mutex::new(HashMap::new()),
2024-03-05 19:48:54 -05:00
});
2022-10-05 15:33:57 +02:00
let db = Box::leak(db_raw);
2024-03-05 19:48:54 -05:00
let services_raw = Box::new(Services::build(db, &config, tracing_reload_handler)?);
2024-03-05 19:48:54 -05:00
2022-10-05 12:45:54 +02:00
// This is the first and only time we initialize the SERVICE static
*SERVICES.write().unwrap() = Some(Box::leak(services_raw));
2024-03-05 19:48:54 -05:00
2024-04-06 01:24:08 -07:00
migrations(db, &config).await?;
2024-03-05 19:48:54 -05:00
2022-10-08 13:57:01 +02:00
services().admin.start_handler();
2024-03-05 19:48:54 -05:00
2022-04-07 12:11:55 +00:00
// Set emergency access for the conduit user
2022-10-05 12:45:54 +02:00
match set_emergency_access() {
2022-04-07 12:11:55 +00:00
Ok(pwd_set) => {
if pwd_set {
warn!(
"The Conduit account emergency password is set! Please unset it as soon as you finish admin \
account recovery!"
2022-10-05 12:45:54 +02:00
);
2024-03-25 17:05:11 -04:00
services()
.admin
.send_message(RoomMessageEventContent::text_plain(
"The Conduit account emergency password is set! Please unset it as soon as you finish \
admin account recovery!",
))
.await;
2022-04-07 12:11:55 +00:00
}
2024-03-05 19:48:54 -05:00
},
2022-04-07 12:11:55 +00:00
Err(e) => {
error!("Could not set the configured emergency password for the conduit user: {}", e);
},
};
2024-03-05 19:48:54 -05:00
2022-10-08 13:57:01 +02:00
services().sending.start_handler();
2024-03-05 19:48:54 -05:00
2024-04-01 20:48:40 -07:00
if config.allow_local_presence {
services().presence.start_handler();
}
2022-10-05 18:36:12 +02:00
Self::start_cleanup_task().await;
2023-07-29 20:01:38 +02:00
if services().globals.allow_check_for_updates() {
2024-03-23 12:34:28 -04:00
Self::start_check_for_updates_task().await;
2023-07-29 20:01:38 +02:00
}
2024-03-05 19:48:54 -05:00
2022-10-05 12:45:54 +02:00
Ok(())
2020-03-30 13:46:18 +02:00
}
2024-03-05 19:48:54 -05:00
2024-04-06 01:24:08 -07:00
fn check_db_setup(config: &Config) -> Result<()> {
let path = Path::new(&config.database_path);
2024-03-05 19:48:54 -05:00
2024-04-06 01:24:08 -07:00
let sqlite_exists = path.join("conduit.db").exists();
let rocksdb_exists = path.join("IDENTITY").exists();
2024-03-05 19:48:54 -05:00
2024-05-05 20:40:58 -04:00
if sqlite_exists && rocksdb_exists {
return Err(Error::bad_config("Multiple databases at database_path detected."));
2024-04-06 01:24:08 -07:00
}
if sqlite_exists && config.database_backend != "sqlite" {
return Err(Error::bad_config(
"Found sqlite at database_path, but is not specified in config.",
));
}
if rocksdb_exists && config.database_backend != "rocksdb" {
return Err(Error::bad_config(
"Found rocksdb at database_path, but is not specified in config.",
));
}
Ok(())
2021-07-14 07:07:08 +00:00
}
2024-03-05 19:48:54 -05:00
2022-10-05 18:36:12 +02:00
#[tracing::instrument]
2024-03-23 12:34:28 -04:00
async fn start_check_for_updates_task() {
let timer_interval = Duration::from_secs(7200); // 2 hours
2023-07-29 20:01:38 +02:00
tokio::spawn(async move {
let mut i = interval(timer_interval);
2024-03-23 12:34:28 -04:00
2023-07-29 20:01:38 +02:00
loop {
2024-03-23 12:34:28 -04:00
tokio::select! {
_ = i.tick() => {
debug!(target: "start_check_for_updates_task", "Timer ticked");
},
}
2024-03-23 14:38:15 -04:00
_ = Self::try_handle_updates().await;
2023-07-29 20:01:38 +02:00
}
});
}
2024-03-05 19:48:54 -05:00
2023-07-29 20:01:38 +02:00
async fn try_handle_updates() -> Result<()> {
2024-03-25 17:05:11 -04:00
let response = services()
.globals
.client
.default
.get("https://pupbrain.dev/check-for-updates/stable")
.send()
.await?;
2024-03-05 19:48:54 -05:00
2023-07-29 20:01:38 +02:00
let response = serde_json::from_str::<CheckForUpdatesResponse>(&response.text().await?).map_err(|e| {
2023-12-02 21:45:09 -05:00
error!("Bad check for updates response: {e}");
Error::BadServerResponse("Bad version check response")
})?;
2024-03-05 19:48:54 -05:00
2023-07-29 20:01:38 +02:00
let mut last_update_id = services().globals.last_check_for_updates_id()?;
for update in response.updates {
last_update_id = last_update_id.max(update.id);
if update.id > services().globals.last_check_for_updates_id()? {
2023-12-02 21:45:09 -05:00
error!("{}", update.message);
2024-03-25 17:05:11 -04:00
services()
.admin
.send_message(RoomMessageEventContent::text_plain(format!(
"@room: the following is a message from the conduwuit puppy. it was sent on '{}':\n\n{}",
update.date, update.message
)))
.await;
2023-07-29 20:01:38 +02:00
}
}
2024-03-25 17:05:11 -04:00
services()
.globals
.update_check_for_updates_id(last_update_id)?;
2024-03-05 19:48:54 -05:00
2023-07-29 20:01:38 +02:00
Ok(())
}
2024-03-05 19:48:54 -05:00
2023-07-29 20:01:38 +02:00
#[tracing::instrument]
2024-03-06 18:14:47 -05:00
async fn start_cleanup_task() {
2024-01-14 22:39:08 -05:00
let timer_interval = Duration::from_secs(u64::from(services().globals.config.cleanup_second_interval));
2024-03-05 19:48:54 -05:00
2021-07-14 07:07:08 +00:00
tokio::spawn(async move {
let mut i = interval(timer_interval);
2024-03-09 17:10:38 -05:00
#[cfg(unix)]
let mut hangup = signal(SignalKind::hangup()).expect("Failed to register SIGHUP signal receiver");
#[cfg(unix)]
let mut ctrl_c = signal(SignalKind::interrupt()).expect("Failed to register SIGINT signal receiver");
2021-07-15 18:09:10 +02:00
#[cfg(unix)]
2024-03-09 17:10:38 -05:00
let mut terminate = signal(SignalKind::terminate()).expect("Failed to register SIGTERM signal receiver");
2024-03-05 19:48:54 -05:00
2021-07-14 07:07:08 +00:00
loop {
2021-07-15 18:09:10 +02:00
#[cfg(unix)]
tokio::select! {
2021-08-01 16:59:52 +02:00
_ = i.tick() => {
2023-07-29 21:57:41 +00:00
debug!(target: "database-cleanup", "Timer ticked");
}
_ = hangup.recv() => {
debug!(target: "database-cleanup","Received SIGHUP");
2021-07-14 07:07:08 +00:00
}
2023-07-29 21:57:41 +00:00
_ = ctrl_c.recv() => {
2024-03-06 18:00:16 -05:00
debug!(target: "database-cleanup", "Received Ctrl+C");
2023-07-29 21:57:41 +00:00
}
_ = terminate.recv() => {
2024-03-06 18:00:16 -05:00
debug!(target: "database-cleanup","Received SIGTERM");
2021-07-14 07:07:08 +00:00
}
}
2024-03-06 18:00:16 -05:00
2021-07-15 18:09:10 +02:00
#[cfg(not(unix))]
2021-08-01 16:59:52 +02:00
{
2021-07-15 18:09:10 +02:00
i.tick().await;
2023-07-29 21:57:41 +00:00
debug!(target: "database-cleanup", "Timer ticked")
2021-07-14 07:07:08 +00:00
}
2024-03-06 18:00:16 -05:00
Self::perform_cleanup();
2021-07-14 07:07:08 +00:00
}
});
}
2024-04-06 01:24:08 -07:00
fn perform_cleanup() {
if !services().globals.config.rocksdb_periodic_cleanup {
return;
}
2024-04-06 01:24:08 -07:00
let start = Instant::now();
if let Err(e) = services().globals.cleanup() {
error!(target: "database-cleanup", "Ran into an error during cleanup: {}", e);
} else {
debug!(target: "database-cleanup", "Finished cleanup in {:#?}.", start.elapsed());
}
}
#[allow(dead_code)]
2024-04-22 23:48:57 -04:00
fn flush(&self) -> Result<()> {
2024-04-06 01:24:08 -07:00
let start = std::time::Instant::now();
let res = self.db.flush();
debug!("flush: took {:?}", start.elapsed());
res
}
2021-07-14 07:07:08 +00:00
}
2022-04-07 12:11:55 +00:00
/// Sets the emergency password and push rules for the @conduit account in case
/// emergency password is set
2022-10-05 12:45:54 +02:00
fn set_emergency_access() -> Result<bool> {
let conduit_user = UserId::parse_with_server_name("conduit", services().globals.server_name())
2022-04-07 12:11:55 +00:00
.expect("@conduit:server_name is a valid UserId");
2024-03-05 19:48:54 -05:00
2024-03-25 17:05:11 -04:00
services()
.users
.set_password(&conduit_user, services().globals.emergency_password().as_deref())?;
2024-03-05 19:48:54 -05:00
2022-10-05 12:45:54 +02:00
let (ruleset, res) = match services().globals.emergency_password() {
2022-04-07 12:11:55 +00:00
Some(_) => (Ruleset::server_default(&conduit_user), Ok(true)),
None => (Ruleset::new(), Ok(false)),
};
2024-03-05 19:48:54 -05:00
2022-10-05 12:45:54 +02:00
services().account_data.update(
2022-04-07 12:11:55 +00:00
None,
&conduit_user,
2022-01-18 16:53:25 +01:00
GlobalAccountDataEventType::PushRules.to_string().into(),
2022-10-05 15:33:57 +02:00
&serde_json::to_value(&GlobalAccountDataEvent {
2022-04-07 12:11:55 +00:00
content: PushRulesEventContent {
global: ruleset,
},
2022-10-05 20:34:31 +02:00
})
.expect("to json value always works"),
2022-04-07 12:11:55 +00:00
)?;
2024-03-05 19:48:54 -05:00
2022-04-07 12:11:55 +00:00
res
}