Skip to content

Commit

Permalink
sdk-ui: make SlidingSyncRoom not needed in `RoomListItem::default_r…
Browse files Browse the repository at this point in the history
…oom_timeline_builder`.

Having initial items shouldn't be mandatory to create a timeline, the timeline can also be empty.
  • Loading branch information
jmartinesp committed Sep 12, 2024
1 parent cce3279 commit 014e302
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 44 deletions.
38 changes: 22 additions & 16 deletions crates/matrix-sdk-ui/src/room_list_service/room.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use std::{ops::Deref, sync::Arc};
use async_once_cell::OnceCell as AsyncOnceCell;
use matrix_sdk::SlidingSync;
use ruma::RoomId;
use tracing::info;

use super::Error;
use crate::{
Expand Down Expand Up @@ -150,27 +151,32 @@ impl Room {
}

/// Create a new [`TimelineBuilder`] with the default configuration.
///
/// If the room was synced before some initial events will be added to the
/// [`TimelineBuilder`].
pub async fn default_room_timeline_builder(&self) -> Result<TimelineBuilder, Error> {
// TODO we can remove this once the event cache handles his own cache.

let sliding_sync_room =
let sliding_sync_room = self.inner.sliding_sync.get_room(self.inner.room.room_id()).await;

if let Some(sliding_sync_room) = sliding_sync_room {
self.inner
.sliding_sync
.get_room(self.inner.room.room_id())
.room
.client()
.event_cache()
.add_initial_events(
self.inner.room.room_id(),
sliding_sync_room.timeline_queue().iter().cloned().collect(),
sliding_sync_room.prev_batch(),
)
.await
.ok_or_else(|| Error::RoomNotFound(self.inner.room.room_id().to_owned()))?;

self.inner
.room
.client()
.event_cache()
.add_initial_events(
self.inner.room.room_id(),
sliding_sync_room.timeline_queue().iter().cloned().collect(),
sliding_sync_room.prev_batch(),
)
.await
.map_err(Error::EventCache)?;
.map_err(Error::EventCache)?;
} else {
info!(
"No cached sliding sync room found for `{}`, the timeline will be empty.",
self.room_id()
);
}

Ok(Timeline::builder(&self.inner.room).track_read_marker_and_receipts())
}
Expand Down
33 changes: 32 additions & 1 deletion crates/matrix-sdk-ui/tests/integration/room_list_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@ use matrix_sdk_ui::{
RoomListService,
};
use ruma::{
api::client::room::create_room::v3::Request as CreateRoomRequest,
assign, event_id,
events::{room::message::RoomMessageEventContent, StateEventType},
mxc_uri, room_id, uint,
};
use serde_json::json;
use stream_assert::{assert_next_matches, assert_pending};
use tokio::{spawn, sync::mpsc::channel, task::yield_now};
use wiremock::MockServer;
use wiremock::{
matchers::{header, method, path},
Mock, MockServer, ResponseTemplate,
};

use crate::timeline::sliding_sync::{assert_timeline_stream, timeline_event};

Expand Down Expand Up @@ -2404,6 +2408,33 @@ async fn test_room_timeline() -> Result<(), Error> {
Ok(())
}

#[async_test]
async fn test_room_empty_timeline() {
let (client, server, room_list) = new_room_list_service().await.unwrap();
mock_encryption_state(&server, false).await;

Mock::given(method("POST"))
.and(path("_matrix/client/r0/createRoom"))
.and(header("authorization", "Bearer 1234"))
.respond_with(
ResponseTemplate::new(200).set_body_json(json!({ "room_id": "!example:localhost"})),
)
.mount(&server)
.await;

let room = client.create_room(CreateRoomRequest::default()).await.unwrap();
let room_id = room.room_id().to_owned();

// The room wasn't synced, but it will be available
let room = room_list.room(&room_id).unwrap();
let timeline = room.default_room_timeline_builder().await.unwrap().build().await.unwrap();
let (prev_items, _) = timeline.subscribe().await;

// However, since the room wasn't synced its timeline won't have any initial
// items
assert!(prev_items.is_empty());
}

#[async_test]
async fn test_room_latest_event() -> Result<(), Error> {
let (_, server, room_list) = new_room_list_service().await?;
Expand Down
44 changes: 17 additions & 27 deletions crates/matrix-sdk/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2252,14 +2252,12 @@ impl Client {
if room.is_state_partially_or_fully_synced() {
debug!("Found just created room!");
return room;
} else {
warn!("Room wasn't partially synced, waiting for sync beat to try again");
}
debug!("Room wasn't partially synced, waiting for sync beat to try again");
} else {
warn!("Room wasn't found, waiting for sync beat to try again");
debug!("Room wasn't found, waiting for sync beat to try again");
}
self.inner.sync_beat.listen().await;
debug!("New sync beat found");
}
}
}
Expand Down Expand Up @@ -2310,6 +2308,7 @@ pub(crate) mod tests {
use std::{sync::Arc, time::Duration};

use assert_matches::assert_matches;
use futures_util::FutureExt;
use matrix_sdk_base::{
store::{MemoryStore, StoreConfig},
RoomState,
Expand All @@ -2328,6 +2327,10 @@ pub(crate) mod tests {
owned_room_id, room_id, RoomId, ServerName, UserId,
};
use serde_json::json;
use tokio::{
spawn,
time::{sleep, timeout},
};
use url::Url;
use wiremock::{
matchers::{body_json, header, method, path, query_param_is_missing},
Expand Down Expand Up @@ -2668,7 +2671,7 @@ pub(crate) mod tests {
let client = logged_in_client(None).await;

// Wait for the init tasks to die.
tokio::time::sleep(Duration::from_secs(1)).await;
sleep(Duration::from_secs(1)).await;

let weak_client = WeakClient::from_client(&client);
assert_eq!(weak_client.strong_count(), 1);
Expand All @@ -2691,7 +2694,7 @@ pub(crate) mod tests {
drop(client);

// Give a bit of time for background tasks to die.
tokio::time::sleep(Duration::from_secs(1)).await;
sleep(Duration::from_secs(1)).await;

// The weak client must be the last reference to the client now.
assert_eq!(weak_client.strong_count(), 0);
Expand Down Expand Up @@ -2824,10 +2827,7 @@ pub(crate) mod tests {

client.sync_once(SyncSettings::default()).await.unwrap();

let room =
tokio::time::timeout(Duration::from_secs(1), client.await_room_remote_echo(room_id))
.await
.unwrap();
let room = client.await_room_remote_echo(room_id).now_or_never().unwrap();
assert_eq!(room.room_id(), room_id);
}

Expand Down Expand Up @@ -2857,18 +2857,16 @@ pub(crate) mod tests {

// Perform the /sync request with a delay so it starts after the
// `await_room_remote_echo` call has happened
tokio::spawn({
spawn({
let client = client.clone();
async move {
tokio::time::sleep(Duration::from_millis(100)).await;
sleep(Duration::from_millis(100)).await;
client.sync_once(SyncSettings::default()).await.unwrap();
}
});

let room =
tokio::time::timeout(Duration::from_secs(1), client.await_room_remote_echo(room_id))
.await
.unwrap();
timeout(Duration::from_secs(1), client.await_room_remote_echo(room_id)).await.unwrap();
assert_eq!(room.room_id(), room_id);
}

Expand All @@ -2881,11 +2879,7 @@ pub(crate) mod tests {
let room_id = room_id!("!room:example.org");
// Room is not present so the client won't be able to find it. The call will
// timeout.
let err =
tokio::time::timeout(Duration::from_secs(1), client.await_room_remote_echo(room_id))
.await
.err();
assert!(err.is_some());
timeout(Duration::from_secs(1), client.await_room_remote_echo(room_id)).await.unwrap_err();
}

#[async_test]
Expand Down Expand Up @@ -2913,12 +2907,8 @@ pub(crate) mod tests {
.unwrap();

// Room is locally present, but not synced, the call will timeout
let err = tokio::time::timeout(
Duration::from_secs(1),
client.await_room_remote_echo(room.room_id()),
)
.await
.err();
assert!(err.is_some());
timeout(Duration::from_secs(1), client.await_room_remote_echo(room.room_id()))
.await
.unwrap_err();
}
}

0 comments on commit 014e302

Please sign in to comment.