diff --git a/crates/matrix-sdk-ui/src/room_list_service/mod.rs b/crates/matrix-sdk-ui/src/room_list_service/mod.rs index bd6a046b53d..22eb9f0efb2 100644 --- a/crates/matrix-sdk-ui/src/room_list_service/mod.rs +++ b/crates/matrix-sdk-ui/src/room_list_service/mod.rs @@ -220,28 +220,22 @@ impl RoomListService { // returned. If true, only invited rooms are returned. is_invite: None, }))) - .requires_timeout(move |request_generator| { + .requires_timeout(move |_request_generator| { // We want Sliding Sync to apply the poll + network timeout —i.e. to do the // long-polling— in some particular cases. Let's define them. match observable_state.get() { - // These are the states where we want an immediate response from the - // server, with no long-polling. - State::Init - | State::SettingUp - | State::Recovering - | State::Error { .. } - | State::Terminated { .. } => PollTimeout::Some(0), - - // Otherwise we want long-polling if the list is fully-loaded. - State::Running => { - if request_generator.is_fully_loaded() { - // Long-polling. - PollTimeout::Default - } else { - // No long-polling yet. - PollTimeout::Some(0) - } + // The very first request must return immediately so the session can + // be established as fast as possible. + State::Init => PollTimeout::Some(0), + + // Once we have a `pos`, let the server long-poll. If a list change + // still needs to be delivered, the server can answer immediately. + State::SettingUp | State::Recovering | State::Running => { + PollTimeout::Default } + + // Terminal states — included for exhaustiveness. + State::Error { .. } | State::Terminated { .. } => PollTimeout::Some(0), } }), ) @@ -562,7 +556,13 @@ pub enum SyncIndicator { #[cfg(test)] mod tests { - use std::future::ready; + use std::{ + future::ready, + sync::{ + Arc, + atomic::{AtomicUsize, Ordering}, + }, + }; use futures_util::{StreamExt, pin_mut}; use matrix_sdk::{ @@ -677,4 +677,50 @@ mod tests { Ok(()) } + + #[async_test] + async fn test_long_poll_after_first_sync() -> Result<(), Error> { + let (client, server) = new_client().await; + let room_list = RoomListService::new(client).await?; + + let sync = room_list.sync(); + pin_mut!(sync); + + let pos = Arc::new(AtomicUsize::new(0)); + let _mock_guard = Mock::given(SlidingSyncMatcher) + .respond_with(move |_request: &Request| { + let next_pos = pos.fetch_add(1, Ordering::SeqCst).to_string(); + ResponseTemplate::new(200).set_body_json(json!({ + "pos": next_pos, + "lists": { + ALL_ROOMS_LIST_NAME: { + "count": 0, + "ops": [], + }, + }, + "rooms": {}, + })) + }) + .mount_as_scoped(&server) + .await; + + let _ = sync.next().await; + assert_eq!(room_list.state().get(), State::SettingUp); + let _ = sync.next().await; + + let requests = server.received_requests().await.unwrap(); + let second_request = + requests.iter().filter(|request| SlidingSyncMatcher.matches(request)).nth(1).unwrap(); + + assert!( + second_request + .url + .query_pairs() + .any(|(key, value)| key == "timeout" && value == "30000"), + "expected second sync request to enable long-poll timeout, got {:?}", + second_request.url + ); + + Ok(()) + } } diff --git a/crates/matrix-sdk-ui/tests/integration/room_list_service.rs b/crates/matrix-sdk-ui/tests/integration/room_list_service.rs index bd51ea944fc..f7fb5ed4c68 100644 --- a/crates/matrix-sdk-ui/tests/integration/room_list_service.rs +++ b/crates/matrix-sdk-ui/tests/integration/room_list_service.rs @@ -415,8 +415,8 @@ async fn test_sync_all_states() -> Result<(), Error> { states = SettingUp => Running, // The previous `pos`. assert pos Some("0"), - // Still no long-polling because the list isn't fully-loaded. - assert timeout Some(0), + // Long-polling is enabled for all post-init states. + assert timeout Some(30000), assert request >= { "conn_id": "room-list", "lists": { @@ -443,8 +443,8 @@ async fn test_sync_all_states() -> Result<(), Error> { [server, room_list, sync] states = Running => Running, assert pos Some("1"), - // Still no long-polling because the list isn't fully-loaded. - assert timeout Some(0), + // Long-polling is enabled for all post-init states. + assert timeout Some(30000), assert request >= { "conn_id": "room-list", "lists": { @@ -471,9 +471,8 @@ async fn test_sync_all_states() -> Result<(), Error> { [server, room_list, sync] states = Running => Running, assert pos Some("2"), - // Still no long-polling because the list isn't fully-loaded, - // but it's about to be! - assert timeout Some(0), + // Long-polling is enabled for all post-init states. + assert timeout Some(30000), assert request >= { "conn_id": "room-list", "lists": { @@ -500,7 +499,7 @@ async fn test_sync_all_states() -> Result<(), Error> { [server, room_list, sync] states = Running => Running, assert pos Some("3"), - // The list is fully-loaded, we can start long-polling. + // Long-polling is enabled for all post-init states. assert timeout Some(30000), assert request >= { "conn_id": "room-list",