|
14 | 14 |
|
15 | 15 | //! A sub-object for running pagination tasks on a given room.
|
16 | 16 |
|
17 |
| -use std::{sync::Arc, time::Duration}; |
| 17 | +use std::{future::Future, ops::ControlFlow, sync::Arc, time::Duration}; |
18 | 18 |
|
19 | 19 | use eyeball::Subscriber;
|
20 | 20 | use matrix_sdk_base::deserialized_responses::SyncTimelineEvent;
|
@@ -59,17 +59,75 @@ impl RoomPagination {
|
59 | 59 | /// This automatically takes care of waiting for a pagination token from
|
60 | 60 | /// sync, if we haven't done that before.
|
61 | 61 | ///
|
| 62 | + /// The `until` argument is an async closure that returns a [`ControlFlow`] |
| 63 | + /// to decide whether a new pagination must be run or not. It's helpful when |
| 64 | + /// the server replies with e.g. a certain set of events, but we would like |
| 65 | + /// more, or the event we are looking for isn't part of this set: in this |
| 66 | + /// case, `until` returns [`Control::Continue`], otherwise it returns |
| 67 | + /// [`ControlFlow::Break`]. `until` receives [`BackPaginationOutcome`] as |
| 68 | + /// its sole argument. |
| 69 | + /// |
62 | 70 | /// # Errors
|
63 | 71 | ///
|
64 | 72 | /// It may return an error if the pagination token used during
|
65 | 73 | /// back-pagination has disappeared while we started the pagination. In
|
66 | 74 | /// that case, it's desirable to call the method again.
|
67 |
| - #[instrument(skip(self))] |
68 |
| - pub async fn run_backwards(&self, batch_size: u16) -> Result<BackPaginationOutcome> { |
| 75 | + /// |
| 76 | + /// # Example |
| 77 | + /// |
| 78 | + /// To do a single run: |
| 79 | + /// |
| 80 | + /// ```rust |
| 81 | + /// use std::ops::ControlFlow; |
| 82 | + /// |
| 83 | + /// use matrix_sdk::event_cache::{ |
| 84 | + /// BackPaginationOutcome, |
| 85 | + /// RoomPagination, |
| 86 | + /// TimelineHasBeenResetWhilePaginating |
| 87 | + /// }; |
| 88 | + /// |
| 89 | + /// # async fn foo(room_pagination: RoomPagination) { |
| 90 | + /// let result = room_pagination.run_backwards( |
| 91 | + /// 42, |
| 92 | + /// |BackPaginationOutcome { events, reached_start }, |
| 93 | + /// _timeline_has_been_reset: TimelineHasBeenResetWhilePaginating| async move { |
| 94 | + /// // Do something with `events` and `reached_start` maybe? |
| 95 | + /// let _ = events; |
| 96 | + /// let _ = reached_start; |
| 97 | + /// |
| 98 | + /// ControlFlow::Break(()) |
| 99 | + /// } |
| 100 | + /// ).await; |
| 101 | + /// # } |
| 102 | + #[instrument(skip(self, until))] |
| 103 | + pub async fn run_backwards<Until, Break, UntilFuture>( |
| 104 | + &self, |
| 105 | + batch_size: u16, |
| 106 | + mut until: Until, |
| 107 | + ) -> Result<Break> |
| 108 | + where |
| 109 | + Until: FnMut(BackPaginationOutcome, TimelineHasBeenResetWhilePaginating) -> UntilFuture, |
| 110 | + UntilFuture: Future<Output = ControlFlow<Break, ()>>, |
| 111 | + { |
| 112 | + let mut timeline_has_been_reset = TimelineHasBeenResetWhilePaginating::No; |
| 113 | + |
69 | 114 | loop {
|
70 |
| - if let Some(result) = self.run_backwards_impl(batch_size).await? { |
71 |
| - return Ok(result); |
| 115 | + if let Some(outcome) = self.run_backwards_impl(batch_size).await? { |
| 116 | + match until(outcome, timeline_has_been_reset).await { |
| 117 | + ControlFlow::Continue(()) => { |
| 118 | + trace!("back-pagination continues"); |
| 119 | + |
| 120 | + timeline_has_been_reset = TimelineHasBeenResetWhilePaginating::No; |
| 121 | + |
| 122 | + continue; |
| 123 | + } |
| 124 | + |
| 125 | + ControlFlow::Break(value) => return Ok(value), |
| 126 | + } |
72 | 127 | }
|
| 128 | + |
| 129 | + timeline_has_been_reset = TimelineHasBeenResetWhilePaginating::Yes; |
| 130 | + |
73 | 131 | debug!("back-pagination has been internally restarted because of a timeline reset.");
|
74 | 132 | }
|
75 | 133 | }
|
@@ -259,6 +317,16 @@ impl RoomPagination {
|
259 | 317 | }
|
260 | 318 | }
|
261 | 319 |
|
| 320 | +/// A type representing whether the timeline has been reset. |
| 321 | +#[derive(Debug)] |
| 322 | +pub enum TimelineHasBeenResetWhilePaginating { |
| 323 | + /// The timeline has been reset. |
| 324 | + Yes, |
| 325 | + |
| 326 | + /// The timeline has not been reset. |
| 327 | + No, |
| 328 | +} |
| 329 | + |
262 | 330 | #[cfg(test)]
|
263 | 331 | mod tests {
|
264 | 332 | // Those tests require time to work, and it does not on wasm32.
|
|
0 commit comments