mod append; mod backfill; mod build; mod create; mod data; mod redact; use std::{fmt::Write, sync::Arc}; use async_trait::async_trait; pub use conduwuit_core::matrix::pdu::{PduId, RawPduId}; use conduwuit_core::{ Result, Server, at, err, matrix::{ event::Event, pdu::{PduCount, PduEvent}, }, utils::{MutexMap, MutexMapGuard, future::TryExtExt, stream::TryIgnore}, warn, }; use futures::{Future, Stream, TryStreamExt, pin_mut}; use ruma::{ CanonicalJsonObject, EventId, OwnedEventId, OwnedRoomId, RoomId, UserId, events::room::encrypted::Relation, }; use serde::Deserialize; use self::data::Data; pub use self::data::PdusIterItem; use crate::{ Dep, account_data, admin, appservice, globals, pusher, rooms, sending, server_keys, users, }; // Update Relationships #[derive(Deserialize)] struct ExtractRelatesTo { #[serde(rename = "m.relates_to")] relates_to: Relation, } #[derive(Clone, Debug, Deserialize)] struct ExtractEventId { event_id: OwnedEventId, } #[derive(Clone, Debug, Deserialize)] struct ExtractRelatesToEventId { #[serde(rename = "m.relates_to")] relates_to: ExtractEventId, } #[derive(Deserialize)] struct ExtractBody { body: Option, } pub struct Service { services: Services, db: Data, pub mutex_insert: RoomMutexMap, } struct Services { server: Arc, account_data: Dep, appservice: Dep, admin: Dep, alias: Dep, globals: Dep, short: Dep, state: Dep, state_cache: Dep, state_accessor: Dep, pdu_metadata: Dep, read_receipt: Dep, sending: Dep, server_keys: Dep, user: Dep, users: Dep, pusher: Dep, threads: Dep, search: Dep, spaces: Dep, event_handler: Dep, } type RoomMutexMap = MutexMap; pub type RoomMutexGuard = MutexMapGuard; #[async_trait] impl crate::Service for Service { fn build(args: crate::Args<'_>) -> Result> { Ok(Arc::new(Self { services: Services { server: args.server.clone(), account_data: args.depend::("account_data"), appservice: args.depend::("appservice"), admin: args.depend::("admin"), alias: args.depend::("rooms::alias"), globals: args.depend::("globals"), short: args.depend::("rooms::short"), state: args.depend::("rooms::state"), state_cache: args.depend::("rooms::state_cache"), state_accessor: args .depend::("rooms::state_accessor"), pdu_metadata: args.depend::("rooms::pdu_metadata"), read_receipt: args.depend::("rooms::read_receipt"), sending: args.depend::("sending"), server_keys: args.depend::("server_keys"), user: args.depend::("rooms::user"), users: args.depend::("users"), pusher: args.depend::("pusher"), threads: args.depend::("rooms::threads"), search: args.depend::("rooms::search"), spaces: args.depend::("rooms::spaces"), event_handler: args .depend::("rooms::event_handler"), }, db: Data::new(&args), mutex_insert: RoomMutexMap::new(), })) } async fn memory_usage(&self, out: &mut (dyn Write + Send)) -> Result { let mutex_insert = self.mutex_insert.len(); writeln!(out, "insert_mutex: {mutex_insert}")?; Ok(()) } fn name(&self) -> &str { crate::service::make_name(std::module_path!()) } } impl Service { #[tracing::instrument(skip(self), level = "debug")] pub async fn first_pdu_in_room(&self, room_id: &RoomId) -> Result { self.first_item_in_room(room_id).await.map(at!(1)) } #[tracing::instrument(skip(self), level = "debug")] pub async fn first_item_in_room(&self, room_id: &RoomId) -> Result<(PduCount, impl Event)> { let pdus = self.pdus(None, room_id, None); pin_mut!(pdus); pdus.try_next() .await? .ok_or_else(|| err!(Request(NotFound("No PDU found in room")))) } #[tracing::instrument(skip(self), level = "debug")] pub async fn latest_pdu_in_room(&self, room_id: &RoomId) -> Result { self.db.latest_pdu_in_room(None, room_id).await } #[tracing::instrument(skip(self), level = "debug")] pub async fn last_timeline_count( &self, sender_user: Option<&UserId>, room_id: &RoomId, ) -> Result { self.db.last_timeline_count(sender_user, room_id).await } /// Returns the `count` of this pdu's id. pub async fn get_pdu_count(&self, event_id: &EventId) -> Result { self.db.get_pdu_count(event_id).await } /// Returns the json of a pdu. pub async fn get_pdu_json(&self, event_id: &EventId) -> Result { self.db.get_pdu_json(event_id).await } /// Returns the json of a pdu. #[inline] pub async fn get_non_outlier_pdu_json( &self, event_id: &EventId, ) -> Result { self.db.get_non_outlier_pdu_json(event_id).await } /// Returns the pdu's id. #[inline] pub async fn get_pdu_id(&self, event_id: &EventId) -> Result { self.db.get_pdu_id(event_id).await } /// Returns the pdu. /// /// Checks the `eventid_outlierpdu` Tree if not found in the timeline. #[inline] pub async fn get_non_outlier_pdu(&self, event_id: &EventId) -> Result { self.db.get_non_outlier_pdu(event_id).await } /// Returns the pdu. /// /// Checks the `eventid_outlierpdu` Tree if not found in the timeline. #[inline] pub async fn get_pdu(&self, event_id: &EventId) -> Result { self.db.get_pdu(event_id).await } /// Returns the pdu. /// /// This does __NOT__ check the outliers `Tree`. #[inline] pub async fn get_pdu_from_id(&self, pdu_id: &RawPduId) -> Result { self.db.get_pdu_from_id(pdu_id).await } /// Returns the pdu as a `BTreeMap`. #[inline] pub async fn get_pdu_json_from_id(&self, pdu_id: &RawPduId) -> Result { self.db.get_pdu_json_from_id(pdu_id).await } /// Checks if pdu exists /// /// Checks the `eventid_outlierpdu` Tree if not found in the timeline. #[inline] pub fn pdu_exists<'a>( &'a self, event_id: &'a EventId, ) -> impl Future + Send + 'a { self.db.pdu_exists(event_id).is_ok() } /// Removes a pdu and creates a new one with the same id. #[tracing::instrument(skip(self), level = "debug")] pub async fn replace_pdu(&self, pdu_id: &RawPduId, pdu_json: &CanonicalJsonObject) -> Result { self.db.replace_pdu(pdu_id, pdu_json).await } /// Returns an iterator over all PDUs in a room. Unknown rooms produce no /// items. #[inline] pub fn all_pdus<'a>( &'a self, user_id: &'a UserId, room_id: &'a RoomId, ) -> impl Stream + Send + 'a { self.pdus(Some(user_id), room_id, None).ignore_err() } /// Reverse iteration starting at from. #[tracing::instrument(skip(self), level = "debug")] pub fn pdus_rev<'a>( &'a self, user_id: Option<&'a UserId>, room_id: &'a RoomId, until: Option, ) -> impl Stream> + Send + 'a { self.db .pdus_rev(user_id, room_id, until.unwrap_or_else(PduCount::max)) } /// Forward iteration starting at from. #[tracing::instrument(skip(self), level = "debug")] pub fn pdus<'a>( &'a self, user_id: Option<&'a UserId>, room_id: &'a RoomId, from: Option, ) -> impl Stream> + Send + 'a { self.db .pdus(user_id, room_id, from.unwrap_or_else(PduCount::min)) } }