style: Document & refactor rooms/lazy_loading service

This commit is contained in:
timedout
2026-06-27 18:36:44 +01:00
parent 0d1b130127
commit 0a162b7bc4
3 changed files with 74 additions and 74 deletions
+72 -72
View File
@@ -3,7 +3,7 @@
use std::{collections::HashSet, sync::Arc};
use conduwuit::{
Result, implement,
Result,
utils::{IterStream, ReadyExt, stream::TryIgnore},
};
use database::{Database, Deserialized, Handle, Interfix, Map, Qry};
@@ -55,87 +55,87 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
#[implement(Service)]
#[tracing::instrument(skip(self), level = "debug")]
pub async fn reset(&self, ctx: &Context<'_>) {
let prefix = (ctx.user_id, ctx.device_id, ctx.room_id, Interfix);
self.db
.lazyloadedids
.keys_prefix_raw(&prefix)
.ignore_err()
.ready_for_each(|key| self.db.lazyloadedids.remove(key))
.await;
}
impl Service {
/// Resets the lazy loading context.
pub async fn reset(&self, ctx: &Context<'_>) {
let prefix = (ctx.user_id, ctx.device_id, ctx.room_id, Interfix);
self.db
.lazyloadedids
.keys_prefix_raw(&prefix)
.ignore_err()
.ready_for_each(|key| self.db.lazyloadedids.remove(key))
.await;
}
/// Returns only the subset of `senders` which should be sent to the client
/// according to the provided lazy loading context.
#[implement(Service)]
#[tracing::instrument(name = "retain", level = "debug", skip_all)]
pub async fn retain_lazy_members(&self, senders: MemberSet, ctx: &Context<'_>) -> MemberSet {
debug_assert!(
ctx.options.is_none_or(Options::is_enabled),
"lazy loading should be enabled by your options"
);
/// Returns only the subset of `senders` which should be sent to the client
/// according to the provided lazy loading context.
pub async fn retain_lazy_members(&self, senders: MemberSet, ctx: &Context<'_>) -> MemberSet {
debug_assert!(
ctx.options.is_none_or(Options::is_enabled),
"lazy loading should be enabled by your options"
);
let include_redundant = cfg!(feature = "element_hacks")
|| ctx.options.is_some_and(Options::include_redundant_members);
let include_redundant = cfg!(feature = "element_hacks")
|| ctx.options.is_some_and(Options::include_redundant_members);
let witness = self
.witness(ctx, senders.iter().map(AsRef::as_ref))
.zip(senders.iter().stream());
let witness = self
.witness(ctx, senders.iter().map(AsRef::as_ref))
.zip(senders.iter().stream());
pin_mut!(witness);
let _cork = self.db.db.cork();
let mut senders = MemberSet::with_capacity(senders.len());
while let Some((status, sender)) = witness.next().await {
if include_redundant || status == Status::Unseen {
senders.insert(sender.clone());
continue;
}
if let Status::Seen(seen) = status {
if seen == 0 || ctx.token == Some(seen) {
pin_mut!(witness);
let _cork = self.db.db.cork();
let mut senders = MemberSet::with_capacity(senders.len());
while let Some((status, sender)) = witness.next().await {
if include_redundant || status == Status::Unseen {
senders.insert(sender.clone());
continue;
}
if let Status::Seen(seen) = status {
if seen == 0 || ctx.token == Some(seen) {
senders.insert(sender.clone());
continue;
}
}
}
senders
}
senders
}
/// Witnesses a set of users via the lazy loading context, returning a
/// stream of their statuses.
fn witness<'a, I>(
&'a self,
ctx: &'a Context<'a>,
senders: I,
) -> impl Stream<Item = Status> + Send + 'a
where
I: Iterator<Item = &'a UserId> + Send + Clone + 'a,
{
let make_key =
|sender: &'a UserId| -> Key<'a> { (ctx.user_id, ctx.device_id, ctx.room_id, sender) };
#[implement(Service)]
fn witness<'a, I>(
&'a self,
ctx: &'a Context<'a>,
senders: I,
) -> impl Stream<Item = Status> + Send + 'a
where
I: Iterator<Item = &'a UserId> + Send + Clone + 'a,
{
let make_key =
|sender: &'a UserId| -> Key<'a> { (ctx.user_id, ctx.device_id, ctx.room_id, sender) };
senders
.clone()
.stream()
.map(make_key)
.qry(&self.db.lazyloadedids)
.map(into_status)
.zip(senders.stream())
.map(move |(status, sender)| {
if matches!(status, Status::Unseen) {
self.db
.lazyloadedids
.put_aput::<8, _, _>(make_key(sender), 0_u64);
} else if matches!(status, Status::Seen(0)) {
self.db
.lazyloadedids
.put_aput::<8, _, _>(make_key(sender), ctx.token.unwrap_or(0_u64));
}
senders
.clone()
.stream()
.map(make_key)
.qry(&self.db.lazyloadedids)
.map(into_status)
.zip(senders.stream())
.map(move |(status, sender)| {
if matches!(status, Status::Unseen) {
self.db
.lazyloadedids
.put_aput::<8, _, _>(make_key(sender), 0_u64);
} else if matches!(status, Status::Seen(0)) {
self.db
.lazyloadedids
.put_aput::<8, _, _>(make_key(sender), ctx.token.unwrap_or(0_u64));
}
status
})
status
})
}
}
fn into_status(result: Result<Handle<'_>>) -> Status {
@@ -146,6 +146,8 @@ fn into_status(result: Result<Handle<'_>>) -> Status {
}
impl Options for LazyLoadOptions {
fn is_enabled(&self) -> bool { !self.is_disabled() }
fn include_redundant_members(&self) -> bool {
if let Self::Enabled { include_redundant_members } = self {
*include_redundant_members
@@ -153,6 +155,4 @@ fn include_redundant_members(&self) -> bool {
false
}
}
fn is_enabled(&self) -> bool { !self.is_disabled() }
}
+1 -1
View File
@@ -1,6 +1,6 @@
use std::sync::Arc;
use conduwuit::{Result, implement, utils::stream::TryIgnore};
use conduwuit::{Result, utils::stream::TryIgnore};
use database::Map;
use futures::{Stream, StreamExt};
use ruma::{OwnedRoomId, RoomId};
+1 -1
View File
@@ -1,6 +1,6 @@
use std::sync::Arc;
use conduwuit::{Result, implement, matrix::PduEvent};
use conduwuit::{Result, matrix::PduEvent};
use database::{Deserialized, Json, Map};
use ruma::{CanonicalJsonObject, EventId};