devirtualize service Data traits

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk 2024-05-27 03:17:20 +00:00
parent a6edaad6fc
commit 7ad7badd60
64 changed files with 1190 additions and 1176 deletions

View file

@ -1,31 +1,26 @@
use std::sync::Arc;
use database::KvTree;
use ruma::{api::client::error::ErrorKind, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, RoomAliasId, RoomId, UserId};
use crate::{services, utils, Error, KeyValueDatabase, Result};
pub trait Data: Send + Sync {
/// Creates or updates the alias to the given room id.
fn set_alias(&self, alias: &RoomAliasId, room_id: &RoomId, user_id: &UserId) -> Result<()>;
/// Forgets about an alias. Returns an error if the alias did not exist.
fn remove_alias(&self, alias: &RoomAliasId) -> Result<()>;
/// Looks up the roomid for the given alias.
fn resolve_local_alias(&self, alias: &RoomAliasId) -> Result<Option<OwnedRoomId>>;
/// Finds the user who assigned the given alias to a room
fn who_created_alias(&self, alias: &RoomAliasId) -> Result<Option<OwnedUserId>>;
/// Returns all local aliases that point to the given room
fn local_aliases_for_room<'a>(
&'a self, room_id: &RoomId,
) -> Box<dyn Iterator<Item = Result<OwnedRoomAliasId>> + 'a>;
/// Returns all local aliases on the server
fn all_local_aliases<'a>(&'a self) -> Box<dyn Iterator<Item = Result<(OwnedRoomId, String)>> + 'a>;
pub struct Data {
alias_userid: Arc<dyn KvTree>,
alias_roomid: Arc<dyn KvTree>,
aliasid_alias: Arc<dyn KvTree>,
}
impl Data for KeyValueDatabase {
fn set_alias(&self, alias: &RoomAliasId, room_id: &RoomId, user_id: &UserId) -> Result<()> {
impl Data {
pub(super) fn new(db: &Arc<KeyValueDatabase>) -> Self {
Self {
alias_userid: db.alias_userid.clone(),
alias_roomid: db.alias_roomid.clone(),
aliasid_alias: db.aliasid_alias.clone(),
}
}
pub(super) fn set_alias(&self, alias: &RoomAliasId, room_id: &RoomId, user_id: &UserId) -> Result<()> {
// Comes first as we don't want a stuck alias
self.alias_userid
.insert(alias.alias().as_bytes(), user_id.as_bytes())?;
@ -41,7 +36,7 @@ impl Data for KeyValueDatabase {
Ok(())
}
fn remove_alias(&self, alias: &RoomAliasId) -> Result<()> {
pub(super) fn remove_alias(&self, alias: &RoomAliasId) -> Result<()> {
if let Some(room_id) = self.alias_roomid.get(alias.alias().as_bytes())? {
let mut prefix = room_id;
prefix.push(0xFF);
@ -60,7 +55,7 @@ impl Data for KeyValueDatabase {
Ok(())
}
fn resolve_local_alias(&self, alias: &RoomAliasId) -> Result<Option<OwnedRoomId>> {
pub fn resolve_local_alias(&self, alias: &RoomAliasId) -> Result<Option<OwnedRoomId>> {
self.alias_roomid
.get(alias.alias().as_bytes())?
.map(|bytes| {
@ -73,7 +68,7 @@ impl Data for KeyValueDatabase {
.transpose()
}
fn who_created_alias(&self, alias: &RoomAliasId) -> Result<Option<OwnedUserId>> {
pub(super) fn who_created_alias(&self, alias: &RoomAliasId) -> Result<Option<OwnedUserId>> {
self.alias_userid
.get(alias.alias().as_bytes())?
.map(|bytes| {
@ -86,7 +81,7 @@ impl Data for KeyValueDatabase {
.transpose()
}
fn local_aliases_for_room<'a>(
pub fn local_aliases_for_room<'a>(
&'a self, room_id: &RoomId,
) -> Box<dyn Iterator<Item = Result<OwnedRoomAliasId>> + 'a> {
let mut prefix = room_id.as_bytes().to_vec();
@ -100,7 +95,7 @@ impl Data for KeyValueDatabase {
}))
}
fn all_local_aliases<'a>(&'a self) -> Box<dyn Iterator<Item = Result<(OwnedRoomId, String)>> + 'a> {
pub fn all_local_aliases<'a>(&'a self) -> Box<dyn Iterator<Item = Result<(OwnedRoomId, String)>> + 'a> {
Box::new(
self.alias_roomid
.iter()

View file

@ -1,3 +1,6 @@
use conduit::Server;
use database::KeyValueDatabase;
mod data;
use std::sync::Arc;
@ -15,10 +18,16 @@ use ruma::{
use crate::{services, Error, Result};
pub struct Service {
pub db: Arc<dyn Data>,
pub db: Data,
}
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<KeyValueDatabase>) -> Result<Self> {
Ok(Self {
db: Data::new(db),
})
}
#[tracing::instrument(skip(self))]
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 {

View file

@ -1,16 +1,25 @@
use std::{mem::size_of, sync::Arc};
use database::KvTree;
use crate::{utils, KeyValueDatabase, Result};
pub trait Data: Send + Sync {
fn get_cached_eventid_authchain(&self, shorteventid: &[u64]) -> Result<Option<Arc<[u64]>>>;
fn cache_auth_chain(&self, shorteventid: Vec<u64>, auth_chain: Arc<[u64]>) -> Result<()>;
pub(super) struct Data {
shorteventid_authchain: Arc<dyn KvTree>,
db: Arc<KeyValueDatabase>,
}
impl Data for KeyValueDatabase {
fn get_cached_eventid_authchain(&self, key: &[u64]) -> Result<Option<Arc<[u64]>>> {
impl Data {
pub(super) fn new(db: &Arc<KeyValueDatabase>) -> Self {
Self {
shorteventid_authchain: db.shorteventid_authchain.clone(),
db: db.clone(),
}
}
pub(super) fn get_cached_eventid_authchain(&self, key: &[u64]) -> Result<Option<Arc<[u64]>>> {
// Check RAM cache
if let Some(result) = self.auth_chain_cache.lock().unwrap().get_mut(key) {
if let Some(result) = self.db.auth_chain_cache.lock().unwrap().get_mut(key) {
return Ok(Some(Arc::clone(result)));
}
@ -29,7 +38,8 @@ impl Data for KeyValueDatabase {
if let Some(chain) = chain {
// Cache in RAM
self.auth_chain_cache
self.db
.auth_chain_cache
.lock()
.unwrap()
.insert(vec![key[0]], Arc::clone(&chain));
@ -41,7 +51,7 @@ impl Data for KeyValueDatabase {
Ok(None)
}
fn cache_auth_chain(&self, key: Vec<u64>, auth_chain: Arc<[u64]>) -> Result<()> {
pub(super) fn cache_auth_chain(&self, key: Vec<u64>, auth_chain: Arc<[u64]>) -> Result<()> {
// Only persist single events in db
if key.len() == 1 {
self.shorteventid_authchain.insert(
@ -54,7 +64,8 @@ impl Data for KeyValueDatabase {
}
// Cache in RAM
self.auth_chain_cache
self.db
.auth_chain_cache
.lock()
.unwrap()
.insert(key, auth_chain);

View file

@ -1,3 +1,6 @@
use conduit::Server;
use database::KeyValueDatabase;
mod data;
use std::{
collections::{BTreeSet, HashSet},
@ -11,10 +14,16 @@ use tracing::{debug, error, trace, warn};
use crate::{services, Error, Result};
pub struct Service {
pub db: Arc<dyn Data>,
db: Data,
}
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<KeyValueDatabase>) -> Result<Self> {
Ok(Self {
db: Data::new(db),
})
}
pub async fn event_ids_iter<'a>(
&self, room_id: &RoomId, starting_events_: Vec<Arc<EventId>>,
) -> Result<impl Iterator<Item = Arc<EventId>> + 'a> {

View file

@ -1,31 +1,34 @@
use std::sync::Arc;
use database::KvTree;
use ruma::{OwnedRoomId, RoomId};
use crate::{utils, Error, KeyValueDatabase, Result};
pub trait Data: Send + Sync {
/// Adds the room to the public room directory
fn set_public(&self, room_id: &RoomId) -> Result<()>;
/// Removes the room from the public room directory.
fn set_not_public(&self, room_id: &RoomId) -> Result<()>;
/// Returns true if the room is in the public room directory.
fn is_public_room(&self, room_id: &RoomId) -> Result<bool>;
/// Returns the unsorted public room directory
fn public_rooms<'a>(&'a self) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a>;
pub(super) struct Data {
publicroomids: Arc<dyn KvTree>,
}
impl Data for KeyValueDatabase {
fn set_public(&self, room_id: &RoomId) -> Result<()> { self.publicroomids.insert(room_id.as_bytes(), &[]) }
impl Data {
pub(super) fn new(db: &Arc<KeyValueDatabase>) -> Self {
Self {
publicroomids: db.publicroomids.clone(),
}
}
fn set_not_public(&self, room_id: &RoomId) -> Result<()> { self.publicroomids.remove(room_id.as_bytes()) }
pub(super) fn set_public(&self, room_id: &RoomId) -> Result<()> {
self.publicroomids.insert(room_id.as_bytes(), &[])
}
fn is_public_room(&self, room_id: &RoomId) -> Result<bool> {
pub(super) fn set_not_public(&self, room_id: &RoomId) -> Result<()> {
self.publicroomids.remove(room_id.as_bytes())
}
pub(super) fn is_public_room(&self, room_id: &RoomId) -> Result<bool> {
Ok(self.publicroomids.get(room_id.as_bytes())?.is_some())
}
fn public_rooms<'a>(&'a self) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a> {
pub(super) fn public_rooms<'a>(&'a self) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a> {
Box::new(self.publicroomids.iter().map(|(bytes, _)| {
RoomId::parse(
utils::string_from_bytes(&bytes)

View file

@ -1,3 +1,6 @@
use conduit::Server;
use database::KeyValueDatabase;
mod data;
use std::sync::Arc;
@ -8,10 +11,16 @@ use ruma::{OwnedRoomId, RoomId};
use crate::Result;
pub struct Service {
pub db: Arc<dyn Data>,
db: Data,
}
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<KeyValueDatabase>) -> Result<Self> {
Ok(Self {
db: Data::new(db),
})
}
#[tracing::instrument(skip(self))]
pub fn set_public(&self, room_id: &RoomId) -> Result<()> { self.db.set_public(room_id) }

View file

@ -1,6 +1,8 @@
use conduit::Server;
use database::KeyValueDatabase;
mod parse_incoming_pdu;
mod signing_keys;
pub struct Service;
use std::{
cmp,
@ -32,6 +34,8 @@ use tracing::{debug, error, info, trace, warn};
use super::state_compressor::CompressedStateEvent;
use crate::{debug_error, debug_info, pdu, services, Error, PduEvent, Result};
pub struct Service;
// We use some AsyncRecursiveType hacks here so we can call async funtion
// recursively.
type AsyncRecursiveType<'a, T> = Pin<Box<dyn Future<Output = T> + 'a + Send>>;
@ -41,6 +45,8 @@ type AsyncRecursiveCanonicalJsonResult<'a> =
AsyncRecursiveType<'a, Result<(Arc<PduEvent>, BTreeMap<String, CanonicalJsonValue>)>>;
impl Service {
pub fn build(_server: &Arc<Server>, _db: &Arc<KeyValueDatabase>) -> Result<Self> { Ok(Self {}) }
/// When receiving an event one needs to:
/// 0. Check the server is in the room
/// 1. Skip the PDU if we already know about it

View file

@ -1,22 +1,22 @@
use std::sync::Arc;
use database::KvTree;
use ruma::{DeviceId, RoomId, UserId};
use crate::{KeyValueDatabase, Result};
pub trait Data: Send + Sync {
fn lazy_load_was_sent_before(
&self, user_id: &UserId, device_id: &DeviceId, room_id: &RoomId, ll_user: &UserId,
) -> Result<bool>;
fn lazy_load_confirm_delivery(
&self, user_id: &UserId, device_id: &DeviceId, room_id: &RoomId,
confirmed_user_ids: &mut dyn Iterator<Item = &UserId>,
) -> Result<()>;
fn lazy_load_reset(&self, user_id: &UserId, device_id: &DeviceId, room_id: &RoomId) -> Result<()>;
pub struct Data {
lazyloadedids: Arc<dyn KvTree>,
}
impl Data for KeyValueDatabase {
fn lazy_load_was_sent_before(
impl Data {
pub(super) fn new(db: &Arc<KeyValueDatabase>) -> Self {
Self {
lazyloadedids: db.lazyloadedids.clone(),
}
}
pub(super) fn lazy_load_was_sent_before(
&self, user_id: &UserId, device_id: &DeviceId, room_id: &RoomId, ll_user: &UserId,
) -> Result<bool> {
let mut key = user_id.as_bytes().to_vec();
@ -29,7 +29,7 @@ impl Data for KeyValueDatabase {
Ok(self.lazyloadedids.get(&key)?.is_some())
}
fn lazy_load_confirm_delivery(
pub(super) fn lazy_load_confirm_delivery(
&self, user_id: &UserId, device_id: &DeviceId, room_id: &RoomId,
confirmed_user_ids: &mut dyn Iterator<Item = &UserId>,
) -> Result<()> {
@ -49,7 +49,7 @@ impl Data for KeyValueDatabase {
Ok(())
}
fn lazy_load_reset(&self, user_id: &UserId, device_id: &DeviceId, room_id: &RoomId) -> Result<()> {
pub(super) fn lazy_load_reset(&self, user_id: &UserId, device_id: &DeviceId, room_id: &RoomId) -> Result<()> {
let mut prefix = user_id.as_bytes().to_vec();
prefix.push(0xFF);
prefix.extend_from_slice(device_id.as_bytes());

View file

@ -1,3 +1,6 @@
use conduit::Server;
use database::KeyValueDatabase;
mod data;
use std::{
collections::{HashMap, HashSet},
@ -11,13 +14,20 @@ use tokio::sync::Mutex;
use crate::{PduCount, Result};
pub struct Service {
pub db: Arc<dyn Data>,
pub db: Data,
#[allow(clippy::type_complexity)]
pub lazy_load_waiting: Mutex<HashMap<(OwnedUserId, OwnedDeviceId, OwnedRoomId, PduCount), HashSet<OwnedUserId>>>,
}
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<KeyValueDatabase>) -> Result<Self> {
Ok(Self {
db: Data::new(db),
lazy_load_waiting: Mutex::new(HashMap::new()),
})
}
#[tracing::instrument(skip(self))]
pub fn lazy_load_was_sent_before(
&self, user_id: &UserId, device_id: &DeviceId, room_id: &RoomId, ll_user: &UserId,

View file

@ -1,20 +1,29 @@
use std::sync::Arc;
use database::KvTree;
use ruma::{OwnedRoomId, RoomId};
use tracing::error;
use crate::{services, utils, Error, KeyValueDatabase, Result};
pub trait Data: Send + Sync {
fn exists(&self, room_id: &RoomId) -> Result<bool>;
fn iter_ids<'a>(&'a self) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a>;
fn is_disabled(&self, room_id: &RoomId) -> Result<bool>;
fn disable_room(&self, room_id: &RoomId, disabled: bool) -> Result<()>;
fn is_banned(&self, room_id: &RoomId) -> Result<bool>;
fn ban_room(&self, room_id: &RoomId, banned: bool) -> Result<()>;
fn list_banned_rooms<'a>(&'a self) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a>;
pub struct Data {
disabledroomids: Arc<dyn KvTree>,
bannedroomids: Arc<dyn KvTree>,
roomid_shortroomid: Arc<dyn KvTree>,
pduid_pdu: Arc<dyn KvTree>,
}
impl Data for KeyValueDatabase {
fn exists(&self, room_id: &RoomId) -> Result<bool> {
impl Data {
pub(super) fn new(db: &Arc<KeyValueDatabase>) -> Self {
Self {
disabledroomids: db.disabledroomids.clone(),
bannedroomids: db.bannedroomids.clone(),
roomid_shortroomid: db.roomid_shortroomid.clone(),
pduid_pdu: db.pduid_pdu.clone(),
}
}
pub(super) fn exists(&self, room_id: &RoomId) -> Result<bool> {
let prefix = match services().rooms.short.get_shortroomid(room_id)? {
Some(b) => b.to_be_bytes().to_vec(),
None => return Ok(false),
@ -29,7 +38,7 @@ impl Data for KeyValueDatabase {
.is_some())
}
fn iter_ids<'a>(&'a self) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a> {
pub(super) fn iter_ids<'a>(&'a self) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a> {
Box::new(self.roomid_shortroomid.iter().map(|(bytes, _)| {
RoomId::parse(
utils::string_from_bytes(&bytes)
@ -39,11 +48,11 @@ impl Data for KeyValueDatabase {
}))
}
fn is_disabled(&self, room_id: &RoomId) -> Result<bool> {
pub(super) fn is_disabled(&self, room_id: &RoomId) -> Result<bool> {
Ok(self.disabledroomids.get(room_id.as_bytes())?.is_some())
}
fn disable_room(&self, room_id: &RoomId, disabled: bool) -> Result<()> {
pub(super) fn disable_room(&self, room_id: &RoomId, disabled: bool) -> Result<()> {
if disabled {
self.disabledroomids.insert(room_id.as_bytes(), &[])?;
} else {
@ -53,9 +62,11 @@ impl Data for KeyValueDatabase {
Ok(())
}
fn is_banned(&self, room_id: &RoomId) -> Result<bool> { Ok(self.bannedroomids.get(room_id.as_bytes())?.is_some()) }
pub(super) fn is_banned(&self, room_id: &RoomId) -> Result<bool> {
Ok(self.bannedroomids.get(room_id.as_bytes())?.is_some())
}
fn ban_room(&self, room_id: &RoomId, banned: bool) -> Result<()> {
pub(super) fn ban_room(&self, room_id: &RoomId, banned: bool) -> Result<()> {
if banned {
self.bannedroomids.insert(room_id.as_bytes(), &[])?;
} else {
@ -65,7 +76,7 @@ impl Data for KeyValueDatabase {
Ok(())
}
fn list_banned_rooms<'a>(&'a self) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a> {
pub(super) fn list_banned_rooms<'a>(&'a self) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a> {
Box::new(self.bannedroomids.iter().map(
|(room_id_bytes, _ /* non-banned rooms should not be in this table */)| {
let room_id = utils::string_from_bytes(&room_id_bytes)

View file

@ -1,3 +1,6 @@
use conduit::Server;
use database::KeyValueDatabase;
mod data;
use std::sync::Arc;
@ -8,10 +11,16 @@ use ruma::{OwnedRoomId, RoomId};
use crate::Result;
pub struct Service {
pub db: Arc<dyn Data>,
pub db: Data,
}
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<KeyValueDatabase>) -> Result<Self> {
Ok(Self {
db: Data::new(db),
})
}
/// Checks if a room exists.
#[tracing::instrument(skip(self))]
pub fn exists(&self, room_id: &RoomId) -> Result<bool> { self.db.exists(room_id) }

View file

@ -1,15 +1,22 @@
use std::sync::Arc;
use database::KvTree;
use ruma::{CanonicalJsonObject, EventId};
use crate::{Error, KeyValueDatabase, PduEvent, Result};
pub trait Data: Send + Sync {
fn get_outlier_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>>;
fn get_outlier_pdu(&self, event_id: &EventId) -> Result<Option<PduEvent>>;
fn add_pdu_outlier(&self, event_id: &EventId, pdu: &CanonicalJsonObject) -> Result<()>;
pub struct Data {
eventid_outlierpdu: Arc<dyn KvTree>,
}
impl Data for KeyValueDatabase {
fn get_outlier_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>> {
impl Data {
pub(super) fn new(db: &Arc<KeyValueDatabase>) -> Self {
Self {
eventid_outlierpdu: db.eventid_outlierpdu.clone(),
}
}
pub(super) fn get_outlier_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>> {
self.eventid_outlierpdu
.get(event_id.as_bytes())?
.map_or(Ok(None), |pdu| {
@ -17,7 +24,7 @@ impl Data for KeyValueDatabase {
})
}
fn get_outlier_pdu(&self, event_id: &EventId) -> Result<Option<PduEvent>> {
pub(super) fn get_outlier_pdu(&self, event_id: &EventId) -> Result<Option<PduEvent>> {
self.eventid_outlierpdu
.get(event_id.as_bytes())?
.map_or(Ok(None), |pdu| {
@ -25,7 +32,7 @@ impl Data for KeyValueDatabase {
})
}
fn add_pdu_outlier(&self, event_id: &EventId, pdu: &CanonicalJsonObject) -> Result<()> {
pub(super) fn add_pdu_outlier(&self, event_id: &EventId, pdu: &CanonicalJsonObject) -> Result<()> {
self.eventid_outlierpdu.insert(
event_id.as_bytes(),
&serde_json::to_vec(&pdu).expect("CanonicalJsonObject is valid"),

View file

@ -1,3 +1,6 @@
use conduit::Server;
use database::KeyValueDatabase;
mod data;
use std::sync::Arc;
@ -8,10 +11,16 @@ use ruma::{CanonicalJsonObject, EventId};
use crate::{PduEvent, Result};
pub struct Service {
pub db: Arc<dyn Data>,
pub db: Data,
}
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<KeyValueDatabase>) -> Result<Self> {
Ok(Self {
db: Data::new(db),
})
}
/// Returns the pdu from the outlier tree.
pub fn get_outlier_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>> {
self.db.get_outlier_pdu_json(event_id)

View file

@ -1,30 +1,33 @@
use std::{mem::size_of, sync::Arc};
use database::KvTree;
use ruma::{EventId, RoomId, UserId};
use crate::{services, utils, Error, KeyValueDatabase, PduCount, PduEvent, Result};
pub trait Data: Send + Sync {
fn add_relation(&self, from: u64, to: u64) -> Result<()>;
#[allow(clippy::type_complexity)]
fn relations_until<'a>(
&'a self, user_id: &'a UserId, room_id: u64, target: u64, until: PduCount,
) -> Result<Box<dyn Iterator<Item = Result<(PduCount, PduEvent)>> + 'a>>;
fn mark_as_referenced(&self, room_id: &RoomId, event_ids: &[Arc<EventId>]) -> Result<()>;
fn is_event_referenced(&self, room_id: &RoomId, event_id: &EventId) -> Result<bool>;
fn mark_event_soft_failed(&self, event_id: &EventId) -> Result<()>;
fn is_event_soft_failed(&self, event_id: &EventId) -> Result<bool>;
pub(super) struct Data {
tofrom_relation: Arc<dyn KvTree>,
referencedevents: Arc<dyn KvTree>,
softfailedeventids: Arc<dyn KvTree>,
}
impl Data for KeyValueDatabase {
fn add_relation(&self, from: u64, to: u64) -> Result<()> {
impl Data {
pub(super) fn new(db: &Arc<KeyValueDatabase>) -> Self {
Self {
tofrom_relation: db.tofrom_relation.clone(),
referencedevents: db.referencedevents.clone(),
softfailedeventids: db.softfailedeventids.clone(),
}
}
pub(super) fn add_relation(&self, from: u64, to: u64) -> Result<()> {
let mut key = to.to_be_bytes().to_vec();
key.extend_from_slice(&from.to_be_bytes());
self.tofrom_relation.insert(&key, &[])?;
Ok(())
}
fn relations_until<'a>(
pub(super) fn relations_until<'a>(
&'a self, user_id: &'a UserId, shortroomid: u64, target: u64, until: PduCount,
) -> Result<Box<dyn Iterator<Item = Result<(PduCount, PduEvent)>> + 'a>> {
let prefix = target.to_be_bytes().to_vec();
@ -63,7 +66,7 @@ impl Data for KeyValueDatabase {
))
}
fn mark_as_referenced(&self, room_id: &RoomId, event_ids: &[Arc<EventId>]) -> Result<()> {
pub(super) fn mark_as_referenced(&self, room_id: &RoomId, event_ids: &[Arc<EventId>]) -> Result<()> {
for prev in event_ids {
let mut key = room_id.as_bytes().to_vec();
key.extend_from_slice(prev.as_bytes());
@ -73,17 +76,17 @@ impl Data for KeyValueDatabase {
Ok(())
}
fn is_event_referenced(&self, room_id: &RoomId, event_id: &EventId) -> Result<bool> {
pub(super) fn is_event_referenced(&self, room_id: &RoomId, event_id: &EventId) -> Result<bool> {
let mut key = room_id.as_bytes().to_vec();
key.extend_from_slice(event_id.as_bytes());
Ok(self.referencedevents.get(&key)?.is_some())
}
fn mark_event_soft_failed(&self, event_id: &EventId) -> Result<()> {
pub(super) fn mark_event_soft_failed(&self, event_id: &EventId) -> Result<()> {
self.softfailedeventids.insert(event_id.as_bytes(), &[])
}
fn is_event_soft_failed(&self, event_id: &EventId) -> Result<bool> {
pub(super) fn is_event_soft_failed(&self, event_id: &EventId) -> Result<bool> {
self.softfailedeventids
.get(event_id.as_bytes())
.map(|o| o.is_some())

View file

@ -1,3 +1,6 @@
use conduit::Server;
use database::KeyValueDatabase;
mod data;
use std::sync::Arc;
@ -13,7 +16,7 @@ use serde::Deserialize;
use crate::{services, PduCount, PduEvent, Result};
pub struct Service {
pub db: Arc<dyn Data>,
db: Data,
}
#[derive(Clone, Debug, Deserialize)]
@ -27,6 +30,12 @@ struct ExtractRelatesToEventId {
}
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<KeyValueDatabase>) -> Result<Self> {
Ok(Self {
db: Data::new(db),
})
}
#[tracing::instrument(skip(self, from, to))]
pub fn add_relation(&self, from: PduCount, to: PduCount) -> Result<()> {
match (from, to) {

View file

@ -1,5 +1,6 @@
use std::mem::size_of;
use std::{mem::size_of, sync::Arc};
use database::KvTree;
use ruma::{
events::{receipt::ReceiptEvent, AnySyncEphemeralRoomEvent},
serde::Raw,
@ -11,32 +12,22 @@ use crate::{services, utils, Error, KeyValueDatabase, Result};
type AnySyncEphemeralRoomEventIter<'a> =
Box<dyn Iterator<Item = Result<(OwnedUserId, u64, Raw<AnySyncEphemeralRoomEvent>)>> + 'a>;
pub trait Data: Send + Sync {
/// Replaces the previous read receipt.
fn readreceipt_update(&self, user_id: &UserId, room_id: &RoomId, event: ReceiptEvent) -> Result<()>;
/// Returns an iterator over the most recent read_receipts in a room that
/// happened after the event with id `since`.
fn readreceipts_since(&self, room_id: &RoomId, since: u64) -> AnySyncEphemeralRoomEventIter<'_>;
/// Sets a private read marker at `count`.
fn private_read_set(&self, room_id: &RoomId, user_id: &UserId, count: u64) -> Result<()>;
/// Returns the private read marker.
///
/// TODO: use this?
#[allow(dead_code)]
fn private_read_get(&self, room_id: &RoomId, user_id: &UserId) -> Result<Option<u64>>;
/// Returns the count of the last typing update in this room.
///
/// TODO: use this?
#[allow(dead_code)]
fn last_privateread_update(&self, user_id: &UserId, room_id: &RoomId) -> Result<u64>;
pub(super) struct Data {
roomuserid_privateread: Arc<dyn KvTree>,
roomuserid_lastprivatereadupdate: Arc<dyn KvTree>,
readreceiptid_readreceipt: Arc<dyn KvTree>,
}
impl Data for KeyValueDatabase {
fn readreceipt_update(&self, user_id: &UserId, room_id: &RoomId, event: ReceiptEvent) -> Result<()> {
impl Data {
pub(super) fn new(db: &Arc<KeyValueDatabase>) -> Self {
Self {
roomuserid_privateread: db.roomuserid_privateread.clone(),
roomuserid_lastprivatereadupdate: db.roomuserid_lastprivatereadupdate.clone(),
readreceiptid_readreceipt: db.readreceiptid_readreceipt.clone(),
}
}
pub(super) fn readreceipt_update(&self, user_id: &UserId, room_id: &RoomId, event: ReceiptEvent) -> Result<()> {
let mut prefix = room_id.as_bytes().to_vec();
prefix.push(0xFF);
@ -71,9 +62,7 @@ impl Data for KeyValueDatabase {
Ok(())
}
fn readreceipts_since<'a>(
&'a self, room_id: &RoomId, since: u64,
) -> Box<dyn Iterator<Item = Result<(OwnedUserId, u64, Raw<AnySyncEphemeralRoomEvent>)>> + 'a> {
pub(super) fn readreceipts_since<'a>(&'a self, room_id: &RoomId, since: u64) -> AnySyncEphemeralRoomEventIter<'a> {
let mut prefix = room_id.as_bytes().to_vec();
prefix.push(0xFF);
let prefix2 = prefix.clone();
@ -107,7 +96,7 @@ impl Data for KeyValueDatabase {
)
}
fn private_read_set(&self, room_id: &RoomId, user_id: &UserId, count: u64) -> Result<()> {
pub(super) fn private_read_set(&self, room_id: &RoomId, user_id: &UserId, count: u64) -> Result<()> {
let mut key = room_id.as_bytes().to_vec();
key.push(0xFF);
key.extend_from_slice(user_id.as_bytes());
@ -119,7 +108,7 @@ impl Data for KeyValueDatabase {
.insert(&key, &services().globals.next_count()?.to_be_bytes())
}
fn private_read_get(&self, room_id: &RoomId, user_id: &UserId) -> Result<Option<u64>> {
pub(super) fn private_read_get(&self, room_id: &RoomId, user_id: &UserId) -> Result<Option<u64>> {
let mut key = room_id.as_bytes().to_vec();
key.push(0xFF);
key.extend_from_slice(user_id.as_bytes());
@ -133,7 +122,7 @@ impl Data for KeyValueDatabase {
})
}
fn last_privateread_update(&self, user_id: &UserId, room_id: &RoomId) -> Result<u64> {
pub(super) fn last_privateread_update(&self, user_id: &UserId, room_id: &RoomId) -> Result<u64> {
let mut key = room_id.as_bytes().to_vec();
key.push(0xFF);
key.extend_from_slice(user_id.as_bytes());

View file

@ -1,3 +1,6 @@
use conduit::Server;
use database::KeyValueDatabase;
mod data;
use std::sync::Arc;
@ -8,10 +11,16 @@ use ruma::{events::receipt::ReceiptEvent, serde::Raw, OwnedUserId, RoomId, UserI
use crate::{services, Result};
pub struct Service {
pub db: Arc<dyn Data>,
db: Data,
}
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<KeyValueDatabase>) -> Result<Self> {
Ok(Self {
db: Data::new(db),
})
}
/// Replaces the previous read receipt.
pub fn readreceipt_update(&self, user_id: &UserId, room_id: &RoomId, event: ReceiptEvent) -> Result<()> {
self.db.readreceipt_update(user_id, room_id, event)?;

View file

@ -1,30 +1,24 @@
use std::sync::Arc;
use database::KvTree;
use ruma::RoomId;
use crate::{services, utils, KeyValueDatabase, Result};
type SearchPdusResult<'a> = Result<Option<(Box<dyn Iterator<Item = Vec<u8>> + 'a>, Vec<String>)>>;
pub trait Data: Send + Sync {
fn index_pdu(&self, shortroomid: u64, pdu_id: &[u8], message_body: &str) -> Result<()>;
fn deindex_pdu(&self, shortroomid: u64, pdu_id: &[u8], message_body: &str) -> Result<()>;
fn search_pdus<'a>(&'a self, room_id: &RoomId, search_string: &str) -> SearchPdusResult<'a>;
pub struct Data {
tokenids: Arc<dyn KvTree>,
}
/// Splits a string into tokens used as keys in the search inverted index
///
/// This may be used to tokenize both message bodies (for indexing) or search
/// queries (for querying).
fn tokenize(body: &str) -> impl Iterator<Item = String> + '_ {
body.split_terminator(|c: char| !c.is_alphanumeric())
.filter(|s| !s.is_empty())
.filter(|word| word.len() <= 50)
.map(str::to_lowercase)
}
impl Data {
pub(super) fn new(db: &Arc<KeyValueDatabase>) -> Self {
Self {
tokenids: db.tokenids.clone(),
}
}
impl Data for KeyValueDatabase {
fn index_pdu(&self, shortroomid: u64, pdu_id: &[u8], message_body: &str) -> Result<()> {
pub(super) fn index_pdu(&self, shortroomid: u64, pdu_id: &[u8], message_body: &str) -> Result<()> {
let mut batch = tokenize(message_body).map(|word| {
let mut key = shortroomid.to_be_bytes().to_vec();
key.extend_from_slice(word.as_bytes());
@ -36,7 +30,7 @@ impl Data for KeyValueDatabase {
self.tokenids.insert_batch(&mut batch)
}
fn deindex_pdu(&self, shortroomid: u64, pdu_id: &[u8], message_body: &str) -> Result<()> {
pub(super) fn deindex_pdu(&self, shortroomid: u64, pdu_id: &[u8], message_body: &str) -> Result<()> {
let batch = tokenize(message_body).map(|word| {
let mut key = shortroomid.to_be_bytes().to_vec();
key.extend_from_slice(word.as_bytes());
@ -52,7 +46,7 @@ impl Data for KeyValueDatabase {
Ok(())
}
fn search_pdus<'a>(&'a self, room_id: &RoomId, search_string: &str) -> SearchPdusResult<'a> {
pub(super) fn search_pdus<'a>(&'a self, room_id: &RoomId, search_string: &str) -> SearchPdusResult<'a> {
let prefix = services()
.rooms
.short
@ -88,3 +82,14 @@ impl Data for KeyValueDatabase {
Ok(Some((Box::new(common_elements), words)))
}
}
/// Splits a string into tokens used as keys in the search inverted index
///
/// This may be used to tokenize both message bodies (for indexing) or search
/// queries (for querying).
fn tokenize(body: &str) -> impl Iterator<Item = String> + '_ {
body.split_terminator(|c: char| !c.is_alphanumeric())
.filter(|s| !s.is_empty())
.filter(|word| word.len() <= 50)
.map(str::to_lowercase)
}

View file

@ -1,3 +1,6 @@
use conduit::Server;
use database::KeyValueDatabase;
mod data;
use std::sync::Arc;
@ -8,10 +11,16 @@ use ruma::RoomId;
use crate::Result;
pub struct Service {
pub db: Arc<dyn Data>,
pub db: Data,
}
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<KeyValueDatabase>) -> Result<Self> {
Ok(Self {
db: Data::new(db),
})
}
#[tracing::instrument(skip(self))]
pub fn index_pdu(&self, shortroomid: u64, pdu_id: &[u8], message_body: &str) -> Result<()> {
self.db.index_pdu(shortroomid, pdu_id, message_body)

View file

@ -1,33 +1,33 @@
use std::sync::Arc;
use conduit::warn;
use database::{KeyValueDatabase, KvTree};
use ruma::{events::StateEventType, EventId, RoomId};
use tracing::warn;
use crate::{services, utils, Error, KeyValueDatabase, Result};
use crate::{services, utils, Error, Result};
pub trait Data: Send + Sync {
fn get_or_create_shorteventid(&self, event_id: &EventId) -> Result<u64>;
fn multi_get_or_create_shorteventid(&self, event_id: &[&EventId]) -> Result<Vec<u64>>;
fn get_shortstatekey(&self, event_type: &StateEventType, state_key: &str) -> Result<Option<u64>>;
fn get_or_create_shortstatekey(&self, event_type: &StateEventType, state_key: &str) -> Result<u64>;
fn get_eventid_from_short(&self, shorteventid: u64) -> Result<Arc<EventId>>;
fn get_statekey_from_short(&self, shortstatekey: u64) -> Result<(StateEventType, String)>;
/// Returns (shortstatehash, already_existed)
fn get_or_create_shortstatehash(&self, state_hash: &[u8]) -> Result<(u64, bool)>;
fn get_shortroomid(&self, room_id: &RoomId) -> Result<Option<u64>>;
fn get_or_create_shortroomid(&self, room_id: &RoomId) -> Result<u64>;
pub(super) struct Data {
eventid_shorteventid: Arc<dyn KvTree>,
shorteventid_eventid: Arc<dyn KvTree>,
statekey_shortstatekey: Arc<dyn KvTree>,
shortstatekey_statekey: Arc<dyn KvTree>,
roomid_shortroomid: Arc<dyn KvTree>,
statehash_shortstatehash: Arc<dyn KvTree>,
}
impl Data for KeyValueDatabase {
fn get_or_create_shorteventid(&self, event_id: &EventId) -> Result<u64> {
impl Data {
pub(super) fn new(db: &Arc<KeyValueDatabase>) -> Self {
Self {
eventid_shorteventid: db.eventid_shorteventid.clone(),
shorteventid_eventid: db.shorteventid_eventid.clone(),
statekey_shortstatekey: db.statekey_shortstatekey.clone(),
shortstatekey_statekey: db.shortstatekey_statekey.clone(),
roomid_shortroomid: db.roomid_shortroomid.clone(),
statehash_shortstatehash: db.statehash_shortstatehash.clone(),
}
}
pub(super) fn get_or_create_shorteventid(&self, event_id: &EventId) -> Result<u64> {
let short = if let Some(shorteventid) = self.eventid_shorteventid.get(event_id.as_bytes())? {
utils::u64_from_bytes(&shorteventid).map_err(|_| Error::bad_database("Invalid shorteventid in db."))?
} else {
@ -42,7 +42,7 @@ impl Data for KeyValueDatabase {
Ok(short)
}
fn multi_get_or_create_shorteventid(&self, event_ids: &[&EventId]) -> Result<Vec<u64>> {
pub(super) fn multi_get_or_create_shorteventid(&self, event_ids: &[&EventId]) -> Result<Vec<u64>> {
let mut ret: Vec<u64> = Vec::with_capacity(event_ids.len());
let keys = event_ids
.iter()
@ -74,7 +74,7 @@ impl Data for KeyValueDatabase {
Ok(ret)
}
fn get_shortstatekey(&self, event_type: &StateEventType, state_key: &str) -> Result<Option<u64>> {
pub(super) fn get_shortstatekey(&self, event_type: &StateEventType, state_key: &str) -> Result<Option<u64>> {
let mut statekey_vec = event_type.to_string().as_bytes().to_vec();
statekey_vec.push(0xFF);
statekey_vec.extend_from_slice(state_key.as_bytes());
@ -90,7 +90,7 @@ impl Data for KeyValueDatabase {
Ok(short)
}
fn get_or_create_shortstatekey(&self, event_type: &StateEventType, state_key: &str) -> Result<u64> {
pub(super) fn get_or_create_shortstatekey(&self, event_type: &StateEventType, state_key: &str) -> Result<u64> {
let mut statekey_vec = event_type.to_string().as_bytes().to_vec();
statekey_vec.push(0xFF);
statekey_vec.extend_from_slice(state_key.as_bytes());
@ -109,7 +109,7 @@ impl Data for KeyValueDatabase {
Ok(short)
}
fn get_eventid_from_short(&self, shorteventid: u64) -> Result<Arc<EventId>> {
pub(super) fn get_eventid_from_short(&self, shorteventid: u64) -> Result<Arc<EventId>> {
let bytes = self
.shorteventid_eventid
.get(&shorteventid.to_be_bytes())?
@ -124,7 +124,7 @@ impl Data for KeyValueDatabase {
Ok(event_id)
}
fn get_statekey_from_short(&self, shortstatekey: u64) -> Result<(StateEventType, String)> {
pub(super) fn get_statekey_from_short(&self, shortstatekey: u64) -> Result<(StateEventType, String)> {
let bytes = self
.shortstatekey_statekey
.get(&shortstatekey.to_be_bytes())?
@ -150,7 +150,7 @@ impl Data for KeyValueDatabase {
}
/// Returns (shortstatehash, already_existed)
fn get_or_create_shortstatehash(&self, state_hash: &[u8]) -> Result<(u64, bool)> {
pub(super) fn get_or_create_shortstatehash(&self, state_hash: &[u8]) -> Result<(u64, bool)> {
Ok(if let Some(shortstatehash) = self.statehash_shortstatehash.get(state_hash)? {
(
utils::u64_from_bytes(&shortstatehash)
@ -165,14 +165,14 @@ impl Data for KeyValueDatabase {
})
}
fn get_shortroomid(&self, room_id: &RoomId) -> Result<Option<u64>> {
pub(super) fn get_shortroomid(&self, room_id: &RoomId) -> Result<Option<u64>> {
self.roomid_shortroomid
.get(room_id.as_bytes())?
.map(|bytes| utils::u64_from_bytes(&bytes).map_err(|_| Error::bad_database("Invalid shortroomid in db.")))
.transpose()
}
fn get_or_create_shortroomid(&self, room_id: &RoomId) -> Result<u64> {
pub(super) fn get_or_create_shortroomid(&self, room_id: &RoomId) -> Result<u64> {
Ok(if let Some(short) = self.roomid_shortroomid.get(room_id.as_bytes())? {
utils::u64_from_bytes(&short).map_err(|_| Error::bad_database("Invalid shortroomid in db."))?
} else {

View file

@ -1,3 +1,6 @@
use conduit::Server;
use database::KeyValueDatabase;
mod data;
use std::sync::Arc;
@ -7,10 +10,16 @@ use ruma::{events::StateEventType, EventId, RoomId};
use crate::Result;
pub struct Service {
pub db: Arc<dyn Data>,
db: Data,
}
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<KeyValueDatabase>) -> Result<Self> {
Ok(Self {
db: Data::new(db),
})
}
pub fn get_or_create_shorteventid(&self, event_id: &EventId) -> Result<u64> {
self.db.get_or_create_shorteventid(event_id)
}

View file

@ -1,8 +1,11 @@
use std::{
fmt::{Display, Formatter},
str::FromStr,
sync::Arc,
};
use conduit::Server;
use database::KeyValueDatabase;
use lru_cache::LruCache;
use ruma::{
api::{
@ -330,6 +333,16 @@ impl From<CachedSpaceHierarchySummary> for SpaceHierarchyRoomsChunk {
}
impl Service {
pub fn build(server: &Arc<Server>, _db: &Arc<KeyValueDatabase>) -> Result<Self> {
let config = &server.config;
Ok(Self {
roomid_spacehierarchy_cache: Mutex::new(LruCache::new(
(f64::from(config.roomid_spacehierarchy_cache_capacity) * config.conduit_cache_capacity_modifier)
as usize,
)),
})
}
///Gets the response for the space hierarchy over federation request
///
///Panics if the room does not exist, so a check if the room exists should

View file

@ -1,39 +1,27 @@
use std::{collections::HashSet, sync::Arc};
use conduit::utils::mutex_map;
use database::KvTree;
use ruma::{EventId, OwnedEventId, RoomId};
use crate::{utils, Error, KeyValueDatabase, Result};
pub trait Data: Send + Sync {
/// Returns the last state hash key added to the db for the given room.
fn get_room_shortstatehash(&self, room_id: &RoomId) -> Result<Option<u64>>;
/// Set the state hash to a new version, but does not update `state_cache`.
fn set_room_state(
&self,
room_id: &RoomId,
new_shortstatehash: u64,
_mutex_lock: &mutex_map::Guard<()>, // Take mutex guard to make sure users get the room state mutex
) -> Result<()>;
/// Associates a state with an event.
fn set_event_state(&self, shorteventid: u64, shortstatehash: u64) -> Result<()>;
/// Returns all events we would send as the `prev_events` of the next event.
fn get_forward_extremities(&self, room_id: &RoomId) -> Result<HashSet<Arc<EventId>>>;
/// Replace the forward extremities of the room.
fn set_forward_extremities(
&self,
room_id: &RoomId,
event_ids: Vec<OwnedEventId>,
_mutex_lock: &mutex_map::Guard<()>, // Take mutex guard to make sure users get the room state mutex
) -> Result<()>;
pub struct Data {
shorteventid_shortstatehash: Arc<dyn KvTree>,
roomid_pduleaves: Arc<dyn KvTree>,
roomid_shortstatehash: Arc<dyn KvTree>,
}
impl Data for KeyValueDatabase {
fn get_room_shortstatehash(&self, room_id: &RoomId) -> Result<Option<u64>> {
impl Data {
pub(super) fn new(db: &Arc<KeyValueDatabase>) -> Self {
Self {
shorteventid_shortstatehash: db.shorteventid_shortstatehash.clone(),
roomid_pduleaves: db.roomid_pduleaves.clone(),
roomid_shortstatehash: db.roomid_shortstatehash.clone(),
}
}
pub(super) fn get_room_shortstatehash(&self, room_id: &RoomId) -> Result<Option<u64>> {
self.roomid_shortstatehash
.get(room_id.as_bytes())?
.map_or(Ok(None), |bytes| {
@ -43,7 +31,7 @@ impl Data for KeyValueDatabase {
})
}
fn set_room_state(
pub(super) fn set_room_state(
&self,
room_id: &RoomId,
new_shortstatehash: u64,
@ -54,13 +42,13 @@ impl Data for KeyValueDatabase {
Ok(())
}
fn set_event_state(&self, shorteventid: u64, shortstatehash: u64) -> Result<()> {
pub(super) fn set_event_state(&self, shorteventid: u64, shortstatehash: u64) -> Result<()> {
self.shorteventid_shortstatehash
.insert(&shorteventid.to_be_bytes(), &shortstatehash.to_be_bytes())?;
Ok(())
}
fn get_forward_extremities(&self, room_id: &RoomId) -> Result<HashSet<Arc<EventId>>> {
pub(super) fn get_forward_extremities(&self, room_id: &RoomId) -> Result<HashSet<Arc<EventId>>> {
let mut prefix = room_id.as_bytes().to_vec();
prefix.push(0xFF);
@ -76,7 +64,7 @@ impl Data for KeyValueDatabase {
.collect()
}
fn set_forward_extremities(
pub(super) fn set_forward_extremities(
&self,
room_id: &RoomId,
event_ids: Vec<OwnedEventId>,

View file

@ -1,3 +1,6 @@
use conduit::Server;
use database::KeyValueDatabase;
mod data;
use std::{
collections::{HashMap, HashSet},
@ -22,10 +25,16 @@ use super::state_compressor::CompressedStateEvent;
use crate::{services, utils::calculate_hash, Error, PduEvent, Result};
pub struct Service {
pub db: Arc<dyn Data>,
pub db: Data,
}
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<KeyValueDatabase>) -> Result<Self> {
Ok(Self {
db: Data::new(db),
})
}
/// Set the room to the given statehash and update caches.
pub async fn force_state(
&self,

View file

@ -1,56 +1,25 @@
use std::{collections::HashMap, sync::Arc};
use async_trait::async_trait;
use database::KvTree;
use ruma::{events::StateEventType, EventId, RoomId};
use crate::{services, utils, Error, KeyValueDatabase, PduEvent, Result};
#[async_trait]
pub trait Data: Send + Sync {
/// Builds a StateMap by iterating over all keys that start
/// with state_hash, this gives the full state for the given state_hash.
#[allow(unused_qualifications)] // async traits
async fn state_full_ids(&self, shortstatehash: u64) -> Result<HashMap<u64, Arc<EventId>>>;
#[allow(unused_qualifications)] // async traits
async fn state_full(&self, shortstatehash: u64) -> Result<HashMap<(StateEventType, String), Arc<PduEvent>>>;
/// Returns a single PDU from `room_id` with key (`event_type`,
/// `state_key`).
fn state_get_id(
&self, shortstatehash: u64, event_type: &StateEventType, state_key: &str,
) -> Result<Option<Arc<EventId>>>;
/// Returns a single PDU from `room_id` with key (`event_type`,
/// `state_key`).
fn state_get(
&self, shortstatehash: u64, event_type: &StateEventType, state_key: &str,
) -> Result<Option<Arc<PduEvent>>>;
/// Returns the state hash for this pdu.
fn pdu_shortstatehash(&self, event_id: &EventId) -> Result<Option<u64>>;
/// Returns the full room state.
#[allow(unused_qualifications)] // async traits
async fn room_state_full(&self, room_id: &RoomId) -> Result<HashMap<(StateEventType, String), Arc<PduEvent>>>;
/// Returns a single PDU from `room_id` with key (`event_type`,
/// `state_key`).
fn room_state_get_id(
&self, room_id: &RoomId, event_type: &StateEventType, state_key: &str,
) -> Result<Option<Arc<EventId>>>;
/// Returns a single PDU from `room_id` with key (`event_type`,
/// `state_key`).
fn room_state_get(
&self, room_id: &RoomId, event_type: &StateEventType, state_key: &str,
) -> Result<Option<Arc<PduEvent>>>;
pub struct Data {
eventid_shorteventid: Arc<dyn KvTree>,
shorteventid_shortstatehash: Arc<dyn KvTree>,
}
#[async_trait]
impl Data for KeyValueDatabase {
impl Data {
pub(super) fn new(db: &Arc<KeyValueDatabase>) -> Self {
Self {
eventid_shorteventid: db.eventid_shorteventid.clone(),
shorteventid_shortstatehash: db.shorteventid_shortstatehash.clone(),
}
}
#[allow(unused_qualifications)] // async traits
async fn state_full_ids(&self, shortstatehash: u64) -> Result<HashMap<u64, Arc<EventId>>> {
pub(super) async fn state_full_ids(&self, shortstatehash: u64) -> Result<HashMap<u64, Arc<EventId>>> {
let full_state = services()
.rooms
.state_compressor
@ -76,7 +45,9 @@ impl Data for KeyValueDatabase {
}
#[allow(unused_qualifications)] // async traits
async fn state_full(&self, shortstatehash: u64) -> Result<HashMap<(StateEventType, String), Arc<PduEvent>>> {
pub(super) async fn state_full(
&self, shortstatehash: u64,
) -> Result<HashMap<(StateEventType, String), Arc<PduEvent>>> {
let full_state = services()
.rooms
.state_compressor
@ -116,7 +87,8 @@ impl Data for KeyValueDatabase {
/// Returns a single PDU from `room_id` with key (`event_type`,
/// `state_key`).
fn state_get_id(
#[allow(clippy::unused_self)]
pub(super) fn state_get_id(
&self, shortstatehash: u64, event_type: &StateEventType, state_key: &str,
) -> Result<Option<Arc<EventId>>> {
let Some(shortstatekey) = services()
@ -148,7 +120,7 @@ impl Data for KeyValueDatabase {
/// Returns a single PDU from `room_id` with key (`event_type`,
/// `state_key`).
fn state_get(
pub(super) fn state_get(
&self, shortstatehash: u64, event_type: &StateEventType, state_key: &str,
) -> Result<Option<Arc<PduEvent>>> {
self.state_get_id(shortstatehash, event_type, state_key)?
@ -156,7 +128,7 @@ impl Data for KeyValueDatabase {
}
/// Returns the state hash for this pdu.
fn pdu_shortstatehash(&self, event_id: &EventId) -> Result<Option<u64>> {
pub(super) fn pdu_shortstatehash(&self, event_id: &EventId) -> Result<Option<u64>> {
self.eventid_shorteventid
.get(event_id.as_bytes())?
.map_or(Ok(None), |shorteventid| {
@ -173,7 +145,9 @@ impl Data for KeyValueDatabase {
/// Returns the full room state.
#[allow(unused_qualifications)] // async traits
async fn room_state_full(&self, room_id: &RoomId) -> Result<HashMap<(StateEventType, String), Arc<PduEvent>>> {
pub(super) async fn room_state_full(
&self, room_id: &RoomId,
) -> Result<HashMap<(StateEventType, String), Arc<PduEvent>>> {
if let Some(current_shortstatehash) = services().rooms.state.get_room_shortstatehash(room_id)? {
self.state_full(current_shortstatehash).await
} else {
@ -183,7 +157,7 @@ impl Data for KeyValueDatabase {
/// Returns a single PDU from `room_id` with key (`event_type`,
/// `state_key`).
fn room_state_get_id(
pub(super) fn room_state_get_id(
&self, room_id: &RoomId, event_type: &StateEventType, state_key: &str,
) -> Result<Option<Arc<EventId>>> {
if let Some(current_shortstatehash) = services().rooms.state.get_room_shortstatehash(room_id)? {
@ -195,7 +169,7 @@ impl Data for KeyValueDatabase {
/// Returns a single PDU from `room_id` with key (`event_type`,
/// `state_key`).
fn room_state_get(
pub(super) fn room_state_get(
&self, room_id: &RoomId, event_type: &StateEventType, state_key: &str,
) -> Result<Option<Arc<PduEvent>>> {
if let Some(current_shortstatehash) = services().rooms.state.get_room_shortstatehash(room_id)? {

View file

@ -1,3 +1,8 @@
use std::sync::Mutex as StdMutex;
use conduit::Server;
use database::KeyValueDatabase;
mod data;
use std::{
collections::HashMap,
@ -29,12 +34,25 @@ use tracing::{error, warn};
use crate::{service::pdu::PduBuilder, services, Error, PduEvent, Result};
pub struct Service {
pub db: Arc<dyn Data>,
pub db: Data,
pub server_visibility_cache: Mutex<LruCache<(OwnedServerName, u64), bool>>,
pub user_visibility_cache: Mutex<LruCache<(OwnedUserId, u64), bool>>,
}
impl Service {
pub fn build(server: &Arc<Server>, db: &Arc<KeyValueDatabase>) -> Result<Self> {
let config = &server.config;
Ok(Self {
db: Data::new(db),
server_visibility_cache: StdMutex::new(LruCache::new(
(f64::from(config.server_visibility_cache_capacity) * config.conduit_cache_capacity_modifier) as usize,
)),
user_visibility_cache: StdMutex::new(LruCache::new(
(f64::from(config.user_visibility_cache_capacity) * config.conduit_cache_capacity_modifier) as usize,
)),
})
}
/// Builds a StateMap by iterating over all keys that start
/// with state_hash, this gives the full state for the given state_hash.
#[tracing::instrument(skip(self))]

View file

@ -17,101 +17,53 @@ use crate::{
type StrippedStateEventIter<'a> = Box<dyn Iterator<Item = Result<(OwnedRoomId, Vec<Raw<AnyStrippedStateEvent>>)>> + 'a>;
type AnySyncStateEventIter<'a> = Box<dyn Iterator<Item = Result<(OwnedRoomId, Vec<Raw<AnySyncStateEvent>>)>> + 'a>;
pub trait Data: Send + Sync {
fn mark_as_once_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<()>;
fn mark_as_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<()>;
fn mark_as_invited(
&self, user_id: &UserId, room_id: &RoomId, last_state: Option<Vec<Raw<AnyStrippedStateEvent>>>,
invite_via: Option<Vec<OwnedServerName>>,
) -> Result<()>;
fn mark_as_left(&self, user_id: &UserId, room_id: &RoomId) -> Result<()>;
use std::sync::Arc;
fn update_joined_count(&self, room_id: &RoomId) -> Result<()>;
use database::KvTree;
fn appservice_in_room(&self, room_id: &RoomId, appservice: &RegistrationInfo) -> Result<bool>;
/// Makes a user forget a room.
fn forget(&self, room_id: &RoomId, user_id: &UserId) -> Result<()>;
/// Returns an iterator of all servers participating in this room.
fn room_servers<'a>(&'a self, room_id: &RoomId) -> Box<dyn Iterator<Item = Result<OwnedServerName>> + 'a>;
fn server_in_room(&self, server: &ServerName, room_id: &RoomId) -> Result<bool>;
/// Returns an iterator of all rooms a server participates in (as far as we
/// know).
fn server_rooms<'a>(&'a self, server: &ServerName) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a>;
/// Returns an iterator of all joined members of a room.
fn room_members<'a>(&'a self, room_id: &RoomId) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a>;
/// Returns an iterator of all our local users
/// in the room, even if they're deactivated/guests
fn local_users_in_room<'a>(&'a self, room_id: &RoomId) -> Box<dyn Iterator<Item = OwnedUserId> + 'a>;
/// Returns an iterator of all our local joined users in a room who are
/// active (not deactivated, not guest)
fn active_local_users_in_room<'a>(&'a self, room_id: &RoomId) -> Box<dyn Iterator<Item = OwnedUserId> + 'a>;
fn room_joined_count(&self, room_id: &RoomId) -> Result<Option<u64>>;
fn room_invited_count(&self, room_id: &RoomId) -> Result<Option<u64>>;
/// Returns an iterator over all User IDs who ever joined a room.
///
/// TODO: use this?
#[allow(dead_code)]
fn room_useroncejoined<'a>(&'a self, room_id: &RoomId) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a>;
/// Returns an iterator over all invited members of a room.
fn room_members_invited<'a>(&'a self, room_id: &RoomId) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a>;
fn get_invite_count(&self, room_id: &RoomId, user_id: &UserId) -> Result<Option<u64>>;
fn get_left_count(&self, room_id: &RoomId, user_id: &UserId) -> Result<Option<u64>>;
/// Returns an iterator over all rooms this user joined.
fn rooms_joined(&self, user_id: &UserId) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + '_>;
/// Returns an iterator over all rooms a user was invited to.
fn rooms_invited<'a>(&'a self, user_id: &UserId) -> StrippedStateEventIter<'a>;
fn invite_state(&self, user_id: &UserId, room_id: &RoomId) -> Result<Option<Vec<Raw<AnyStrippedStateEvent>>>>;
fn left_state(&self, user_id: &UserId, room_id: &RoomId) -> Result<Option<Vec<Raw<AnyStrippedStateEvent>>>>;
/// Returns an iterator over all rooms a user left.
fn rooms_left<'a>(&'a self, user_id: &UserId) -> AnySyncStateEventIter<'a>;
fn once_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<bool>;
fn is_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<bool>;
fn is_invited(&self, user_id: &UserId, room_id: &RoomId) -> Result<bool>;
fn is_left(&self, user_id: &UserId, room_id: &RoomId) -> Result<bool>;
/// Gets the servers to either accept or decline invites via for a given
/// room.
fn servers_invite_via<'a>(&'a self, room_id: &RoomId) -> Box<dyn Iterator<Item = Result<OwnedServerName>> + 'a>;
/// Add the given servers the list to accept or decline invites via for a
/// given room.
///
/// TODO: use this?
#[allow(dead_code)]
fn add_servers_invite_via(&self, room_id: &RoomId, servers: &[OwnedServerName]) -> Result<()>;
pub struct Data {
userroomid_joined: Arc<dyn KvTree>,
roomuserid_joined: Arc<dyn KvTree>,
userroomid_invitestate: Arc<dyn KvTree>,
roomuserid_invitecount: Arc<dyn KvTree>,
userroomid_leftstate: Arc<dyn KvTree>,
roomuserid_leftcount: Arc<dyn KvTree>,
roomid_inviteviaservers: Arc<dyn KvTree>,
roomuseroncejoinedids: Arc<dyn KvTree>,
roomid_joinedcount: Arc<dyn KvTree>,
roomid_invitedcount: Arc<dyn KvTree>,
roomserverids: Arc<dyn KvTree>,
serverroomids: Arc<dyn KvTree>,
db: Arc<KeyValueDatabase>,
}
impl Data for KeyValueDatabase {
fn mark_as_once_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
impl Data {
pub(super) fn new(db: &Arc<KeyValueDatabase>) -> Self {
Self {
userroomid_joined: db.userroomid_joined.clone(),
roomuserid_joined: db.roomuserid_joined.clone(),
userroomid_invitestate: db.userroomid_invitestate.clone(),
roomuserid_invitecount: db.roomuserid_invitecount.clone(),
userroomid_leftstate: db.userroomid_leftstate.clone(),
roomuserid_leftcount: db.roomuserid_leftcount.clone(),
roomid_inviteviaservers: db.roomid_inviteviaservers.clone(),
roomuseroncejoinedids: db.roomuseroncejoinedids.clone(),
roomid_joinedcount: db.roomid_joinedcount.clone(),
roomid_invitedcount: db.roomid_invitedcount.clone(),
roomserverids: db.roomserverids.clone(),
serverroomids: db.serverroomids.clone(),
db: db.clone(),
}
}
pub(super) fn mark_as_once_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
let mut userroom_id = user_id.as_bytes().to_vec();
userroom_id.push(0xFF);
userroom_id.extend_from_slice(room_id.as_bytes());
self.roomuseroncejoinedids.insert(&userroom_id, &[])
}
fn mark_as_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
pub(super) fn mark_as_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
let roomid = room_id.as_bytes().to_vec();
let mut roomuser_id = roomid.clone();
@ -134,7 +86,7 @@ impl Data for KeyValueDatabase {
Ok(())
}
fn mark_as_invited(
pub(super) fn mark_as_invited(
&self, user_id: &UserId, room_id: &RoomId, last_state: Option<Vec<Raw<AnyStrippedStateEvent>>>,
invite_via: Option<Vec<OwnedServerName>>,
) -> Result<()> {
@ -179,7 +131,7 @@ impl Data for KeyValueDatabase {
Ok(())
}
fn mark_as_left(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
pub(super) fn mark_as_left(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
let roomid = room_id.as_bytes().to_vec();
let mut roomuser_id = roomid.clone();
@ -206,7 +158,7 @@ impl Data for KeyValueDatabase {
Ok(())
}
fn update_joined_count(&self, room_id: &RoomId) -> Result<()> {
pub(super) fn update_joined_count(&self, room_id: &RoomId) -> Result<()> {
let mut joinedcount = 0_u64;
let mut invitedcount = 0_u64;
let mut joined_servers = HashSet::new();
@ -256,7 +208,8 @@ impl Data for KeyValueDatabase {
self.serverroomids.insert(&serverroom_id, &[])?;
}
self.appservice_in_room_cache
self.db
.appservice_in_room_cache
.write()
.unwrap()
.remove(room_id);
@ -265,8 +218,9 @@ impl Data for KeyValueDatabase {
}
#[tracing::instrument(skip(self, room_id, appservice))]
fn appservice_in_room(&self, room_id: &RoomId, appservice: &RegistrationInfo) -> Result<bool> {
pub(super) fn appservice_in_room(&self, room_id: &RoomId, appservice: &RegistrationInfo) -> Result<bool> {
let maybe = self
.db
.appservice_in_room_cache
.read()
.unwrap()
@ -288,7 +242,8 @@ impl Data for KeyValueDatabase {
.room_members(room_id)
.any(|userid| userid.map_or(false, |userid| appservice.users.is_match(userid.as_str())));
self.appservice_in_room_cache
self.db
.appservice_in_room_cache
.write()
.unwrap()
.entry(room_id.to_owned())
@ -301,7 +256,7 @@ impl Data for KeyValueDatabase {
/// Makes a user forget a room.
#[tracing::instrument(skip(self))]
fn forget(&self, room_id: &RoomId, user_id: &UserId) -> Result<()> {
pub(super) fn forget(&self, room_id: &RoomId, user_id: &UserId) -> Result<()> {
let mut userroom_id = user_id.as_bytes().to_vec();
userroom_id.push(0xFF);
userroom_id.extend_from_slice(room_id.as_bytes());
@ -318,7 +273,9 @@ impl Data for KeyValueDatabase {
/// Returns an iterator of all servers participating in this room.
#[tracing::instrument(skip(self))]
fn room_servers<'a>(&'a self, room_id: &RoomId) -> Box<dyn Iterator<Item = Result<OwnedServerName>> + 'a> {
pub(super) fn room_servers<'a>(
&'a self, room_id: &RoomId,
) -> Box<dyn Iterator<Item = Result<OwnedServerName>> + 'a> {
let mut prefix = room_id.as_bytes().to_vec();
prefix.push(0xFF);
@ -336,7 +293,7 @@ impl Data for KeyValueDatabase {
}
#[tracing::instrument(skip(self))]
fn server_in_room(&self, server: &ServerName, room_id: &RoomId) -> Result<bool> {
pub(super) fn server_in_room(&self, server: &ServerName, room_id: &RoomId) -> Result<bool> {
let mut key = server.as_bytes().to_vec();
key.push(0xFF);
key.extend_from_slice(room_id.as_bytes());
@ -347,7 +304,9 @@ impl Data for KeyValueDatabase {
/// Returns an iterator of all rooms a server participates in (as far as we
/// know).
#[tracing::instrument(skip(self))]
fn server_rooms<'a>(&'a self, server: &ServerName) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a> {
pub(super) fn server_rooms<'a>(
&'a self, server: &ServerName,
) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a> {
let mut prefix = server.as_bytes().to_vec();
prefix.push(0xFF);
@ -366,7 +325,7 @@ impl Data for KeyValueDatabase {
/// Returns an iterator of all joined members of a room.
#[tracing::instrument(skip(self))]
fn room_members<'a>(&'a self, room_id: &RoomId) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a> {
pub(super) fn room_members<'a>(&'a self, room_id: &RoomId) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a> {
let mut prefix = room_id.as_bytes().to_vec();
prefix.push(0xFF);
@ -385,7 +344,7 @@ impl Data for KeyValueDatabase {
/// Returns an iterator of all our local users in the room, even if they're
/// deactivated/guests
fn local_users_in_room<'a>(&'a self, room_id: &RoomId) -> Box<dyn Iterator<Item = OwnedUserId> + 'a> {
pub(super) fn local_users_in_room<'a>(&'a self, room_id: &RoomId) -> Box<dyn Iterator<Item = OwnedUserId> + 'a> {
Box::new(
self.room_members(room_id)
.filter_map(Result::ok)
@ -396,7 +355,9 @@ impl Data for KeyValueDatabase {
/// Returns an iterator of all our local joined users in a room who are
/// active (not deactivated, not guest)
#[tracing::instrument(skip(self))]
fn active_local_users_in_room<'a>(&'a self, room_id: &RoomId) -> Box<dyn Iterator<Item = OwnedUserId> + 'a> {
pub(super) fn active_local_users_in_room<'a>(
&'a self, room_id: &RoomId,
) -> Box<dyn Iterator<Item = OwnedUserId> + 'a> {
Box::new(
self.local_users_in_room(room_id)
.filter(|user| !services().users.is_deactivated(user).unwrap_or(true)),
@ -405,7 +366,7 @@ impl Data for KeyValueDatabase {
/// Returns the number of users which are currently in a room
#[tracing::instrument(skip(self))]
fn room_joined_count(&self, room_id: &RoomId) -> Result<Option<u64>> {
pub(super) fn room_joined_count(&self, room_id: &RoomId) -> Result<Option<u64>> {
self.roomid_joinedcount
.get(room_id.as_bytes())?
.map(|b| utils::u64_from_bytes(&b).map_err(|_| Error::bad_database("Invalid joinedcount in db.")))
@ -414,7 +375,7 @@ impl Data for KeyValueDatabase {
/// Returns the number of users which are currently invited to a room
#[tracing::instrument(skip(self))]
fn room_invited_count(&self, room_id: &RoomId) -> Result<Option<u64>> {
pub(super) fn room_invited_count(&self, room_id: &RoomId) -> Result<Option<u64>> {
self.roomid_invitedcount
.get(room_id.as_bytes())?
.map(|b| utils::u64_from_bytes(&b).map_err(|_| Error::bad_database("Invalid joinedcount in db.")))
@ -423,7 +384,9 @@ impl Data for KeyValueDatabase {
/// Returns an iterator over all User IDs who ever joined a room.
#[tracing::instrument(skip(self))]
fn room_useroncejoined<'a>(&'a self, room_id: &RoomId) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a> {
pub(super) fn room_useroncejoined<'a>(
&'a self, room_id: &RoomId,
) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a> {
let mut prefix = room_id.as_bytes().to_vec();
prefix.push(0xFF);
@ -446,7 +409,9 @@ impl Data for KeyValueDatabase {
/// Returns an iterator over all invited members of a room.
#[tracing::instrument(skip(self))]
fn room_members_invited<'a>(&'a self, room_id: &RoomId) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a> {
pub(super) fn room_members_invited<'a>(
&'a self, room_id: &RoomId,
) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a> {
let mut prefix = room_id.as_bytes().to_vec();
prefix.push(0xFF);
@ -468,7 +433,7 @@ impl Data for KeyValueDatabase {
}
#[tracing::instrument(skip(self))]
fn get_invite_count(&self, room_id: &RoomId, user_id: &UserId) -> Result<Option<u64>> {
pub(super) fn get_invite_count(&self, room_id: &RoomId, user_id: &UserId) -> Result<Option<u64>> {
let mut key = room_id.as_bytes().to_vec();
key.push(0xFF);
key.extend_from_slice(user_id.as_bytes());
@ -483,7 +448,7 @@ impl Data for KeyValueDatabase {
}
#[tracing::instrument(skip(self))]
fn get_left_count(&self, room_id: &RoomId, user_id: &UserId) -> Result<Option<u64>> {
pub(super) fn get_left_count(&self, room_id: &RoomId, user_id: &UserId) -> Result<Option<u64>> {
let mut key = room_id.as_bytes().to_vec();
key.push(0xFF);
key.extend_from_slice(user_id.as_bytes());
@ -496,7 +461,7 @@ impl Data for KeyValueDatabase {
/// Returns an iterator over all rooms this user joined.
#[tracing::instrument(skip(self))]
fn rooms_joined(&self, user_id: &UserId) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + '_> {
pub(super) fn rooms_joined(&self, user_id: &UserId) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + '_> {
Box::new(
self.userroomid_joined
.scan_prefix(user_id.as_bytes().to_vec())
@ -516,7 +481,7 @@ impl Data for KeyValueDatabase {
/// Returns an iterator over all rooms a user was invited to.
#[tracing::instrument(skip(self))]
fn rooms_invited<'a>(&'a self, user_id: &UserId) -> StrippedStateEventIter<'a> {
pub(super) fn rooms_invited<'a>(&'a self, user_id: &UserId) -> StrippedStateEventIter<'a> {
let mut prefix = user_id.as_bytes().to_vec();
prefix.push(0xFF);
@ -543,7 +508,9 @@ impl Data for KeyValueDatabase {
}
#[tracing::instrument(skip(self))]
fn invite_state(&self, user_id: &UserId, room_id: &RoomId) -> Result<Option<Vec<Raw<AnyStrippedStateEvent>>>> {
pub(super) fn invite_state(
&self, user_id: &UserId, room_id: &RoomId,
) -> Result<Option<Vec<Raw<AnyStrippedStateEvent>>>> {
let mut key = user_id.as_bytes().to_vec();
key.push(0xFF);
key.extend_from_slice(room_id.as_bytes());
@ -560,7 +527,9 @@ impl Data for KeyValueDatabase {
}
#[tracing::instrument(skip(self))]
fn left_state(&self, user_id: &UserId, room_id: &RoomId) -> Result<Option<Vec<Raw<AnyStrippedStateEvent>>>> {
pub(super) fn left_state(
&self, user_id: &UserId, room_id: &RoomId,
) -> Result<Option<Vec<Raw<AnyStrippedStateEvent>>>> {
let mut key = user_id.as_bytes().to_vec();
key.push(0xFF);
key.extend_from_slice(room_id.as_bytes());
@ -578,7 +547,7 @@ impl Data for KeyValueDatabase {
/// Returns an iterator over all rooms a user left.
#[tracing::instrument(skip(self))]
fn rooms_left<'a>(&'a self, user_id: &UserId) -> AnySyncStateEventIter<'a> {
pub(super) fn rooms_left<'a>(&'a self, user_id: &UserId) -> AnySyncStateEventIter<'a> {
let mut prefix = user_id.as_bytes().to_vec();
prefix.push(0xFF);
@ -605,7 +574,7 @@ impl Data for KeyValueDatabase {
}
#[tracing::instrument(skip(self))]
fn once_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<bool> {
pub(super) fn once_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<bool> {
let mut userroom_id = user_id.as_bytes().to_vec();
userroom_id.push(0xFF);
userroom_id.extend_from_slice(room_id.as_bytes());
@ -614,7 +583,7 @@ impl Data for KeyValueDatabase {
}
#[tracing::instrument(skip(self))]
fn is_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<bool> {
pub(super) fn is_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<bool> {
let mut userroom_id = user_id.as_bytes().to_vec();
userroom_id.push(0xFF);
userroom_id.extend_from_slice(room_id.as_bytes());
@ -623,7 +592,7 @@ impl Data for KeyValueDatabase {
}
#[tracing::instrument(skip(self))]
fn is_invited(&self, user_id: &UserId, room_id: &RoomId) -> Result<bool> {
pub(super) fn is_invited(&self, user_id: &UserId, room_id: &RoomId) -> Result<bool> {
let mut userroom_id = user_id.as_bytes().to_vec();
userroom_id.push(0xFF);
userroom_id.extend_from_slice(room_id.as_bytes());
@ -632,7 +601,7 @@ impl Data for KeyValueDatabase {
}
#[tracing::instrument(skip(self))]
fn is_left(&self, user_id: &UserId, room_id: &RoomId) -> Result<bool> {
pub(super) fn is_left(&self, user_id: &UserId, room_id: &RoomId) -> Result<bool> {
let mut userroom_id = user_id.as_bytes().to_vec();
userroom_id.push(0xFF);
userroom_id.extend_from_slice(room_id.as_bytes());
@ -641,7 +610,9 @@ impl Data for KeyValueDatabase {
}
#[tracing::instrument(skip(self))]
fn servers_invite_via<'a>(&'a self, room_id: &RoomId) -> Box<dyn Iterator<Item = Result<OwnedServerName>> + 'a> {
pub(super) fn servers_invite_via<'a>(
&'a self, room_id: &RoomId,
) -> Box<dyn Iterator<Item = Result<OwnedServerName>> + 'a> {
let key = room_id.as_bytes().to_vec();
Box::new(
@ -665,7 +636,7 @@ impl Data for KeyValueDatabase {
}
#[tracing::instrument(skip(self))]
fn add_servers_invite_via(&self, room_id: &RoomId, servers: &[OwnedServerName]) -> Result<()> {
pub(super) fn add_servers_invite_via(&self, room_id: &RoomId, servers: &[OwnedServerName]) -> Result<()> {
let mut prev_servers = self
.servers_invite_via(room_id)
.filter_map(Result::ok)

View file

@ -1,6 +1,8 @@
use std::sync::Arc;
use conduit::Server;
use data::Data;
use database::KeyValueDatabase;
use itertools::Itertools;
use ruma::{
events::{
@ -24,10 +26,16 @@ use crate::{service::appservice::RegistrationInfo, services, user_is_local, Erro
mod data;
pub struct Service {
pub db: Arc<dyn Data>,
pub db: Data,
}
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<KeyValueDatabase>) -> Result<Self> {
Ok(Self {
db: Data::new(db),
})
}
/// Update current membership data.
#[tracing::instrument(skip(self, last_state))]
#[allow(clippy::too_many_arguments)]

View file

@ -1,21 +1,28 @@
use std::{collections::HashSet, mem::size_of, sync::Arc};
use database::KvTree;
use super::CompressedStateEvent;
use crate::{utils, Error, KeyValueDatabase, Result};
pub struct StateDiff {
pub parent: Option<u64>,
pub added: Arc<HashSet<CompressedStateEvent>>,
pub removed: Arc<HashSet<CompressedStateEvent>>,
pub(super) struct StateDiff {
pub(super) parent: Option<u64>,
pub(super) added: Arc<HashSet<CompressedStateEvent>>,
pub(super) removed: Arc<HashSet<CompressedStateEvent>>,
}
pub trait Data: Send + Sync {
fn get_statediff(&self, shortstatehash: u64) -> Result<StateDiff>;
fn save_statediff(&self, shortstatehash: u64, diff: StateDiff) -> Result<()>;
pub struct Data {
shortstatehash_statediff: Arc<dyn KvTree>,
}
impl Data for KeyValueDatabase {
fn get_statediff(&self, shortstatehash: u64) -> Result<StateDiff> {
impl Data {
pub(super) fn new(db: &Arc<KeyValueDatabase>) -> Self {
Self {
shortstatehash_statediff: db.shortstatehash_statediff.clone(),
}
}
pub(super) fn get_statediff(&self, shortstatehash: u64) -> Result<StateDiff> {
let value = self
.shortstatehash_statediff
.get(&shortstatehash.to_be_bytes())?
@ -53,7 +60,7 @@ impl Data for KeyValueDatabase {
})
}
fn save_statediff(&self, shortstatehash: u64, diff: StateDiff) -> Result<()> {
pub(super) fn save_statediff(&self, shortstatehash: u64, diff: StateDiff) -> Result<()> {
let mut value = diff.parent.unwrap_or(0).to_be_bytes().to_vec();
for new in diff.added.iter() {
value.extend_from_slice(&new[..]);

View file

@ -1,3 +1,8 @@
use std::sync::Mutex as StdMutex;
use conduit::Server;
use database::KeyValueDatabase;
mod data;
use std::{
collections::HashSet,
@ -41,16 +46,25 @@ type ParentStatesVec = Vec<(
)>;
type HashSetCompressStateEvent = Result<(u64, Arc<HashSet<CompressedStateEvent>>, Arc<HashSet<CompressedStateEvent>>)>;
pub type CompressedStateEvent = [u8; 2 * size_of::<u64>()];
pub struct Service {
pub db: Arc<dyn Data>,
pub db: Data,
pub stateinfo_cache: StateInfoLruCache,
}
pub type CompressedStateEvent = [u8; 2 * size_of::<u64>()];
impl Service {
pub fn build(server: &Arc<Server>, db: &Arc<KeyValueDatabase>) -> Result<Self> {
let config = &server.config;
Ok(Self {
db: Data::new(db),
stateinfo_cache: StdMutex::new(LruCache::new(
(f64::from(config.stateinfo_cache_capacity) * config.conduit_cache_capacity_modifier) as usize,
)),
})
}
/// Returns a stack with info on shortstatehash, full state, added diff and
/// removed diff for the selected shortstatehash and each parent layer.
#[tracing::instrument(skip(self))]

View file

@ -1,22 +1,24 @@
use std::mem::size_of;
use std::{mem::size_of, sync::Arc};
use database::KvTree;
use ruma::{api::client::threads::get_threads::v1::IncludeThreads, OwnedUserId, RoomId, UserId};
use crate::{services, utils, Error, KeyValueDatabase, PduEvent, Result};
type PduEventIterResult<'a> = Result<Box<dyn Iterator<Item = Result<(u64, PduEvent)>> + 'a>>;
pub trait Data: Send + Sync {
fn threads_until<'a>(
&'a self, user_id: &'a UserId, room_id: &'a RoomId, until: u64, include: &'a IncludeThreads,
) -> PduEventIterResult<'a>;
fn update_participants(&self, root_id: &[u8], participants: &[OwnedUserId]) -> Result<()>;
fn get_participants(&self, root_id: &[u8]) -> Result<Option<Vec<OwnedUserId>>>;
pub struct Data {
threadid_userids: Arc<dyn KvTree>,
}
impl Data for KeyValueDatabase {
fn threads_until<'a>(
impl Data {
pub(super) fn new(db: &Arc<KeyValueDatabase>) -> Self {
Self {
threadid_userids: db.threadid_userids.clone(),
}
}
pub(super) fn threads_until<'a>(
&'a self, user_id: &'a UserId, room_id: &'a RoomId, until: u64, _include: &'a IncludeThreads,
) -> PduEventIterResult<'a> {
let prefix = services()
@ -50,7 +52,7 @@ impl Data for KeyValueDatabase {
))
}
fn update_participants(&self, root_id: &[u8], participants: &[OwnedUserId]) -> Result<()> {
pub(super) fn update_participants(&self, root_id: &[u8], participants: &[OwnedUserId]) -> Result<()> {
let users = participants
.iter()
.map(|user| user.as_bytes())
@ -62,7 +64,7 @@ impl Data for KeyValueDatabase {
Ok(())
}
fn get_participants(&self, root_id: &[u8]) -> Result<Option<Vec<OwnedUserId>>> {
pub(super) fn get_participants(&self, root_id: &[u8]) -> Result<Option<Vec<OwnedUserId>>> {
if let Some(users) = self.threadid_userids.get(root_id)? {
Ok(Some(
users

View file

@ -1,3 +1,6 @@
use conduit::Server;
use database::KeyValueDatabase;
mod data;
use std::{collections::BTreeMap, sync::Arc};
@ -13,10 +16,16 @@ use serde_json::json;
use crate::{services, Error, PduEvent, Result};
pub struct Service {
pub db: Arc<dyn Data>,
pub db: Data,
}
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<KeyValueDatabase>) -> Result<Self> {
Ok(Self {
db: Data::new(db),
})
}
pub fn threads_until<'a>(
&'a self, user_id: &'a UserId, room_id: &'a RoomId, until: u64, include: &'a IncludeThreads,
) -> Result<impl Iterator<Item = Result<(u64, PduEvent)>> + 'a> {

View file

@ -1,76 +1,36 @@
use std::{collections::hash_map, mem::size_of, sync::Arc};
use database::KvTree;
use ruma::{api::client::error::ErrorKind, CanonicalJsonObject, EventId, OwnedUserId, RoomId, UserId};
use tracing::error;
use super::PduCount;
use crate::{services, utils, Error, KeyValueDatabase, PduEvent, Result};
pub trait Data: Send + Sync {
fn last_timeline_count(&self, sender_user: &UserId, room_id: &RoomId) -> Result<PduCount>;
/// Returns the `count` of this pdu's id.
fn get_pdu_count(&self, event_id: &EventId) -> Result<Option<PduCount>>;
/// Returns the json of a pdu.
fn get_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>>;
/// Returns the json of a pdu.
fn get_non_outlier_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>>;
/// Returns the pdu's id.
fn get_pdu_id(&self, event_id: &EventId) -> Result<Option<Vec<u8>>>;
/// Returns the pdu.
///
/// Checks the `eventid_outlierpdu` Tree if not found in the timeline.
fn get_non_outlier_pdu(&self, event_id: &EventId) -> Result<Option<PduEvent>>;
/// Returns the pdu.
///
/// Checks the `eventid_outlierpdu` Tree if not found in the timeline.
fn get_pdu(&self, event_id: &EventId) -> Result<Option<Arc<PduEvent>>>;
/// Returns the pdu.
///
/// This does __NOT__ check the outliers `Tree`.
fn get_pdu_from_id(&self, pdu_id: &[u8]) -> Result<Option<PduEvent>>;
/// Returns the pdu as a `BTreeMap<String, CanonicalJsonValue>`.
fn get_pdu_json_from_id(&self, pdu_id: &[u8]) -> Result<Option<CanonicalJsonObject>>;
/// Adds a new pdu to the timeline
fn append_pdu(&self, pdu_id: &[u8], pdu: &PduEvent, json: &CanonicalJsonObject, count: u64) -> Result<()>;
// Adds a new pdu to the backfilled timeline
fn prepend_backfill_pdu(&self, pdu_id: &[u8], event_id: &EventId, json: &CanonicalJsonObject) -> Result<()>;
/// Removes a pdu and creates a new one with the same id.
fn replace_pdu(&self, pdu_id: &[u8], pdu_json: &CanonicalJsonObject, pdu: &PduEvent) -> Result<()>;
/// Returns an iterator over all events and their tokens in a room that
/// happened before the event with id `until` in reverse-chronological
/// order.
#[allow(clippy::type_complexity)]
fn pdus_until<'a>(
&'a self, user_id: &UserId, room_id: &RoomId, until: PduCount,
) -> Result<Box<dyn Iterator<Item = Result<(PduCount, PduEvent)>> + 'a>>;
/// Returns an iterator over all events in a room that happened after the
/// event with id `from` in chronological order.
#[allow(clippy::type_complexity)]
fn pdus_after<'a>(
&'a self, user_id: &UserId, room_id: &RoomId, from: PduCount,
) -> Result<Box<dyn Iterator<Item = Result<(PduCount, PduEvent)>> + 'a>>;
fn increment_notification_counts(
&self, room_id: &RoomId, notifies: Vec<OwnedUserId>, highlights: Vec<OwnedUserId>,
) -> Result<()>;
pub struct Data {
eventid_pduid: Arc<dyn KvTree>,
pduid_pdu: Arc<dyn KvTree>,
eventid_outlierpdu: Arc<dyn KvTree>,
userroomid_notificationcount: Arc<dyn KvTree>,
userroomid_highlightcount: Arc<dyn KvTree>,
db: Arc<KeyValueDatabase>,
}
impl Data for KeyValueDatabase {
fn last_timeline_count(&self, sender_user: &UserId, room_id: &RoomId) -> Result<PduCount> {
impl Data {
pub(super) fn new(db: &Arc<KeyValueDatabase>) -> Self {
Self {
eventid_pduid: db.eventid_pduid.clone(),
pduid_pdu: db.pduid_pdu.clone(),
eventid_outlierpdu: db.eventid_outlierpdu.clone(),
userroomid_notificationcount: db.userroomid_notificationcount.clone(),
userroomid_highlightcount: db.userroomid_highlightcount.clone(),
db: db.clone(),
}
}
pub(super) fn last_timeline_count(&self, sender_user: &UserId, room_id: &RoomId) -> Result<PduCount> {
match self
.db
.lasttimelinecount_cache
.lock()
.unwrap()
@ -96,7 +56,7 @@ impl Data for KeyValueDatabase {
}
/// Returns the `count` of this pdu's id.
fn get_pdu_count(&self, event_id: &EventId) -> Result<Option<PduCount>> {
pub(super) fn get_pdu_count(&self, event_id: &EventId) -> Result<Option<PduCount>> {
self.eventid_pduid
.get(event_id.as_bytes())?
.map(|pdu_id| pdu_count(&pdu_id))
@ -104,7 +64,7 @@ impl Data for KeyValueDatabase {
}
/// Returns the json of a pdu.
fn get_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>> {
pub(super) fn get_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>> {
self.get_non_outlier_pdu_json(event_id)?.map_or_else(
|| {
self.eventid_outlierpdu
@ -117,7 +77,7 @@ impl Data for KeyValueDatabase {
}
/// Returns the json of a pdu.
fn get_non_outlier_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>> {
pub(super) fn get_non_outlier_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>> {
self.eventid_pduid
.get(event_id.as_bytes())?
.map(|pduid| {
@ -131,10 +91,12 @@ impl Data for KeyValueDatabase {
}
/// Returns the pdu's id.
fn get_pdu_id(&self, event_id: &EventId) -> Result<Option<Vec<u8>>> { self.eventid_pduid.get(event_id.as_bytes()) }
pub(super) fn get_pdu_id(&self, event_id: &EventId) -> Result<Option<Vec<u8>>> {
self.eventid_pduid.get(event_id.as_bytes())
}
/// Returns the pdu.
fn get_non_outlier_pdu(&self, event_id: &EventId) -> Result<Option<PduEvent>> {
pub(super) fn get_non_outlier_pdu(&self, event_id: &EventId) -> Result<Option<PduEvent>> {
self.eventid_pduid
.get(event_id.as_bytes())?
.map(|pduid| {
@ -150,7 +112,7 @@ impl Data for KeyValueDatabase {
/// Returns the pdu.
///
/// Checks the `eventid_outlierpdu` Tree if not found in the timeline.
fn get_pdu(&self, event_id: &EventId) -> Result<Option<Arc<PduEvent>>> {
pub(super) fn get_pdu(&self, event_id: &EventId) -> Result<Option<Arc<PduEvent>>> {
if let Some(pdu) = self
.get_non_outlier_pdu(event_id)?
.map_or_else(
@ -173,7 +135,7 @@ impl Data for KeyValueDatabase {
/// Returns the pdu.
///
/// This does __NOT__ check the outliers `Tree`.
fn get_pdu_from_id(&self, pdu_id: &[u8]) -> Result<Option<PduEvent>> {
pub(super) fn get_pdu_from_id(&self, pdu_id: &[u8]) -> Result<Option<PduEvent>> {
self.pduid_pdu.get(pdu_id)?.map_or(Ok(None), |pdu| {
Ok(Some(
serde_json::from_slice(&pdu).map_err(|_| Error::bad_database("Invalid PDU in db."))?,
@ -182,7 +144,7 @@ impl Data for KeyValueDatabase {
}
/// Returns the pdu as a `BTreeMap<String, CanonicalJsonValue>`.
fn get_pdu_json_from_id(&self, pdu_id: &[u8]) -> Result<Option<CanonicalJsonObject>> {
pub(super) fn get_pdu_json_from_id(&self, pdu_id: &[u8]) -> Result<Option<CanonicalJsonObject>> {
self.pduid_pdu.get(pdu_id)?.map_or(Ok(None), |pdu| {
Ok(Some(
serde_json::from_slice(&pdu).map_err(|_| Error::bad_database("Invalid PDU in db."))?,
@ -190,13 +152,16 @@ impl Data for KeyValueDatabase {
})
}
fn append_pdu(&self, pdu_id: &[u8], pdu: &PduEvent, json: &CanonicalJsonObject, count: u64) -> Result<()> {
pub(super) fn append_pdu(
&self, pdu_id: &[u8], pdu: &PduEvent, json: &CanonicalJsonObject, count: u64,
) -> Result<()> {
self.pduid_pdu.insert(
pdu_id,
&serde_json::to_vec(json).expect("CanonicalJsonObject is always a valid"),
)?;
self.lasttimelinecount_cache
self.db
.lasttimelinecount_cache
.lock()
.unwrap()
.insert(pdu.room_id.clone(), PduCount::Normal(count));
@ -207,7 +172,9 @@ impl Data for KeyValueDatabase {
Ok(())
}
fn prepend_backfill_pdu(&self, pdu_id: &[u8], event_id: &EventId, json: &CanonicalJsonObject) -> Result<()> {
pub(super) fn prepend_backfill_pdu(
&self, pdu_id: &[u8], event_id: &EventId, json: &CanonicalJsonObject,
) -> Result<()> {
self.pduid_pdu.insert(
pdu_id,
&serde_json::to_vec(json).expect("CanonicalJsonObject is always a valid"),
@ -220,7 +187,7 @@ impl Data for KeyValueDatabase {
}
/// Removes a pdu and creates a new one with the same id.
fn replace_pdu(&self, pdu_id: &[u8], pdu_json: &CanonicalJsonObject, _pdu: &PduEvent) -> Result<()> {
pub(super) fn replace_pdu(&self, pdu_id: &[u8], pdu_json: &CanonicalJsonObject, _pdu: &PduEvent) -> Result<()> {
if self.pduid_pdu.get(pdu_id)?.is_some() {
self.pduid_pdu.insert(
pdu_id,
@ -236,7 +203,7 @@ impl Data for KeyValueDatabase {
/// Returns an iterator over all events and their tokens in a room that
/// happened before the event with id `until` in reverse-chronological
/// order.
fn pdus_until<'a>(
pub(super) fn pdus_until<'a>(
&'a self, user_id: &UserId, room_id: &RoomId, until: PduCount,
) -> Result<Box<dyn Iterator<Item = Result<(PduCount, PduEvent)>> + 'a>> {
let (prefix, current) = count_to_id(room_id, until, 1, true)?;
@ -260,7 +227,7 @@ impl Data for KeyValueDatabase {
))
}
fn pdus_after<'a>(
pub(super) fn pdus_after<'a>(
&'a self, user_id: &UserId, room_id: &RoomId, from: PduCount,
) -> Result<Box<dyn Iterator<Item = Result<(PduCount, PduEvent)>> + 'a>> {
let (prefix, current) = count_to_id(room_id, from, 1, false)?;
@ -284,7 +251,7 @@ impl Data for KeyValueDatabase {
))
}
fn increment_notification_counts(
pub(super) fn increment_notification_counts(
&self, room_id: &RoomId, notifies: Vec<OwnedUserId>, highlights: Vec<OwnedUserId>,
) -> Result<()> {
let mut notifies_batch = Vec::new();
@ -311,7 +278,7 @@ impl Data for KeyValueDatabase {
}
/// Returns the `count` of this pdu's id.
fn pdu_count(pdu_id: &[u8]) -> Result<PduCount> {
pub(super) fn pdu_count(pdu_id: &[u8]) -> Result<PduCount> {
let last_u64 = utils::u64_from_bytes(&pdu_id[pdu_id.len() - size_of::<u64>()..])
.map_err(|_| Error::bad_database("PDU has invalid count bytes."))?;
let second_last_u64 =
@ -324,7 +291,9 @@ fn pdu_count(pdu_id: &[u8]) -> Result<PduCount> {
}
}
fn count_to_id(room_id: &RoomId, count: PduCount, offset: u64, subtract: bool) -> Result<(Vec<u8>, Vec<u8>)> {
pub(super) fn count_to_id(
room_id: &RoomId, count: PduCount, offset: u64, subtract: bool,
) -> Result<(Vec<u8>, Vec<u8>)> {
let prefix = services()
.rooms
.short

View file

@ -1,3 +1,6 @@
use conduit::Server;
use database::KeyValueDatabase;
mod data;
use std::{
@ -74,12 +77,19 @@ struct ExtractBody {
}
pub struct Service {
pub db: Arc<dyn Data>,
pub db: Data,
pub lasttimelinecount_cache: Mutex<HashMap<OwnedRoomId, PduCount>>,
}
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<KeyValueDatabase>) -> Result<Self> {
Ok(Self {
db: Data::new(db),
lasttimelinecount_cache: Mutex::new(HashMap::new()),
})
}
#[tracing::instrument(skip(self))]
pub fn first_pdu_in_room(&self, room_id: &RoomId) -> Result<Option<Arc<PduEvent>>> {
self.all_pdus(user_id!("@doesntmatter:conduit.rs"), room_id)?

View file

@ -1,5 +1,7 @@
use std::collections::BTreeMap;
use std::{collections::BTreeMap, sync::Arc};
use conduit::Server;
use database::KeyValueDatabase;
use ruma::{
api::federation::transactions::edu::{Edu, TypingContent},
events::SyncEphemeralRoomEvent,
@ -23,6 +25,14 @@ pub struct Service {
}
impl Service {
pub fn build(_server: &Arc<Server>, _db: &Arc<KeyValueDatabase>) -> Result<Self> {
Ok(Self {
typing: RwLock::new(BTreeMap::new()),
last_typing_update: RwLock::new(BTreeMap::new()),
typing_update_sender: broadcast::channel(100).0,
})
}
/// Sets a user as typing until the timeout timestamp is reached or
/// roomtyping_remove is called.
pub async fn typing_add(&self, user_id: &UserId, room_id: &RoomId, timeout: u64) -> Result<()> {

View file

@ -1,28 +1,30 @@
use std::sync::Arc;
use database::KvTree;
use ruma::{OwnedRoomId, OwnedUserId, RoomId, UserId};
use crate::{services, utils, Error, KeyValueDatabase, Result};
pub trait Data: Send + Sync {
fn reset_notification_counts(&self, user_id: &UserId, room_id: &RoomId) -> Result<()>;
fn notification_count(&self, user_id: &UserId, room_id: &RoomId) -> Result<u64>;
fn highlight_count(&self, user_id: &UserId, room_id: &RoomId) -> Result<u64>;
// Returns the count at which the last reset_notification_counts was called
fn last_notification_read(&self, user_id: &UserId, room_id: &RoomId) -> Result<u64>;
fn associate_token_shortstatehash(&self, room_id: &RoomId, token: u64, shortstatehash: u64) -> Result<()>;
fn get_token_shortstatehash(&self, room_id: &RoomId, token: u64) -> Result<Option<u64>>;
fn get_shared_rooms<'a>(
&'a self, users: Vec<OwnedUserId>,
) -> Result<Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a>>;
pub struct Data {
userroomid_notificationcount: Arc<dyn KvTree>,
userroomid_highlightcount: Arc<dyn KvTree>,
roomuserid_lastnotificationread: Arc<dyn KvTree>,
roomsynctoken_shortstatehash: Arc<dyn KvTree>,
userroomid_joined: Arc<dyn KvTree>,
}
impl Data for KeyValueDatabase {
fn reset_notification_counts(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
impl Data {
pub(super) fn new(db: &Arc<KeyValueDatabase>) -> Self {
Self {
userroomid_notificationcount: db.userroomid_notificationcount.clone(),
userroomid_highlightcount: db.userroomid_highlightcount.clone(),
roomuserid_lastnotificationread: db.roomuserid_lastnotificationread.clone(),
roomsynctoken_shortstatehash: db.roomsynctoken_shortstatehash.clone(),
userroomid_joined: db.userroomid_joined.clone(),
}
}
pub(super) fn reset_notification_counts(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
let mut userroom_id = user_id.as_bytes().to_vec();
userroom_id.push(0xFF);
userroom_id.extend_from_slice(room_id.as_bytes());
@ -41,7 +43,7 @@ impl Data for KeyValueDatabase {
Ok(())
}
fn notification_count(&self, user_id: &UserId, room_id: &RoomId) -> Result<u64> {
pub(super) fn notification_count(&self, user_id: &UserId, room_id: &RoomId) -> Result<u64> {
let mut userroom_id = user_id.as_bytes().to_vec();
userroom_id.push(0xFF);
userroom_id.extend_from_slice(room_id.as_bytes());
@ -53,7 +55,7 @@ impl Data for KeyValueDatabase {
})
}
fn highlight_count(&self, user_id: &UserId, room_id: &RoomId) -> Result<u64> {
pub(super) fn highlight_count(&self, user_id: &UserId, room_id: &RoomId) -> Result<u64> {
let mut userroom_id = user_id.as_bytes().to_vec();
userroom_id.push(0xFF);
userroom_id.extend_from_slice(room_id.as_bytes());
@ -65,7 +67,7 @@ impl Data for KeyValueDatabase {
})
}
fn last_notification_read(&self, user_id: &UserId, room_id: &RoomId) -> Result<u64> {
pub(super) fn last_notification_read(&self, user_id: &UserId, room_id: &RoomId) -> Result<u64> {
let mut key = room_id.as_bytes().to_vec();
key.push(0xFF);
key.extend_from_slice(user_id.as_bytes());
@ -81,7 +83,9 @@ impl Data for KeyValueDatabase {
.unwrap_or(0))
}
fn associate_token_shortstatehash(&self, room_id: &RoomId, token: u64, shortstatehash: u64) -> Result<()> {
pub(super) fn associate_token_shortstatehash(
&self, room_id: &RoomId, token: u64, shortstatehash: u64,
) -> Result<()> {
let shortroomid = services()
.rooms
.short
@ -95,7 +99,7 @@ impl Data for KeyValueDatabase {
.insert(&key, &shortstatehash.to_be_bytes())
}
fn get_token_shortstatehash(&self, room_id: &RoomId, token: u64) -> Result<Option<u64>> {
pub(super) fn get_token_shortstatehash(&self, room_id: &RoomId, token: u64) -> Result<Option<u64>> {
let shortroomid = services()
.rooms
.short
@ -114,7 +118,7 @@ impl Data for KeyValueDatabase {
.transpose()
}
fn get_shared_rooms<'a>(
pub(super) fn get_shared_rooms<'a>(
&'a self, users: Vec<OwnedUserId>,
) -> Result<Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a>> {
let iterators = users.into_iter().map(move |user_id| {

View file

@ -1,3 +1,6 @@
use conduit::Server;
use database::KeyValueDatabase;
mod data;
use std::sync::Arc;
@ -8,10 +11,16 @@ use ruma::{OwnedRoomId, OwnedUserId, RoomId, UserId};
use crate::Result;
pub struct Service {
pub db: Arc<dyn Data>,
pub db: Data,
}
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<KeyValueDatabase>) -> Result<Self> {
Ok(Self {
db: Data::new(db),
})
}
pub fn reset_notification_counts(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
self.db.reset_notification_counts(user_id, room_id)
}