conduwuit/src/service/rooms/mod.rs

217 lines
8.3 KiB
Rust
Raw Normal View History

mod edus;
pub use edus::RoomEdus;
use crate::{
pdu::{EventHash, PduBuilder},
utils, Database, Error, PduEvent, Result,
};
2021-06-30 09:52:01 +02:00
use lru_cache::LruCache;
use regex::Regex;
use ring::digest;
2020-06-05 18:19:26 +02:00
use ruma::{
2021-04-13 15:00:45 +02:00
api::{client::error::ErrorKind, federation},
2020-06-05 18:19:26 +02:00
events::{
direct::DirectEvent,
ignored_user_list::IgnoredUserListEvent,
push_rules::PushRulesEvent,
room::{
create::RoomCreateEventContent,
member::{MembershipState, RoomMemberEventContent},
power_levels::RoomPowerLevelsEventContent,
},
tag::TagEvent,
2022-04-06 21:31:29 +02:00
AnyStrippedStateEvent, AnySyncStateEvent, GlobalAccountDataEventType,
RoomAccountDataEventType, RoomEventType, StateEventType,
2020-05-24 18:25:52 +02:00
},
push::{Action, Ruleset, Tweak},
2021-04-26 18:20:20 +02:00
serde::{CanonicalJsonObject, CanonicalJsonValue, Raw},
state_res::{self, RoomVersion, StateMap},
2022-01-04 14:30:13 +01:00
uint, DeviceId, EventId, RoomAliasId, RoomId, RoomVersionId, ServerName, UserId,
2020-05-24 18:25:52 +02:00
};
use serde::Deserialize;
use serde_json::value::to_raw_value;
use std::{
borrow::Cow,
2022-02-08 09:25:44 +01:00
collections::{hash_map, BTreeMap, HashMap, HashSet},
2021-11-27 16:35:59 +01:00
fmt::Debug,
iter,
mem::size_of,
2021-08-28 11:39:33 +02:00
sync::{Arc, Mutex, RwLock},
};
use tokio::sync::MutexGuard;
use tracing::{error, warn};
use super::{abstraction::Tree, pusher};
2020-11-09 12:21:04 +01:00
/// The unique identifier of each state group.
///
/// This is created when a state group is added to the database by
/// hashing the entire state.
pub type StateHashId = Vec<u8>;
2021-08-12 23:04:00 +02:00
pub type CompressedStateEvent = [u8; 2 * size_of::<u64>()];
pub struct Rooms {
pub edus: RoomEdus,
2021-08-12 23:04:00 +02:00
pub(super) pduid_pdu: Arc<dyn Tree>, // PduId = ShortRoomId + Count
2021-06-08 18:10:00 +02:00
pub(super) eventid_pduid: Arc<dyn Tree>,
pub(super) roomid_pduleaves: Arc<dyn Tree>,
pub(super) alias_roomid: Arc<dyn Tree>,
pub(super) aliasid_alias: Arc<dyn Tree>, // AliasId = RoomId + Count
pub(super) publicroomids: Arc<dyn Tree>,
pub(super) tokenids: Arc<dyn Tree>, // TokenId = ShortRoomId + Token + PduIdCount
2020-08-18 12:15:27 +02:00
2020-09-14 20:23:19 +02:00
/// Participating servers in a room.
2021-06-08 18:10:00 +02:00
pub(super) roomserverids: Arc<dyn Tree>, // RoomServerId = RoomId + ServerName
pub(super) serverroomids: Arc<dyn Tree>, // ServerRoomId = ServerName + RoomId
2021-06-08 18:10:00 +02:00
pub(super) userroomid_joined: Arc<dyn Tree>,
pub(super) roomuserid_joined: Arc<dyn Tree>,
pub(super) roomid_joinedcount: Arc<dyn Tree>,
2021-08-28 11:39:33 +02:00
pub(super) roomid_invitedcount: Arc<dyn Tree>,
2021-06-08 18:10:00 +02:00
pub(super) roomuseroncejoinedids: Arc<dyn Tree>,
pub(super) userroomid_invitestate: Arc<dyn Tree>, // InviteState = Vec<Raw<Pdu>>
pub(super) roomuserid_invitecount: Arc<dyn Tree>, // InviteCount = Count
pub(super) userroomid_leftstate: Arc<dyn Tree>,
pub(super) roomuserid_leftcount: Arc<dyn Tree>,
pub(super) disabledroomids: Arc<dyn Tree>, // Rooms where incoming federation handling is disabled
2022-01-04 14:30:13 +01:00
pub(super) lazyloadedids: Arc<dyn Tree>, // LazyLoadedIds = UserId + DeviceId + RoomId + LazyLoadedUserId
2021-06-08 18:10:00 +02:00
pub(super) userroomid_notificationcount: Arc<dyn Tree>, // NotifyCount = u64
pub(super) userroomid_highlightcount: Arc<dyn Tree>, // HightlightCount = u64
2020-09-12 21:30:07 +02:00
/// Remember the current state hash of a room.
2021-06-08 18:10:00 +02:00
pub(super) roomid_shortstatehash: Arc<dyn Tree>,
pub(super) roomsynctoken_shortstatehash: Arc<dyn Tree>,
2020-09-12 21:30:07 +02:00
/// Remember the state hash at events in the past.
2021-06-08 18:10:00 +02:00
pub(super) shorteventid_shortstatehash: Arc<dyn Tree>,
2021-03-17 22:30:25 +01:00
/// StateKey = EventType + StateKey, ShortStateKey = Count
2021-06-08 18:10:00 +02:00
pub(super) statekey_shortstatekey: Arc<dyn Tree>,
pub(super) shortstatekey_statekey: Arc<dyn Tree>,
pub(super) roomid_shortroomid: Arc<dyn Tree>,
2021-06-08 18:10:00 +02:00
pub(super) shorteventid_eventid: Arc<dyn Tree>,
pub(super) eventid_shorteventid: Arc<dyn Tree>,
2021-06-08 18:10:00 +02:00
pub(super) statehash_shortstatehash: Arc<dyn Tree>,
pub(super) shortstatehash_statediff: Arc<dyn Tree>, // StateDiff = parent (or 0) + (shortstatekey+shorteventid++) + 0_u64 + (shortstatekey+shorteventid--)
pub(super) shorteventid_authchain: Arc<dyn Tree>,
2021-02-01 12:44:30 -05:00
/// RoomId + EventId -> outlier PDU.
/// Any pdu that has passed the steps 1-8 in the incoming event /federation/send/txn.
2021-06-08 18:10:00 +02:00
pub(super) eventid_outlierpdu: Arc<dyn Tree>,
2021-08-28 11:39:33 +02:00
pub(super) softfailedeventids: Arc<dyn Tree>,
/// RoomId + EventId -> Parent PDU EventId.
pub(super) referencedevents: Arc<dyn Tree>,
2021-06-30 09:52:01 +02:00
2021-11-26 20:36:40 +01:00
pub(super) pdu_cache: Mutex<LruCache<Box<EventId>, Arc<PduEvent>>>,
pub(super) shorteventid_cache: Mutex<LruCache<u64, Arc<EventId>>>,
pub(super) auth_chain_cache: Mutex<LruCache<Vec<u64>, Arc<HashSet<u64>>>>,
2021-11-26 20:36:40 +01:00
pub(super) eventidshort_cache: Mutex<LruCache<Box<EventId>, u64>>,
2022-04-06 21:31:29 +02:00
pub(super) statekeyshort_cache: Mutex<LruCache<(StateEventType, String), u64>>,
pub(super) shortstatekey_cache: Mutex<LruCache<u64, (StateEventType, String)>>,
2021-11-26 20:36:40 +01:00
pub(super) our_real_users_cache: RwLock<HashMap<Box<RoomId>, Arc<HashSet<Box<UserId>>>>>,
pub(super) appservice_in_room_cache: RwLock<HashMap<Box<RoomId>, HashMap<String, bool>>>,
2022-01-04 14:30:13 +01:00
pub(super) lazy_load_waiting:
Mutex<HashMap<(Box<UserId>, Box<DeviceId>, Box<RoomId>, u64), HashSet<Box<UserId>>>>,
2021-08-15 13:17:42 +02:00
pub(super) stateinfo_cache: Mutex<
LruCache<
u64,
Vec<(
u64, // sstatehash
HashSet<CompressedStateEvent>, // full state
HashSet<CompressedStateEvent>, // added
HashSet<CompressedStateEvent>, // removed
)>,
>,
>,
2022-02-08 09:25:44 +01:00
pub(super) lasttimelinecount_cache: Mutex<HashMap<Box<RoomId>, u64>>,
}
impl Rooms {
/// Returns true if a given room version is supported
#[tracing::instrument(skip(self, db))]
pub fn is_supported_version(&self, db: &Database, room_version: &RoomVersionId) -> bool {
db.globals.supported_room_versions().contains(room_version)
}
2020-09-14 20:23:19 +02:00
/// This fetches auth events from the current state.
#[tracing::instrument(skip(self))]
pub fn get_auth_events(
&self,
room_id: &RoomId,
2022-04-06 21:31:29 +02:00
kind: &RoomEventType,
sender: &UserId,
state_key: Option<&str>,
content: &serde_json::value::RawValue,
) -> Result<StateMap<Arc<PduEvent>>> {
let shortstatehash =
if let Some(current_shortstatehash) = self.current_shortstatehash(room_id)? {
current_shortstatehash
} else {
return Ok(HashMap::new());
};
let auth_events = state_res::auth_types_for_event(kind, sender, state_key, content)
.expect("content is a valid JSON object");
let mut sauthevents = auth_events
.into_iter()
.filter_map(|(event_type, state_key)| {
2022-04-06 21:31:29 +02:00
self.get_shortstatekey(&event_type.to_string().into(), &state_key)
.ok()
.flatten()
.map(|s| (s, (event_type, state_key)))
})
.collect::<HashMap<_, _>>();
let full_state = self
.load_shortstatehash_info(shortstatehash)?
.pop()
.expect("there is always one layer")
.1;
Ok(full_state
.into_iter()
.filter_map(|compressed| self.parse_compressed_state_event(compressed).ok())
.filter_map(|(shortstatekey, event_id)| {
sauthevents.remove(&shortstatekey).map(|k| (k, event_id))
})
.filter_map(|(k, event_id)| self.get_pdu(&event_id).ok().flatten().map(|pdu| (k, pdu)))
.collect())
}
/// Generate a new StateHash.
///
2020-09-12 21:30:07 +02:00
/// A unique hash made from hashing all PDU ids of the state joined with 0xff.
2021-03-24 11:52:10 +01:00
fn calculate_hash(&self, bytes_list: &[&[u8]]) -> StateHashId {
2020-09-12 21:30:07 +02:00
// We only hash the pdu's event ids, not the whole pdu
2021-03-17 22:30:25 +01:00
let bytes = bytes_list.join(&0xff);
2020-09-12 21:30:07 +02:00
let hash = digest::digest(&digest::SHA256, &bytes);
2021-03-24 11:52:10 +01:00
hash.as_ref().into()
}
2021-04-11 21:01:27 +02:00
#[tracing::instrument(skip(self))]
2022-06-19 22:56:14 +02:00
pub fn iter_ids(&self) -> impl Iterator<Item = Result<Box<RoomId>>> + '_ {
self.roomid_shortroomid.iter().map(|(bytes, _)| {
RoomId::parse(
utils::string_from_bytes(&bytes).map_err(|_| {
Error::bad_database("Room ID in publicroomids is invalid unicode.")
})?,
)
.map_err(|_| Error::bad_database("Room ID in roomid_shortroomid is invalid."))
2020-09-15 16:13:54 +02:00
})
}
2022-06-19 22:56:14 +02:00
pub fn is_disabled(&self, room_id: &RoomId) -> Result<bool> {
Ok(self.disabledroomids.get(room_id.as_bytes())?.is_some())
}
}