mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-15 19:45:34 -04:00
feat(ffi): Implement RoomList::invites
feat(ffi): Implement `RoomList::invites`
This commit is contained in:
@@ -149,6 +149,24 @@ impl RoomList {
|
||||
})
|
||||
}
|
||||
|
||||
async fn invites(
|
||||
&self,
|
||||
listener: Box<dyn RoomListEntriesListener>,
|
||||
) -> Result<RoomListEntriesResult, RoomListError> {
|
||||
let (entries, entries_stream) = self.inner.invites().await.map_err(RoomListError::from)?;
|
||||
|
||||
Ok(RoomListEntriesResult {
|
||||
entries: entries.into_iter().map(Into::into).collect(),
|
||||
entries_stream: Arc::new(TaskHandle::new(RUNTIME.spawn(async move {
|
||||
pin_mut!(entries_stream);
|
||||
|
||||
while let Some(diff) = entries_stream.next().await {
|
||||
listener.on_update(diff.into());
|
||||
}
|
||||
}))),
|
||||
})
|
||||
}
|
||||
|
||||
async fn apply_input(&self, input: RoomListInput) -> Result<(), RoomListError> {
|
||||
self.inner.apply_input(input.into()).await.map_err(Into::into)
|
||||
}
|
||||
|
||||
@@ -230,6 +230,19 @@ impl RoomList {
|
||||
.ok_or_else(|| Error::UnknownList(ALL_ROOMS_LIST_NAME.to_owned()))
|
||||
}
|
||||
|
||||
/// Get all previous invites, in addition to a [`Stream`] to invites.
|
||||
///
|
||||
/// Invites are taking the form of `RoomListEntry`, it's like a “sub” room
|
||||
/// list.
|
||||
pub async fn invites(
|
||||
&self,
|
||||
) -> Result<(Vector<RoomListEntry>, impl Stream<Item = VectorDiff<RoomListEntry>>), Error> {
|
||||
self.sliding_sync
|
||||
.on_list(INVITES_LIST_NAME, |list| ready(list.room_list_stream()))
|
||||
.await
|
||||
.ok_or_else(|| Error::UnknownList(INVITES_LIST_NAME.to_owned()))
|
||||
}
|
||||
|
||||
/// Pass an [`Input`] onto the state machine.
|
||||
pub async fn apply_input(&self, input: Input) -> Result<(), Error> {
|
||||
use Input::*;
|
||||
|
||||
@@ -13,6 +13,7 @@ use super::Error;
|
||||
|
||||
pub const ALL_ROOMS_LIST_NAME: &str = "all_rooms";
|
||||
pub const VISIBLE_ROOMS_LIST_NAME: &str = "visible_rooms";
|
||||
pub const INVITES_LIST_NAME: &str = "invites";
|
||||
|
||||
/// The state of the [`super::RoomList`]' state machine.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@@ -130,6 +131,36 @@ impl Action for SetAllRoomsListToGrowingSyncMode {
|
||||
}
|
||||
}
|
||||
|
||||
struct AddInvitesList;
|
||||
|
||||
#[async_trait]
|
||||
impl Action for AddInvitesList {
|
||||
async fn run(&self, sliding_sync: &SlidingSync) -> Result<(), Error> {
|
||||
sliding_sync
|
||||
.add_list(
|
||||
SlidingSyncList::builder(INVITES_LIST_NAME)
|
||||
.sync_mode(SlidingSyncMode::new_growing(100))
|
||||
.timeline_limit(0)
|
||||
.required_state(vec![
|
||||
(StateEventType::RoomAvatar, "".to_owned()),
|
||||
(StateEventType::RoomEncryption, "".to_owned()),
|
||||
(StateEventType::RoomMember, "$ME".to_owned()),
|
||||
(StateEventType::RoomCanonicalAlias, "".to_owned()),
|
||||
])
|
||||
.filters(Some(assign!(SyncRequestListFilters::default(), {
|
||||
is_invite: Some(true),
|
||||
is_tombstoned: Some(false),
|
||||
not_room_types: vec!["m.space".to_owned()],
|
||||
|
||||
}))),
|
||||
)
|
||||
.await
|
||||
.map_err(Error::SlidingSync)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Type alias to represent one action.
|
||||
type OneAction = Box<dyn Action + Send + Sync>;
|
||||
|
||||
@@ -169,7 +200,7 @@ macro_rules! actions {
|
||||
impl Actions {
|
||||
actions! {
|
||||
none => [],
|
||||
first_rooms_are_loaded => [SetAllRoomsListToGrowingSyncMode, AddVisibleRoomsList],
|
||||
first_rooms_are_loaded => [SetAllRoomsListToGrowingSyncMode, AddVisibleRoomsList, AddInvitesList],
|
||||
refresh_lists => [SetAllRoomsListToGrowingSyncMode],
|
||||
}
|
||||
|
||||
@@ -303,4 +334,29 @@ mod tests {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
async fn test_action_add_invitess_list() -> Result<(), Error> {
|
||||
let room_list = new_room_list().await?;
|
||||
let sliding_sync = room_list.sliding_sync();
|
||||
|
||||
// List is absent.
|
||||
assert_eq!(sliding_sync.on_list(INVITES_LIST_NAME, |_list| ready(())).await, None);
|
||||
|
||||
// Run the action!
|
||||
AddInvitesList.run(sliding_sync).await?;
|
||||
|
||||
// List is present!
|
||||
assert_eq!(
|
||||
sliding_sync
|
||||
.on_list(INVITES_LIST_NAME, |list| ready(matches!(
|
||||
list.sync_mode(),
|
||||
SlidingSyncMode::Growing { batch_size, .. } if batch_size == 100
|
||||
)))
|
||||
.await,
|
||||
Some(true)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use matrix_sdk_test::async_test;
|
||||
use matrix_sdk_ui::{
|
||||
room_list::{
|
||||
EntriesLoadingState, Error, Input, RoomListEntry, State, ALL_ROOMS_LIST_NAME as ALL_ROOMS,
|
||||
VISIBLE_ROOMS_LIST_NAME as VISIBLE_ROOMS,
|
||||
INVITES_LIST_NAME as INVITES, VISIBLE_ROOMS_LIST_NAME as VISIBLE_ROOMS,
|
||||
},
|
||||
timeline::{TimelineItem, VirtualTimelineItem},
|
||||
RoomList,
|
||||
@@ -326,6 +326,22 @@ async fn test_sync_from_init_to_enjoy() -> Result<(), Error> {
|
||||
"sort": ["by_recency", "by_name"],
|
||||
"timeline_limit": 20,
|
||||
},
|
||||
INVITES: {
|
||||
"ranges": [[0, 99]],
|
||||
"required_state": [
|
||||
["m.room.avatar", ""],
|
||||
["m.room.encryption", ""],
|
||||
["m.room.member", "$ME"],
|
||||
["m.room.canonical_alias", ""],
|
||||
],
|
||||
"filters": {
|
||||
"is_invite": true,
|
||||
"is_tombstoned": false,
|
||||
"not_room_types": ["m.space"],
|
||||
},
|
||||
"sort": ["by_recency", "by_name"],
|
||||
"timeline_limit": 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
respond with = {
|
||||
@@ -341,6 +357,10 @@ async fn test_sync_from_init_to_enjoy() -> Result<(), Error> {
|
||||
"count": 0,
|
||||
"ops": [],
|
||||
},
|
||||
INVITES: {
|
||||
"count": 2,
|
||||
"ops": [],
|
||||
},
|
||||
},
|
||||
"rooms": {
|
||||
// let's ignore them for now
|
||||
@@ -366,6 +386,9 @@ async fn test_sync_from_init_to_enjoy() -> Result<(), Error> {
|
||||
VISIBLE_ROOMS: {
|
||||
"ranges": [[0, 19]],
|
||||
},
|
||||
INVITES: {
|
||||
"ranges": [[0, 1]],
|
||||
}
|
||||
},
|
||||
},
|
||||
respond with = {
|
||||
@@ -381,6 +404,10 @@ async fn test_sync_from_init_to_enjoy() -> Result<(), Error> {
|
||||
"count": 0,
|
||||
"ops": [],
|
||||
},
|
||||
INVITES: {
|
||||
"count": 3,
|
||||
"ops": [],
|
||||
},
|
||||
},
|
||||
"rooms": {
|
||||
// let's ignore them for now
|
||||
@@ -401,6 +428,9 @@ async fn test_sync_from_init_to_enjoy() -> Result<(), Error> {
|
||||
VISIBLE_ROOMS: {
|
||||
"ranges": [[0, 19]],
|
||||
},
|
||||
INVITES: {
|
||||
"ranges": [[0, 2]],
|
||||
},
|
||||
},
|
||||
},
|
||||
respond with = {
|
||||
@@ -416,6 +446,10 @@ async fn test_sync_from_init_to_enjoy() -> Result<(), Error> {
|
||||
"count": 0,
|
||||
"ops": [],
|
||||
},
|
||||
INVITES: {
|
||||
"count": 0,
|
||||
"ops": [],
|
||||
}
|
||||
},
|
||||
"rooms": {
|
||||
// let's ignore them for now
|
||||
@@ -434,7 +468,10 @@ async fn test_sync_from_init_to_enjoy() -> Result<(), Error> {
|
||||
"ranges": [[0, 199]],
|
||||
},
|
||||
VISIBLE_ROOMS: {
|
||||
"ranges": [],
|
||||
"ranges": [[0, 19]],
|
||||
},
|
||||
INVITES: {
|
||||
"ranges": [[0, 0]],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -451,6 +488,10 @@ async fn test_sync_from_init_to_enjoy() -> Result<(), Error> {
|
||||
"count": 0,
|
||||
"ops": [],
|
||||
},
|
||||
INVITES: {
|
||||
"count": 0,
|
||||
"ops": [],
|
||||
},
|
||||
},
|
||||
"rooms": {
|
||||
// let's ignore them for now
|
||||
@@ -466,8 +507,8 @@ async fn test_sync_from_init_to_enjoy() -> Result<(), Error> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
#[async_test]
|
||||
|
||||
#[async_test]
|
||||
async fn test_sync_resumes_from_previous_state() -> Result<(), Error> {
|
||||
let (server, room_list) = new_room_list().await?;
|
||||
|
||||
@@ -515,6 +556,9 @@ async fn test_sync_resumes_from_previous_state() -> Result<(), Error> {
|
||||
VISIBLE_ROOMS: {
|
||||
"ranges": [[0, 19]],
|
||||
},
|
||||
INVITES: {
|
||||
"ranges": [[0, 99]],
|
||||
},
|
||||
},
|
||||
},
|
||||
respond with = {
|
||||
@@ -528,6 +572,10 @@ async fn test_sync_resumes_from_previous_state() -> Result<(), Error> {
|
||||
"count": 0,
|
||||
"ops": [],
|
||||
},
|
||||
INVITES: {
|
||||
"count": 0,
|
||||
"ops": [],
|
||||
},
|
||||
},
|
||||
"rooms": {},
|
||||
},
|
||||
@@ -550,6 +598,9 @@ async fn test_sync_resumes_from_previous_state() -> Result<(), Error> {
|
||||
VISIBLE_ROOMS: {
|
||||
"ranges": [[0, 19]],
|
||||
},
|
||||
INVITES: {
|
||||
"ranges": [[0, 0]],
|
||||
},
|
||||
},
|
||||
},
|
||||
respond with = {
|
||||
@@ -563,6 +614,10 @@ async fn test_sync_resumes_from_previous_state() -> Result<(), Error> {
|
||||
"count": 0,
|
||||
"ops": [],
|
||||
},
|
||||
INVITES: {
|
||||
"count": 0,
|
||||
"ops": [],
|
||||
},
|
||||
},
|
||||
"rooms": {},
|
||||
},
|
||||
@@ -644,6 +699,10 @@ async fn test_sync_resumes_from_terminated() -> Result<(), Error> {
|
||||
// Hello new list.
|
||||
"ranges": [[0, 19]],
|
||||
},
|
||||
INVITES: {
|
||||
// Hello new list.
|
||||
"ranges": [[0, 99]],
|
||||
},
|
||||
},
|
||||
},
|
||||
respond with = (code 400) {
|
||||
@@ -677,6 +736,10 @@ async fn test_sync_resumes_from_terminated() -> Result<(), Error> {
|
||||
// We have set a viewport, which reflects here.
|
||||
"ranges": [[5, 10]],
|
||||
},
|
||||
INVITES: {
|
||||
// The range hasn't been modified due to previous error.
|
||||
"ranges": [[0, 99]],
|
||||
},
|
||||
},
|
||||
},
|
||||
respond with = {
|
||||
@@ -685,6 +748,9 @@ async fn test_sync_resumes_from_terminated() -> Result<(), Error> {
|
||||
ALL_ROOMS: {
|
||||
"count": 110,
|
||||
},
|
||||
INVITES: {
|
||||
"count": 3,
|
||||
}
|
||||
},
|
||||
"rooms": {},
|
||||
},
|
||||
@@ -706,6 +772,10 @@ async fn test_sync_resumes_from_terminated() -> Result<(), Error> {
|
||||
// Despites the error, the range is kept.
|
||||
"ranges": [[5, 10]],
|
||||
},
|
||||
INVITES: {
|
||||
// Despites the error, the range has made progress.
|
||||
"ranges": [[0, 2]],
|
||||
},
|
||||
},
|
||||
},
|
||||
respond with = (code 400) {
|
||||
@@ -735,6 +805,10 @@ async fn test_sync_resumes_from_terminated() -> Result<(), Error> {
|
||||
// Despites the error, the range is kept.
|
||||
"ranges": [[5, 10]],
|
||||
},
|
||||
INVITES: {
|
||||
// Despites the error, the range is kept.
|
||||
"ranges": [[0, 2]],
|
||||
}
|
||||
},
|
||||
},
|
||||
respond with = {
|
||||
@@ -743,6 +817,9 @@ async fn test_sync_resumes_from_terminated() -> Result<(), Error> {
|
||||
ALL_ROOMS: {
|
||||
"count": 110,
|
||||
},
|
||||
INVITES: {
|
||||
"count": 0,
|
||||
},
|
||||
},
|
||||
"rooms": {},
|
||||
},
|
||||
@@ -763,6 +840,10 @@ async fn test_sync_resumes_from_terminated() -> Result<(), Error> {
|
||||
// No error. The range is still here.
|
||||
"ranges": [[5, 10]],
|
||||
},
|
||||
INVITES: {
|
||||
// The range is making progress.
|
||||
"ranges": [[0, 0]],
|
||||
},
|
||||
},
|
||||
},
|
||||
respond with = {
|
||||
@@ -792,6 +873,10 @@ async fn test_sync_resumes_from_terminated() -> Result<(), Error> {
|
||||
// The range is still here.
|
||||
"ranges": [[5, 10]],
|
||||
},
|
||||
INVITES: {
|
||||
// The range is kept as it was.
|
||||
"ranges": [[0, 0]],
|
||||
},
|
||||
},
|
||||
},
|
||||
respond with = (code 400) {
|
||||
@@ -823,6 +908,10 @@ async fn test_sync_resumes_from_terminated() -> Result<(), Error> {
|
||||
// The range is still here.
|
||||
"ranges": [[5, 10]],
|
||||
},
|
||||
INVITES: {
|
||||
// The range is kept as it was.
|
||||
"ranges": [[0, 0]],
|
||||
},
|
||||
},
|
||||
},
|
||||
respond with = {
|
||||
@@ -905,7 +994,7 @@ async fn test_entries_stream() -> Result<(), Error> {
|
||||
set[1] [ F("!r1:bar.org") ];
|
||||
set[2] [ F("!r2:bar.org") ];
|
||||
pending;
|
||||
}
|
||||
};
|
||||
|
||||
sync_then_assert_request_and_fake_response! {
|
||||
[server, room_list, sync]
|
||||
@@ -913,13 +1002,14 @@ async fn test_entries_stream() -> Result<(), Error> {
|
||||
assert request = {
|
||||
"lists": {
|
||||
ALL_ROOMS: {
|
||||
"ranges": [
|
||||
[0, 9],
|
||||
],
|
||||
"ranges": [[0, 9]],
|
||||
},
|
||||
VISIBLE_ROOMS: {
|
||||
"ranges": [[0, 19]],
|
||||
},
|
||||
INVITES: {
|
||||
"ranges": [[0, 99]],
|
||||
},
|
||||
},
|
||||
},
|
||||
respond with = {
|
||||
@@ -939,15 +1029,15 @@ async fn test_entries_stream() -> Result<(), Error> {
|
||||
{
|
||||
"op": "INSERT",
|
||||
"index": 0,
|
||||
"room_id": "!r3:bar.org"
|
||||
"room_id": "!r3:bar.org",
|
||||
},
|
||||
],
|
||||
},
|
||||
VISIBLE_ROOMS: {
|
||||
"count": 0,
|
||||
"ops": [
|
||||
// let's ignore them for now
|
||||
],
|
||||
},
|
||||
INVITES: {
|
||||
"count": 0,
|
||||
},
|
||||
},
|
||||
"rooms": {
|
||||
@@ -966,7 +1056,7 @@ async fn test_entries_stream() -> Result<(), Error> {
|
||||
remove[0];
|
||||
insert[0] [ F("!r3:bar.org") ];
|
||||
pending;
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1046,6 +1136,9 @@ async fn test_entries_stream_with_updated_filter() -> Result<(), Error> {
|
||||
VISIBLE_ROOMS: {
|
||||
"ranges": [[0, 19]],
|
||||
},
|
||||
INVITES: {
|
||||
"ranges": [[0, 99]],
|
||||
},
|
||||
},
|
||||
},
|
||||
respond with = {
|
||||
@@ -1068,9 +1161,9 @@ async fn test_entries_stream_with_updated_filter() -> Result<(), Error> {
|
||||
},
|
||||
VISIBLE_ROOMS: {
|
||||
"count": 0,
|
||||
"ops": [
|
||||
// let's ignore them for now
|
||||
],
|
||||
},
|
||||
INVITES: {
|
||||
"count": 0,
|
||||
},
|
||||
},
|
||||
"rooms": {
|
||||
@@ -1109,6 +1202,162 @@ async fn test_entries_stream_with_updated_filter() -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
async fn test_invites_stream() -> Result<(), Error> {
|
||||
let (server, room_list) = new_room_list().await?;
|
||||
|
||||
let sync = room_list.sync();
|
||||
pin_mut!(sync);
|
||||
|
||||
// The invites aren't accessible yet.
|
||||
assert!(room_list.invites().await.is_err());
|
||||
|
||||
sync_then_assert_request_and_fake_response! {
|
||||
[server, room_list, sync]
|
||||
states = Init => FirstRooms,
|
||||
assert request = {
|
||||
"lists": {
|
||||
ALL_ROOMS: {
|
||||
"ranges": [[0, 19]],
|
||||
},
|
||||
},
|
||||
},
|
||||
respond with = {
|
||||
"pos": "0",
|
||||
"lists": {
|
||||
ALL_ROOMS: {
|
||||
"count": 0,
|
||||
},
|
||||
},
|
||||
"rooms": {},
|
||||
},
|
||||
};
|
||||
|
||||
// The invites aren't accessible yet.
|
||||
assert!(room_list.invites().await.is_err());
|
||||
|
||||
let room_id_0 = room_id!("!r0:bar.org");
|
||||
|
||||
sync_then_assert_request_and_fake_response! {
|
||||
[server, room_list, sync]
|
||||
states = FirstRooms => AllRooms,
|
||||
assert request = {
|
||||
"lists": {
|
||||
ALL_ROOMS: {
|
||||
"ranges": [[0, 0]],
|
||||
},
|
||||
VISIBLE_ROOMS: {
|
||||
"ranges": [[0, 19]],
|
||||
},
|
||||
INVITES: {
|
||||
"ranges": [[0, 99]],
|
||||
},
|
||||
},
|
||||
},
|
||||
respond with = {
|
||||
"pos": "1",
|
||||
"lists": {
|
||||
ALL_ROOMS: {
|
||||
"count": 0,
|
||||
},
|
||||
VISIBLE_ROOMS: {
|
||||
"count": 0,
|
||||
},
|
||||
INVITES: {
|
||||
"count": 1,
|
||||
"ops": [
|
||||
{
|
||||
"op": "SYNC",
|
||||
"range": [0, 0],
|
||||
"room_ids": [
|
||||
room_id_0,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
"rooms": {
|
||||
room_id_0: {
|
||||
"name": "Invitation for Room #0",
|
||||
"initial": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
let (previous_invites, invites_stream) = room_list.invites().await?;
|
||||
pin_mut!(invites_stream);
|
||||
|
||||
assert_eq!(previous_invites.len(), 1);
|
||||
assert_matches!(&previous_invites[0], RoomListEntry::Filled(room_id) => {
|
||||
assert_eq!(room_id, room_id_0);
|
||||
});
|
||||
|
||||
assert_entries_stream! {
|
||||
[invites_stream]
|
||||
pending;
|
||||
};
|
||||
|
||||
sync_then_assert_request_and_fake_response! {
|
||||
[server, room_list, sync]
|
||||
states = AllRooms => CarryOn,
|
||||
assert request = {
|
||||
"lists": {
|
||||
ALL_ROOMS: {
|
||||
"ranges": [[0, 0]],
|
||||
},
|
||||
VISIBLE_ROOMS: {
|
||||
"ranges": [[0, 19]],
|
||||
},
|
||||
INVITES: {
|
||||
"ranges": [[0, 0]],
|
||||
},
|
||||
},
|
||||
},
|
||||
respond with = {
|
||||
"pos": "2",
|
||||
"lists": {
|
||||
ALL_ROOMS: {
|
||||
"count": 0,
|
||||
},
|
||||
VISIBLE_ROOMS: {
|
||||
"count": 0,
|
||||
},
|
||||
INVITES: {
|
||||
"count": 1,
|
||||
"ops": [
|
||||
{
|
||||
"op": "DELETE",
|
||||
"index": 0,
|
||||
},
|
||||
{
|
||||
|
||||
"op": "INSERT",
|
||||
"index": 0,
|
||||
"room_id": "!r1:bar.org",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
"rooms": {
|
||||
"!r1:bar.org": {
|
||||
"name": "Invitation for Room #1",
|
||||
"initial": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
assert_entries_stream! {
|
||||
[invites_stream]
|
||||
remove[0];
|
||||
insert[0] [ F("!r1:bar.org") ];
|
||||
pending;
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
async fn test_room() -> Result<(), Error> {
|
||||
let (server, room_list) = new_room_list().await?;
|
||||
@@ -1634,6 +1883,9 @@ async fn test_input_viewport() -> Result<(), Error> {
|
||||
"ranges": [[0, 19]],
|
||||
"timeline_limit": 20,
|
||||
},
|
||||
INVITES: {
|
||||
"ranges": [[0, 99]],
|
||||
},
|
||||
},
|
||||
},
|
||||
respond with = {
|
||||
@@ -1657,6 +1909,9 @@ async fn test_input_viewport() -> Result<(), Error> {
|
||||
"ranges": [[10, 15], [20, 25]],
|
||||
"timeline_limit": 20,
|
||||
},
|
||||
INVITES: {
|
||||
"ranges": [[0, 99]],
|
||||
},
|
||||
},
|
||||
},
|
||||
respond with = {
|
||||
|
||||
Reference in New Issue
Block a user