Introduce OptionFuture helpers
Optimize user directory searches
This commit is contained in:
@@ -6,7 +6,7 @@ use std::{
|
||||
use axum::extract::State;
|
||||
use futures::{
|
||||
FutureExt, StreamExt, TryFutureExt,
|
||||
future::{OptionFuture, join, join3, join4, join5},
|
||||
future::{join, join3, join4, join5},
|
||||
pin_mut,
|
||||
};
|
||||
use ruma::{
|
||||
@@ -52,6 +52,7 @@ use tuwunel_core::{
|
||||
self, BoolExt, FutureBoolExt, IterStream, ReadyExt, TryFutureExtExt,
|
||||
future::{OptionStream, ReadyBoolExt},
|
||||
math::ruma_from_u64,
|
||||
option::OptionExt,
|
||||
result::MapExpect,
|
||||
stream::{BroadbandExt, Tools, TryExpect, WidebandExt},
|
||||
string::to_small_string,
|
||||
@@ -130,19 +131,18 @@ pub(crate) async fn sync_events_route(
|
||||
let sender_user = body.sender_user();
|
||||
let sender_device = body.sender_device.as_deref();
|
||||
|
||||
let filter: OptionFuture<_> = body
|
||||
let filter = body
|
||||
.body
|
||||
.filter
|
||||
.as_ref()
|
||||
.map(async |filter| match filter {
|
||||
.map_async(async |filter| match filter {
|
||||
| Filter::FilterDefinition(filter) => filter.clone(),
|
||||
| Filter::FilterId(filter_id) => services
|
||||
.users
|
||||
.get_filter(sender_user, filter_id)
|
||||
.await
|
||||
.unwrap_or_default(),
|
||||
})
|
||||
.into();
|
||||
});
|
||||
|
||||
let filter = filter.map(Option::unwrap_or_default);
|
||||
let full_state = body.body.full_state;
|
||||
@@ -243,16 +243,13 @@ async fn build_empty_response(
|
||||
sender_device: Option<&DeviceId>,
|
||||
next_batch: u64,
|
||||
) -> sync_events::v3::Response {
|
||||
let device_one_time_keys_count: OptionFuture<_> = sender_device
|
||||
.map(|sender_device| {
|
||||
services
|
||||
.users
|
||||
.count_one_time_keys(sender_user, sender_device)
|
||||
})
|
||||
.into();
|
||||
|
||||
sync_events::v3::Response {
|
||||
device_one_time_keys_count: device_one_time_keys_count
|
||||
device_one_time_keys_count: sender_device
|
||||
.map_async(|sender_device| {
|
||||
services
|
||||
.users
|
||||
.count_one_time_keys(sender_user, sender_device)
|
||||
})
|
||||
.await
|
||||
.unwrap_or_default(),
|
||||
|
||||
@@ -380,11 +377,12 @@ async fn build_sync_events(
|
||||
knocked_rooms
|
||||
});
|
||||
|
||||
let presence_updates: OptionFuture<_> = services
|
||||
let presence_updates = services
|
||||
.config
|
||||
.allow_local_presence
|
||||
.then(|| process_presence_updates(services, since, next_batch, sender_user, filter))
|
||||
.into();
|
||||
.then_async(|| {
|
||||
process_presence_updates(services, since, next_batch, sender_user, filter)
|
||||
});
|
||||
|
||||
let account_data = services
|
||||
.account_data
|
||||
@@ -399,32 +397,26 @@ async fn build_sync_events(
|
||||
.map(ToOwned::to_owned)
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
let to_device_events: OptionFuture<_> = sender_device
|
||||
.map(|sender_device| {
|
||||
services
|
||||
.users
|
||||
.get_to_device_events(sender_user, sender_device, Some(since), Some(next_batch))
|
||||
.map(at!(1))
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.into();
|
||||
let to_device_events = sender_device.map_async(|sender_device| {
|
||||
services
|
||||
.users
|
||||
.get_to_device_events(sender_user, sender_device, Some(since), Some(next_batch))
|
||||
.map(at!(1))
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
let device_one_time_keys_count: OptionFuture<_> = sender_device
|
||||
.map(|sender_device| {
|
||||
services
|
||||
.users
|
||||
.count_one_time_keys(sender_user, sender_device)
|
||||
})
|
||||
.into();
|
||||
let device_one_time_keys_count = sender_device.map_async(|sender_device| {
|
||||
services
|
||||
.users
|
||||
.count_one_time_keys(sender_user, sender_device)
|
||||
});
|
||||
|
||||
// Remove all to-device events the device received *last time*
|
||||
let remove_to_device_events: OptionFuture<_> = sender_device
|
||||
.map(|sender_device| {
|
||||
services
|
||||
.users
|
||||
.remove_to_device_events(sender_user, sender_device, since)
|
||||
})
|
||||
.into();
|
||||
let remove_to_device_events = sender_device.map_async(|sender_device| {
|
||||
services
|
||||
.users
|
||||
.remove_to_device_events(sender_user, sender_device, since)
|
||||
});
|
||||
|
||||
let (
|
||||
account_data,
|
||||
@@ -643,17 +635,16 @@ async fn load_left_room(
|
||||
.prev_shortstatehash(room_id, PduCount::Normal(since).saturating_add(1))
|
||||
.ok();
|
||||
|
||||
let horizon_shortstatehash: OptionFuture<_> = timeline_pdus
|
||||
let horizon_shortstatehash = timeline_pdus
|
||||
.first()
|
||||
.map(at!(0))
|
||||
.map(|count| {
|
||||
.map_async(|count| {
|
||||
services
|
||||
.timeline
|
||||
.get_shortstatehash(room_id, count)
|
||||
.inspect_err(inspect_debug_log)
|
||||
.ok()
|
||||
})
|
||||
.into();
|
||||
});
|
||||
|
||||
let left_shortstatehash = services
|
||||
.timeline
|
||||
@@ -790,40 +781,34 @@ async fn load_joined_room(
|
||||
"if timeline events, last_timeline_count must be in the since window."
|
||||
);
|
||||
|
||||
let since_shortstatehash: OptionFuture<_> = timeline_changed
|
||||
.then(|| {
|
||||
services
|
||||
.timeline
|
||||
.prev_shortstatehash(room_id, PduCount::Normal(since).saturating_add(1))
|
||||
.ok()
|
||||
})
|
||||
.into();
|
||||
let since_shortstatehash = timeline_changed.then_async(|| {
|
||||
services
|
||||
.timeline
|
||||
.prev_shortstatehash(room_id, PduCount::Normal(since).saturating_add(1))
|
||||
.ok()
|
||||
});
|
||||
|
||||
let horizon_shortstatehash: OptionFuture<_> = timeline_pdus
|
||||
let horizon_shortstatehash = timeline_pdus
|
||||
.first()
|
||||
.map(at!(0))
|
||||
.map(|count| {
|
||||
.map_async(|count| {
|
||||
services
|
||||
.timeline
|
||||
.get_shortstatehash(room_id, count)
|
||||
.inspect_err(inspect_debug_log)
|
||||
})
|
||||
.into();
|
||||
});
|
||||
|
||||
let current_shortstatehash: OptionFuture<_> = timeline_changed
|
||||
.then(|| {
|
||||
services
|
||||
.timeline
|
||||
.get_shortstatehash(room_id, last_timeline_count)
|
||||
.inspect_err(inspect_debug_log)
|
||||
.or_else(|_| services.state.get_room_shortstatehash(room_id))
|
||||
.map_err(|_| err!(Database(error!("Room {room_id} has no state"))))
|
||||
})
|
||||
.into();
|
||||
let current_shortstatehash = timeline_changed.then_async(|| {
|
||||
services
|
||||
.timeline
|
||||
.get_shortstatehash(room_id, last_timeline_count)
|
||||
.inspect_err(inspect_debug_log)
|
||||
.or_else(|_| services.state.get_room_shortstatehash(room_id))
|
||||
.map_err(|_| err!(Database(error!("Room {room_id} has no state"))))
|
||||
});
|
||||
|
||||
let encrypted_room: OptionFuture<_> = timeline_changed
|
||||
.then(|| services.state_accessor.is_encrypted_room(room_id))
|
||||
.into();
|
||||
let encrypted_room =
|
||||
timeline_changed.then_async(|| services.state_accessor.is_encrypted_room(room_id));
|
||||
|
||||
let receipt_events = services
|
||||
.read_receipt
|
||||
@@ -873,53 +858,43 @@ async fn load_joined_room(
|
||||
};
|
||||
|
||||
// Reset lazy loading because this is an initial sync
|
||||
let lazy_load_reset: OptionFuture<_> = initial
|
||||
.then(|| services.lazy_loading.reset(lazy_loading_context))
|
||||
.into();
|
||||
let lazy_load_reset =
|
||||
initial.then_async(|| services.lazy_loading.reset(lazy_loading_context));
|
||||
|
||||
lazy_load_reset.await;
|
||||
let witness: OptionFuture<_> = lazy_loading_enabled
|
||||
.then(|| {
|
||||
let witness: Witness = timeline_pdus
|
||||
.iter()
|
||||
.map(ref_at!(1))
|
||||
.map(Event::sender)
|
||||
.map(Into::into)
|
||||
.chain(receipt_events.keys().map(Into::into))
|
||||
.collect();
|
||||
let witness = lazy_loading_enabled.then_async(|| {
|
||||
let witness: Witness = timeline_pdus
|
||||
.iter()
|
||||
.map(ref_at!(1))
|
||||
.map(Event::sender)
|
||||
.map(Into::into)
|
||||
.chain(receipt_events.keys().map(Into::into))
|
||||
.collect();
|
||||
|
||||
services
|
||||
.lazy_loading
|
||||
.witness_retain(witness, lazy_loading_context)
|
||||
})
|
||||
.into();
|
||||
services
|
||||
.lazy_loading
|
||||
.witness_retain(witness, lazy_loading_context)
|
||||
});
|
||||
|
||||
let sender_joined_count: OptionFuture<_> = timeline_changed
|
||||
.then(|| {
|
||||
services
|
||||
.state_cache
|
||||
.get_joined_count(room_id, sender_user)
|
||||
.unwrap_or(0)
|
||||
})
|
||||
.into();
|
||||
let sender_joined_count = timeline_changed.then_async(|| {
|
||||
services
|
||||
.state_cache
|
||||
.get_joined_count(room_id, sender_user)
|
||||
.unwrap_or(0)
|
||||
});
|
||||
|
||||
let since_encryption: OptionFuture<_> = since_shortstatehash
|
||||
.map(|shortstatehash| {
|
||||
services
|
||||
.state_accessor
|
||||
.state_get(shortstatehash, &StateEventType::RoomEncryption, "")
|
||||
})
|
||||
.into();
|
||||
let since_encryption = since_shortstatehash.map_async(|shortstatehash| {
|
||||
services
|
||||
.state_accessor
|
||||
.state_get(shortstatehash, &StateEventType::RoomEncryption, "")
|
||||
});
|
||||
|
||||
let last_notification_read: OptionFuture<_> = timeline_pdus
|
||||
.is_empty()
|
||||
.then(|| {
|
||||
services
|
||||
.pusher
|
||||
.last_notification_read(sender_user, room_id)
|
||||
.ok()
|
||||
})
|
||||
.into();
|
||||
let last_notification_read = timeline_pdus.is_empty().then_async(|| {
|
||||
services
|
||||
.pusher
|
||||
.last_notification_read(sender_user, room_id)
|
||||
.ok()
|
||||
});
|
||||
|
||||
let last_privateread_update = services
|
||||
.read_receipt
|
||||
@@ -941,21 +916,19 @@ async fn load_joined_room(
|
||||
|
||||
let joined_since_last_sync = sender_joined_count.unwrap_or(0) > since;
|
||||
|
||||
let state_changes: OptionFuture<_> = current_shortstatehash
|
||||
.map(|current_shortstatehash| {
|
||||
calculate_state_changes(
|
||||
services,
|
||||
sender_user,
|
||||
room_id,
|
||||
full_state || initial,
|
||||
since_shortstatehash,
|
||||
horizon_shortstatehash,
|
||||
current_shortstatehash,
|
||||
joined_since_last_sync,
|
||||
witness.as_ref(),
|
||||
)
|
||||
})
|
||||
.into();
|
||||
let state_changes = current_shortstatehash.map_async(|current_shortstatehash| {
|
||||
calculate_state_changes(
|
||||
services,
|
||||
sender_user,
|
||||
room_id,
|
||||
full_state || initial,
|
||||
since_shortstatehash,
|
||||
horizon_shortstatehash,
|
||||
current_shortstatehash,
|
||||
joined_since_last_sync,
|
||||
witness.as_ref(),
|
||||
)
|
||||
});
|
||||
|
||||
let StateChanges {
|
||||
heroes,
|
||||
@@ -1002,35 +975,28 @@ async fn load_joined_room(
|
||||
let send_notification_count_filter =
|
||||
|count: &UInt| *count != uint!(0) || send_notification_resets;
|
||||
|
||||
let notification_count: OptionFuture<_> = send_notification_counts
|
||||
.then(|| {
|
||||
services
|
||||
.pusher
|
||||
.notification_count(sender_user, room_id)
|
||||
.map(TryInto::try_into)
|
||||
.unwrap_or(uint!(0))
|
||||
})
|
||||
.into();
|
||||
let notification_count = send_notification_counts.then_async(|| {
|
||||
services
|
||||
.pusher
|
||||
.notification_count(sender_user, room_id)
|
||||
.map(TryInto::try_into)
|
||||
.unwrap_or(uint!(0))
|
||||
});
|
||||
|
||||
let highlight_count: OptionFuture<_> = send_notification_counts
|
||||
.then(|| {
|
||||
services
|
||||
.pusher
|
||||
.highlight_count(sender_user, room_id)
|
||||
.map(TryInto::try_into)
|
||||
.unwrap_or(uint!(0))
|
||||
})
|
||||
.into();
|
||||
let highlight_count = send_notification_counts.then_async(|| {
|
||||
services
|
||||
.pusher
|
||||
.highlight_count(sender_user, room_id)
|
||||
.map(TryInto::try_into)
|
||||
.unwrap_or(uint!(0))
|
||||
});
|
||||
|
||||
let private_read_event: OptionFuture<_> = last_privateread_update
|
||||
.gt(&since)
|
||||
.then(|| {
|
||||
services
|
||||
.read_receipt
|
||||
.private_read_get(room_id, sender_user)
|
||||
.map(Result::ok)
|
||||
})
|
||||
.into();
|
||||
let private_read_event = last_privateread_update.gt(&since).then_async(|| {
|
||||
services
|
||||
.read_receipt
|
||||
.private_read_get(room_id, sender_user)
|
||||
.map(Result::ok)
|
||||
});
|
||||
|
||||
let typing_events = services
|
||||
.typing
|
||||
@@ -1226,37 +1192,31 @@ async fn calculate_state_changes<'a>(
|
||||
.ok()
|
||||
};
|
||||
|
||||
let lazy_state_ids: OptionFuture<_> = witness
|
||||
.map(|witness| {
|
||||
witness
|
||||
.iter()
|
||||
.stream()
|
||||
.ready_filter(|&user_id| user_id != sender_user)
|
||||
.broad_filter_map(|user_id| state_get_shorteventid(user_id))
|
||||
.into_future()
|
||||
})
|
||||
.into();
|
||||
let lazy_state_ids = witness.map_async(|witness| {
|
||||
witness
|
||||
.iter()
|
||||
.stream()
|
||||
.ready_filter(|&user_id| user_id != sender_user)
|
||||
.broad_filter_map(|user_id| state_get_shorteventid(user_id))
|
||||
.into_future()
|
||||
});
|
||||
|
||||
let state_diff_ids: OptionFuture<_> = incremental
|
||||
.then(|| {
|
||||
services
|
||||
.state_accessor
|
||||
.state_added((since_shortstatehash, horizon_shortstatehash))
|
||||
.boxed()
|
||||
.into_future()
|
||||
})
|
||||
.into();
|
||||
let state_diff_ids = incremental.then_async(|| {
|
||||
services
|
||||
.state_accessor
|
||||
.state_added((since_shortstatehash, horizon_shortstatehash))
|
||||
.boxed()
|
||||
.into_future()
|
||||
});
|
||||
|
||||
let current_state_ids: OptionFuture<_> = (!incremental)
|
||||
.then(|| {
|
||||
services
|
||||
.state_accessor
|
||||
.state_full_shortids(horizon_shortstatehash)
|
||||
.expect_ok()
|
||||
.boxed()
|
||||
.into_future()
|
||||
})
|
||||
.into();
|
||||
let current_state_ids = (!incremental).then_async(|| {
|
||||
services
|
||||
.state_accessor
|
||||
.state_full_shortids(horizon_shortstatehash)
|
||||
.expect_ok()
|
||||
.boxed()
|
||||
.into_future()
|
||||
});
|
||||
|
||||
let state_events = current_state_ids
|
||||
.stream()
|
||||
@@ -1278,9 +1238,8 @@ async fn calculate_state_changes<'a>(
|
||||
.iter()
|
||||
.any(|event| *event.kind() == RoomMember);
|
||||
|
||||
let member_counts: OptionFuture<_> = send_member_counts
|
||||
.then(|| calculate_counts(services, room_id, sender_user))
|
||||
.into();
|
||||
let member_counts =
|
||||
send_member_counts.then_async(|| calculate_counts(services, room_id, sender_user));
|
||||
|
||||
let (joined_member_count, invited_member_count, heroes) =
|
||||
member_counts.await.unwrap_or((None, None, None));
|
||||
@@ -1334,12 +1293,11 @@ async fn calculate_counts(
|
||||
|
||||
let small_room = joined_member_count.saturating_add(invited_member_count) <= 5;
|
||||
|
||||
let heroes: OptionFuture<_> = services
|
||||
let heroes = services
|
||||
.config
|
||||
.calculate_heroes
|
||||
.and_is(small_room)
|
||||
.then(|| calculate_heroes(services, room_id, sender_user))
|
||||
.into();
|
||||
.then_async(|| calculate_heroes(services, room_id, sender_user));
|
||||
|
||||
(Some(joined_member_count), Some(invited_member_count), heroes.await)
|
||||
}
|
||||
|
||||
@@ -6,10 +6,7 @@ mod typing;
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
use futures::{
|
||||
FutureExt,
|
||||
future::{OptionFuture, join5},
|
||||
};
|
||||
use futures::{FutureExt, future::join5};
|
||||
use ruma::{
|
||||
RoomId,
|
||||
api::client::sync::sync_events::v5::{ListId, request::ExtensionRoomConfig, response},
|
||||
@@ -37,45 +34,40 @@ pub(super) async fn handle(
|
||||
) -> Result<response::Extensions> {
|
||||
let SyncInfo { .. } = sync_info;
|
||||
|
||||
let account_data: OptionFuture<_> = conn
|
||||
let account_data = conn
|
||||
.extensions
|
||||
.account_data
|
||||
.enabled
|
||||
.unwrap_or(false)
|
||||
.then(|| account_data::collect(sync_info, conn, window))
|
||||
.into();
|
||||
.then_async(|| account_data::collect(sync_info, conn, window));
|
||||
|
||||
let receipts: OptionFuture<_> = conn
|
||||
let receipts = conn
|
||||
.extensions
|
||||
.receipts
|
||||
.enabled
|
||||
.unwrap_or(false)
|
||||
.then(|| receipts::collect(sync_info, conn, window))
|
||||
.into();
|
||||
.then_async(|| receipts::collect(sync_info, conn, window));
|
||||
|
||||
let typing: OptionFuture<_> = conn
|
||||
let typing = conn
|
||||
.extensions
|
||||
.typing
|
||||
.enabled
|
||||
.unwrap_or(false)
|
||||
.then(|| typing::collect(sync_info, conn, window))
|
||||
.into();
|
||||
.then_async(|| typing::collect(sync_info, conn, window));
|
||||
|
||||
let to_device: OptionFuture<_> = conn
|
||||
let to_device = conn
|
||||
.extensions
|
||||
.to_device
|
||||
.enabled
|
||||
.unwrap_or(false)
|
||||
.then(|| to_device::collect(sync_info, conn))
|
||||
.into();
|
||||
.then_async(|| to_device::collect(sync_info, conn));
|
||||
|
||||
let e2ee: OptionFuture<_> = conn
|
||||
let e2ee = conn
|
||||
.extensions
|
||||
.e2ee
|
||||
.enabled
|
||||
.unwrap_or(false)
|
||||
.then(|| e2ee::collect(sync_info, conn))
|
||||
.into();
|
||||
.then_async(|| e2ee::collect(sync_info, conn));
|
||||
|
||||
let (account_data, receipts, typing, to_device, e2ee) =
|
||||
join5(account_data, receipts, typing, to_device, e2ee)
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::collections::HashSet;
|
||||
|
||||
use futures::{
|
||||
FutureExt, StreamExt, TryFutureExt,
|
||||
future::{OptionFuture, join, join3},
|
||||
future::{join, join3},
|
||||
stream::once,
|
||||
};
|
||||
use ruma::{
|
||||
@@ -71,15 +71,12 @@ pub(super) async fn collect(
|
||||
let device_one_time_keys_count = services
|
||||
.users
|
||||
.last_one_time_keys_update(sender_user)
|
||||
.then(|since| -> OptionFuture<_> {
|
||||
since
|
||||
.gt(&conn.globalsince)
|
||||
.then(|| {
|
||||
services
|
||||
.users
|
||||
.count_one_time_keys(sender_user, sender_device)
|
||||
})
|
||||
.into()
|
||||
.then(|since| {
|
||||
since.gt(&conn.globalsince).then_async(|| {
|
||||
services
|
||||
.users
|
||||
.count_one_time_keys(sender_user, sender_device)
|
||||
})
|
||||
})
|
||||
.map(Option::unwrap_or_default);
|
||||
|
||||
@@ -164,9 +161,8 @@ async fn collect_room(
|
||||
|
||||
let encrypted_since_last_sync = !since_encryption;
|
||||
let joined_since_last_sync = sender_joined_count.is_ok_and(|count| count > conn.globalsince);
|
||||
let joined_members_burst: OptionFuture<_> = (joined_since_last_sync
|
||||
|| encrypted_since_last_sync)
|
||||
.then(|| {
|
||||
let joined_members_burst =
|
||||
(joined_since_last_sync || encrypted_since_last_sync).then_async(|| {
|
||||
services
|
||||
.state_cache
|
||||
.room_members(room_id)
|
||||
@@ -175,8 +171,7 @@ async fn collect_room(
|
||||
.map(|user_id| (MembershipState::Join, user_id))
|
||||
.boxed()
|
||||
.into_future()
|
||||
})
|
||||
.into();
|
||||
});
|
||||
|
||||
services
|
||||
.state_accessor
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use futures::{StreamExt, future::OptionFuture, pin_mut};
|
||||
use futures::{StreamExt, pin_mut};
|
||||
use ruma::{
|
||||
RoomId, api::client::sync::sync_events::v5::request::ListFilters, directory::RoomTypeFilter,
|
||||
events::room::member::MembershipState,
|
||||
@@ -7,7 +7,8 @@ use tuwunel_core::{
|
||||
is_equal_to, is_true,
|
||||
utils::{
|
||||
BoolExt, FutureBoolExt, IterStream, ReadyExt,
|
||||
future::{self, OptionExt, ReadyBoolExt},
|
||||
future::{self, OptionFutureExt, ReadyBoolExt},
|
||||
option::OptionExt,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -20,56 +21,49 @@ pub(super) async fn filter_room(
|
||||
room_id: &RoomId,
|
||||
membership: Option<&MembershipState>,
|
||||
) -> bool {
|
||||
let match_invite: OptionFuture<_> = filter
|
||||
.is_invite
|
||||
.map(async |is_invite| match (membership, is_invite) {
|
||||
| (Some(MembershipState::Invite), true) => true,
|
||||
| (Some(MembershipState::Invite), false) => false,
|
||||
| (Some(_), true) => false,
|
||||
| (Some(_), false) => true,
|
||||
| _ =>
|
||||
services
|
||||
.state_cache
|
||||
.is_invited(sender_user, room_id)
|
||||
.await == is_invite,
|
||||
})
|
||||
.into();
|
||||
let match_invite =
|
||||
filter
|
||||
.is_invite
|
||||
.map_async(async |is_invite| match (membership, is_invite) {
|
||||
| (Some(MembershipState::Invite), true) => true,
|
||||
| (Some(MembershipState::Invite), false) => false,
|
||||
| (Some(_), true) => false,
|
||||
| (Some(_), false) => true,
|
||||
| _ =>
|
||||
services
|
||||
.state_cache
|
||||
.is_invited(sender_user, room_id)
|
||||
.await == is_invite,
|
||||
});
|
||||
|
||||
let match_direct: OptionFuture<_> = filter
|
||||
.is_dm
|
||||
.map(async |is_dm| {
|
||||
services
|
||||
.account_data
|
||||
.is_direct(sender_user, room_id)
|
||||
.await == is_dm
|
||||
})
|
||||
.into();
|
||||
let match_direct = filter.is_dm.map_async(async |is_dm| {
|
||||
services
|
||||
.account_data
|
||||
.is_direct(sender_user, room_id)
|
||||
.await == is_dm
|
||||
});
|
||||
|
||||
let match_direct_member: OptionFuture<_> = filter
|
||||
.is_dm
|
||||
.map(async |is_dm| {
|
||||
services
|
||||
.state_accessor
|
||||
.is_direct(room_id, sender_user)
|
||||
.await == is_dm
|
||||
})
|
||||
.into();
|
||||
let match_direct_member = filter.is_dm.map_async(async |is_dm| {
|
||||
services
|
||||
.state_accessor
|
||||
.is_direct(room_id, sender_user)
|
||||
.await == is_dm
|
||||
});
|
||||
|
||||
let match_encrypted: OptionFuture<_> = filter
|
||||
let match_encrypted = filter
|
||||
.is_encrypted
|
||||
.map(async |is_encrypted| {
|
||||
.map_async(async |is_encrypted| {
|
||||
services
|
||||
.state_accessor
|
||||
.is_encrypted_room(room_id)
|
||||
.await == is_encrypted
|
||||
})
|
||||
.into();
|
||||
});
|
||||
|
||||
let match_space_child: OptionFuture<_> = filter
|
||||
let match_space_child = filter
|
||||
.spaces
|
||||
.is_empty()
|
||||
.is_false()
|
||||
.then(async || {
|
||||
.then_async(async || {
|
||||
filter
|
||||
.spaces
|
||||
.iter()
|
||||
@@ -77,43 +71,38 @@ pub(super) async fn filter_room(
|
||||
.flat_map(|room_id| services.spaces.get_space_children(room_id))
|
||||
.ready_any(is_equal_to!(room_id))
|
||||
.await
|
||||
})
|
||||
.into();
|
||||
});
|
||||
|
||||
let fetch_tags = !filter.tags.is_empty() || !filter.not_tags.is_empty();
|
||||
let match_room_tag: OptionFuture<_> = fetch_tags
|
||||
.then(async || {
|
||||
if let Some(tags) = services
|
||||
.account_data
|
||||
.get_room_tags(sender_user, room_id)
|
||||
.await
|
||||
.ok()
|
||||
.filter(|tags| !tags.is_empty())
|
||||
{
|
||||
tags.keys().any(|tag| {
|
||||
(filter.not_tags.is_empty() || !filter.not_tags.contains(tag))
|
||||
|| (!filter.tags.is_empty() && filter.tags.contains(tag))
|
||||
})
|
||||
} else {
|
||||
filter.tags.is_empty()
|
||||
}
|
||||
})
|
||||
.into();
|
||||
let match_room_tag = fetch_tags.then_async(async || {
|
||||
if let Some(tags) = services
|
||||
.account_data
|
||||
.get_room_tags(sender_user, room_id)
|
||||
.await
|
||||
.ok()
|
||||
.filter(|tags| !tags.is_empty())
|
||||
{
|
||||
tags.keys().any(|tag| {
|
||||
(filter.not_tags.is_empty() || !filter.not_tags.contains(tag))
|
||||
|| (!filter.tags.is_empty() && filter.tags.contains(tag))
|
||||
})
|
||||
} else {
|
||||
filter.tags.is_empty()
|
||||
}
|
||||
});
|
||||
|
||||
let fetch_room_type = !filter.room_types.is_empty() || !filter.not_room_types.is_empty();
|
||||
let match_room_type: OptionFuture<_> = fetch_room_type
|
||||
.then(async || {
|
||||
let room_type = services
|
||||
.state_accessor
|
||||
.get_room_type(room_id)
|
||||
.await
|
||||
.ok();
|
||||
let match_room_type = fetch_room_type.then_async(async || {
|
||||
let room_type = services
|
||||
.state_accessor
|
||||
.get_room_type(room_id)
|
||||
.await
|
||||
.ok();
|
||||
|
||||
let room_type = RoomTypeFilter::from(room_type);
|
||||
(filter.not_room_types.is_empty() || !filter.not_room_types.contains(&room_type))
|
||||
&& (filter.room_types.is_empty() || filter.room_types.contains(&room_type))
|
||||
})
|
||||
.into();
|
||||
let room_type = RoomTypeFilter::from(room_type);
|
||||
(filter.not_room_types.is_empty() || !filter.not_room_types.contains(&room_type))
|
||||
&& (filter.room_types.is_empty() || filter.room_types.contains(&room_type))
|
||||
});
|
||||
|
||||
future::and7(
|
||||
match_invite.is_none_or(is_true!()),
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::{
|
||||
|
||||
use futures::{
|
||||
FutureExt, StreamExt, TryFutureExt, TryStreamExt,
|
||||
future::{OptionFuture, join, join3, join4},
|
||||
future::{join, join3, join4},
|
||||
};
|
||||
use ruma::{
|
||||
JsOption, MxcUri, OwnedMxcUri, OwnedRoomId, RoomId, UserId,
|
||||
@@ -131,19 +131,16 @@ async fn handle_room(
|
||||
(timeline_limit, required_state)
|
||||
});
|
||||
|
||||
let timeline: OptionFuture<_> = is_invite
|
||||
.is_false()
|
||||
.then(|| {
|
||||
load_timeline(
|
||||
services,
|
||||
sender_user,
|
||||
room_id,
|
||||
PduCount::Normal(roomsince),
|
||||
Some(PduCount::from(conn.next_batch)),
|
||||
timeline_limit,
|
||||
)
|
||||
})
|
||||
.into();
|
||||
let timeline = is_invite.is_false().then_async(|| {
|
||||
load_timeline(
|
||||
services,
|
||||
sender_user,
|
||||
room_id,
|
||||
PduCount::Normal(roomsince),
|
||||
Some(PduCount::from(conn.next_batch)),
|
||||
timeline_limit,
|
||||
)
|
||||
});
|
||||
|
||||
let (timeline_pdus, limited, _lastcount) = timeline
|
||||
.await
|
||||
@@ -182,18 +179,17 @@ async fn handle_room(
|
||||
.map(TryInto::try_into)
|
||||
.flat_ok();
|
||||
|
||||
let num_live: OptionFuture<_> = roomsince
|
||||
let num_live = roomsince
|
||||
.ne(&0)
|
||||
.and_is(limited || timeline_pdus.len() >= timeline_limit)
|
||||
.then(|| {
|
||||
.then_async(|| {
|
||||
services
|
||||
.timeline
|
||||
.pdus(None, room_id, Some(roomsince.into()))
|
||||
.count()
|
||||
.map(TryInto::try_into)
|
||||
.map(Result::ok)
|
||||
})
|
||||
.into();
|
||||
});
|
||||
|
||||
let lazy = required_state
|
||||
.iter()
|
||||
@@ -249,14 +245,12 @@ async fn handle_room(
|
||||
.collect();
|
||||
|
||||
// TODO: figure out a timestamp we can use for remote invites
|
||||
let invite_state: OptionFuture<_> = is_invite
|
||||
.then(|| {
|
||||
services
|
||||
.state_cache
|
||||
.invite_state(sender_user, room_id)
|
||||
.ok()
|
||||
})
|
||||
.into();
|
||||
let invite_state = is_invite.then_async(|| {
|
||||
services
|
||||
.state_cache
|
||||
.invite_state(sender_user, room_id)
|
||||
.ok()
|
||||
});
|
||||
|
||||
let room_name = services
|
||||
.state_accessor
|
||||
@@ -327,10 +321,10 @@ async fn handle_room(
|
||||
.boxed()
|
||||
.await;
|
||||
|
||||
let heroes: OptionFuture<_> = services
|
||||
let heroes = services
|
||||
.config
|
||||
.calculate_heroes
|
||||
.then(|| {
|
||||
.then_async(|| {
|
||||
calculate_heroes(
|
||||
services,
|
||||
sender_user,
|
||||
@@ -339,9 +333,10 @@ async fn handle_room(
|
||||
room_avatar.as_deref(),
|
||||
)
|
||||
})
|
||||
.into();
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
|
||||
let (heroes, heroes_name, heroes_avatar) = heroes.await.unwrap_or_default();
|
||||
let (heroes, heroes_name, heroes_avatar) = heroes;
|
||||
|
||||
Ok(response::Room {
|
||||
initial: roomsince.eq(&0).then_some(true),
|
||||
@@ -388,17 +383,15 @@ async fn calculate_heroes(
|
||||
.await
|
||||
.ok()?;
|
||||
|
||||
let name: OptionFuture<_> = content
|
||||
let name = content
|
||||
.displayname
|
||||
.is_none()
|
||||
.then(|| services.users.displayname(&user_id).ok())
|
||||
.into();
|
||||
.then_async(|| services.users.displayname(&user_id).ok());
|
||||
|
||||
let avatar: OptionFuture<_> = content
|
||||
let avatar = content
|
||||
.avatar_url
|
||||
.is_none()
|
||||
.then(|| services.users.avatar_url(&user_id).ok())
|
||||
.into();
|
||||
.then_async(|| services.users.avatar_url(&user_id).ok());
|
||||
|
||||
let (name, avatar) = join(name, avatar).await;
|
||||
let hero = response::Hero {
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use futures::{
|
||||
FutureExt, StreamExt, TryFutureExt,
|
||||
future::{OptionFuture, join5},
|
||||
};
|
||||
use futures::{FutureExt, StreamExt, TryFutureExt, future::join5};
|
||||
use ruma::{OwnedRoomId, UInt, events::room::member::MembershipState, uint};
|
||||
use tuwunel_core::{
|
||||
apply, is_true,
|
||||
@@ -12,6 +9,7 @@ use tuwunel_core::{
|
||||
utils::{
|
||||
BoolExt, TryFutureExtExt,
|
||||
math::usize_from_ruma,
|
||||
option::OptionExt,
|
||||
stream::{BroadbandExt, IterStream},
|
||||
},
|
||||
};
|
||||
@@ -80,15 +78,11 @@ async fn matcher(
|
||||
.iter()
|
||||
.stream()
|
||||
.filter_map(async |(id, list)| {
|
||||
let filter: OptionFuture<_> = list
|
||||
.filters
|
||||
list.filters
|
||||
.clone()
|
||||
.map(async |filters| {
|
||||
.map_async(async |filters| {
|
||||
filter_room(sync_info, &filters, &room_id, membership.as_ref()).await
|
||||
})
|
||||
.into();
|
||||
|
||||
filter
|
||||
.await
|
||||
.is_none_or(is_true!())
|
||||
.then(|| id.clone())
|
||||
@@ -97,50 +91,40 @@ async fn matcher(
|
||||
.map(|lists| (lists.is_empty().is_false(), lists))
|
||||
.await;
|
||||
|
||||
let last_notification: OptionFuture<_> = matched
|
||||
.then(|| {
|
||||
services
|
||||
.pusher
|
||||
.last_notification_read(sender_user, &room_id)
|
||||
.unwrap_or_default()
|
||||
})
|
||||
.into();
|
||||
let last_notification = matched.then_async(|| {
|
||||
services
|
||||
.pusher
|
||||
.last_notification_read(sender_user, &room_id)
|
||||
.unwrap_or_default()
|
||||
});
|
||||
|
||||
let last_privateread: OptionFuture<_> = matched
|
||||
.then(|| {
|
||||
services
|
||||
.read_receipt
|
||||
.last_privateread_update(sender_user, &room_id)
|
||||
})
|
||||
.into();
|
||||
let last_privateread = matched.then_async(|| {
|
||||
services
|
||||
.read_receipt
|
||||
.last_privateread_update(sender_user, &room_id)
|
||||
});
|
||||
|
||||
let last_receipt: OptionFuture<_> = matched
|
||||
.then(|| {
|
||||
services
|
||||
.read_receipt
|
||||
.last_receipt_count(&room_id, sender_user.into(), None)
|
||||
.unwrap_or_default()
|
||||
})
|
||||
.into();
|
||||
let last_receipt = matched.then_async(|| {
|
||||
services
|
||||
.read_receipt
|
||||
.last_receipt_count(&room_id, sender_user.into(), None)
|
||||
.unwrap_or_default()
|
||||
});
|
||||
|
||||
let last_account: OptionFuture<_> = matched
|
||||
.then(|| {
|
||||
services
|
||||
.account_data
|
||||
.last_count(Some(room_id.as_ref()), sender_user, Some(conn.next_batch))
|
||||
.unwrap_or_default()
|
||||
})
|
||||
.into();
|
||||
let last_account = matched.then_async(|| {
|
||||
services
|
||||
.account_data
|
||||
.last_count(Some(room_id.as_ref()), sender_user, Some(conn.next_batch))
|
||||
.unwrap_or_default()
|
||||
});
|
||||
|
||||
let last_timeline: OptionFuture<_> = matched
|
||||
.then(|| {
|
||||
services
|
||||
.timeline
|
||||
.last_timeline_count(None, &room_id, Some(conn.next_batch.into()))
|
||||
.map_ok(PduCount::into_unsigned)
|
||||
.unwrap_or_default()
|
||||
})
|
||||
.into();
|
||||
let last_timeline = matched.then_async(|| {
|
||||
services
|
||||
.timeline
|
||||
.last_timeline_count(None, &room_id, Some(conn.next_batch.into()))
|
||||
.map_ok(PduCount::into_unsigned)
|
||||
.unwrap_or_default()
|
||||
});
|
||||
|
||||
let (last_timeline, last_notification, last_account, last_receipt, last_privateread) =
|
||||
join5(last_timeline, last_notification, last_account, last_receipt, last_privateread)
|
||||
|
||||
Reference in New Issue
Block a user