matrix_sdk/sliding_sync/list/
builder.rs1use std::{
4 convert::identity,
5 fmt,
6 sync::{Arc, RwLock as StdRwLock},
7};
8
9use eyeball::SharedObservable;
10use ruma::{api::client::sync::sync_events::v5 as http, events::StateEventType};
11use tokio::sync::broadcast::Sender;
12
13use super::{
14 super::SlidingSyncInternalMessage, Bound, SlidingSyncList, SlidingSyncListCachePolicy,
15 SlidingSyncListInner, SlidingSyncListLoadingState, SlidingSyncListRequestGenerator,
16 SlidingSyncListStickyParameters, SlidingSyncMode,
17};
18use crate::{
19 Client,
20 sliding_sync::{cache::restore_sliding_sync_list, sticky_parameters::SlidingSyncStickyManager},
21};
22
23#[derive(Clone)]
25struct SlidingSyncListCachedData {
26 maximum_number_of_rooms: Option<u32>,
30}
31
32#[derive(Clone)]
34pub struct SlidingSyncListBuilder {
35 sync_mode: SlidingSyncMode,
36 #[cfg(not(target_family = "wasm"))]
37 requires_timeout: Arc<dyn Fn(&SlidingSyncListRequestGenerator) -> bool + Send + Sync>,
38 #[cfg(target_family = "wasm")]
39 requires_timeout: Arc<dyn Fn(&SlidingSyncListRequestGenerator) -> bool>,
40 required_state: Vec<(StateEventType, String)>,
41 filters: Option<http::request::ListFilters>,
42 timeline_limit: Bound,
43 pub(crate) name: String,
44
45 cache_policy: SlidingSyncListCachePolicy,
47
48 reloaded_cached_data: Option<SlidingSyncListCachedData>,
51
52 #[cfg(not(target_family = "wasm"))]
53 once_built: Arc<Box<dyn Fn(SlidingSyncList) -> SlidingSyncList + Send + Sync>>,
54 #[cfg(target_family = "wasm")]
55 once_built: Arc<Box<dyn Fn(SlidingSyncList) -> SlidingSyncList>>,
56}
57
58#[cfg(not(tarpaulin_include))]
59impl fmt::Debug for SlidingSyncListBuilder {
60 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
61 formatter
63 .debug_struct("SlidingSyncListBuilder")
64 .field("sync_mode", &self.sync_mode)
65 .field("required_state", &self.required_state)
66 .field("filters", &self.filters)
67 .field("timeline_limit", &self.timeline_limit)
68 .field("name", &self.name)
69 .finish_non_exhaustive()
70 }
71}
72
73impl SlidingSyncListBuilder {
74 pub(super) fn new(name: impl Into<String>) -> Self {
75 Self {
76 sync_mode: SlidingSyncMode::default(),
77 requires_timeout: Arc::new(|request_generator| request_generator.is_fully_loaded()),
78 required_state: vec![
79 (StateEventType::RoomEncryption, "".to_owned()),
80 (StateEventType::RoomTombstone, "".to_owned()),
81 ],
82 filters: None,
83 timeline_limit: 1,
84 name: name.into(),
85 reloaded_cached_data: None,
86 cache_policy: SlidingSyncListCachePolicy::Disabled,
87 once_built: Arc::new(Box::new(identity)),
88 }
89 }
90
91 #[cfg(not(target_family = "wasm"))]
97 pub fn once_built<C>(mut self, callback: C) -> Self
98 where
99 C: Fn(SlidingSyncList) -> SlidingSyncList + Send + Sync + 'static,
100 {
101 self.once_built = Arc::new(Box::new(callback));
102 self
103 }
104
105 #[cfg(target_family = "wasm")]
111 pub fn once_built<C>(mut self, callback: C) -> Self
112 where
113 C: Fn(SlidingSyncList) -> SlidingSyncList + 'static,
114 {
115 self.once_built = Arc::new(Box::new(callback));
116 self
117 }
118
119 pub fn sync_mode(mut self, value: impl Into<SlidingSyncMode>) -> Self {
121 self.sync_mode = value.into();
122 self
123 }
124
125 #[cfg(not(target_family = "wasm"))]
131 pub fn requires_timeout<F>(mut self, f: F) -> Self
132 where
133 F: Fn(&SlidingSyncListRequestGenerator) -> bool + Send + Sync + 'static,
134 {
135 self.requires_timeout = Arc::new(f);
136 self
137 }
138
139 #[cfg(target_family = "wasm")]
145 pub fn requires_timeout<F>(mut self, f: F) -> Self
146 where
147 F: Fn(&SlidingSyncListRequestGenerator) -> bool + 'static,
148 {
149 self.requires_timeout = Arc::new(f);
150 self
151 }
152
153 pub fn required_state(mut self, value: Vec<(StateEventType, String)>) -> Self {
155 self.required_state = value;
156 self
157 }
158
159 pub fn filters(mut self, value: Option<http::request::ListFilters>) -> Self {
161 self.filters = value;
162 self
163 }
164
165 pub fn timeline_limit(mut self, timeline_limit: Bound) -> Self {
167 self.timeline_limit = timeline_limit;
168 self
169 }
170
171 pub fn no_timeline_limit(mut self) -> Self {
173 self.timeline_limit = 0;
174 self
175 }
176
177 pub(in super::super) async fn set_cached_and_reload(
183 &mut self,
184 client: &Client,
185 storage_key: &str,
186 ) -> crate::Result<()> {
187 self.cache_policy = SlidingSyncListCachePolicy::Enabled;
188
189 if let Some(frozen_list) =
190 restore_sliding_sync_list(client.state_store(), storage_key, &self.name).await?
191 {
192 assert!(
193 self.reloaded_cached_data.is_none(),
194 "can't call `set_cached_and_reload` twice"
195 );
196 self.reloaded_cached_data = Some(SlidingSyncListCachedData {
197 maximum_number_of_rooms: frozen_list.maximum_number_of_rooms,
198 });
199 Ok(())
200 } else {
201 Ok(())
202 }
203 }
204
205 pub(in super::super) fn build(
207 self,
208 sliding_sync_internal_channel_sender: Sender<SlidingSyncInternalMessage>,
209 ) -> SlidingSyncList {
210 let list = SlidingSyncList {
211 inner: Arc::new(SlidingSyncListInner {
212 #[cfg(any(test, feature = "testing"))]
213 sync_mode: StdRwLock::new(self.sync_mode.clone()),
214
215 sticky: StdRwLock::new(SlidingSyncStickyManager::new(
217 SlidingSyncListStickyParameters::new(self.required_state, self.filters),
218 )),
219 timeline_limit: StdRwLock::new(self.timeline_limit),
220 name: self.name,
221 cache_policy: self.cache_policy,
222 requires_timeout: self.requires_timeout,
223
224 request_generator: StdRwLock::new(SlidingSyncListRequestGenerator::new(
226 self.sync_mode,
227 )),
228
229 state: SharedObservable::new(Default::default()),
232 maximum_number_of_rooms: SharedObservable::new(None),
233
234 sliding_sync_internal_channel_sender,
236 }),
237 };
238
239 let once_built = self.once_built;
240
241 let list = once_built(list);
242
243 if let Some(SlidingSyncListCachedData { maximum_number_of_rooms }) =
251 self.reloaded_cached_data
252 {
253 list.inner.state.set(SlidingSyncListLoadingState::Preloaded);
255
256 list.inner.maximum_number_of_rooms.set(maximum_number_of_rooms);
258 }
259
260 list
261 }
262}