matrix_sdk/sliding_sync/list/
builder.rs1use std::{
4 convert::identity,
5 fmt,
6 sync::{Arc, RwLock as StdRwLock},
7};
8
9use eyeball::{Observable, 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 sliding_sync::{cache::restore_sliding_sync_list, sticky_parameters::SlidingSyncStickyManager},
20 Client,
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 required_state: Vec<(StateEventType, String)>,
37 filters: Option<http::request::ListFilters>,
38 timeline_limit: Bound,
39 pub(crate) name: String,
40
41 cache_policy: SlidingSyncListCachePolicy,
43
44 reloaded_cached_data: Option<SlidingSyncListCachedData>,
47
48 #[cfg(not(target_family = "wasm"))]
49 once_built: Arc<Box<dyn Fn(SlidingSyncList) -> SlidingSyncList + Send + Sync>>,
50 #[cfg(target_family = "wasm")]
51 once_built: Arc<Box<dyn Fn(SlidingSyncList) -> SlidingSyncList>>,
52}
53
54#[cfg(not(tarpaulin_include))]
55impl fmt::Debug for SlidingSyncListBuilder {
56 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
57 formatter
59 .debug_struct("SlidingSyncListBuilder")
60 .field("sync_mode", &self.sync_mode)
61 .field("required_state", &self.required_state)
62 .field("filters", &self.filters)
63 .field("timeline_limit", &self.timeline_limit)
64 .field("name", &self.name)
65 .finish_non_exhaustive()
66 }
67}
68
69impl SlidingSyncListBuilder {
70 pub(super) fn new(name: impl Into<String>) -> Self {
71 Self {
72 sync_mode: SlidingSyncMode::default(),
73 required_state: vec![
74 (StateEventType::RoomEncryption, "".to_owned()),
75 (StateEventType::RoomTombstone, "".to_owned()),
76 ],
77 filters: None,
78 timeline_limit: 1,
79 name: name.into(),
80 reloaded_cached_data: None,
81 cache_policy: SlidingSyncListCachePolicy::Disabled,
82 once_built: Arc::new(Box::new(identity)),
83 }
84 }
85
86 #[cfg(not(target_family = "wasm"))]
92 pub fn once_built<C>(mut self, callback: C) -> Self
93 where
94 C: Fn(SlidingSyncList) -> SlidingSyncList + Send + Sync + 'static,
95 {
96 self.once_built = Arc::new(Box::new(callback));
97 self
98 }
99
100 #[cfg(target_family = "wasm")]
106 pub fn once_built<C>(mut self, callback: C) -> Self
107 where
108 C: Fn(SlidingSyncList) -> SlidingSyncList + 'static,
109 {
110 self.once_built = Arc::new(Box::new(callback));
111 self
112 }
113
114 pub fn sync_mode(mut self, value: impl Into<SlidingSyncMode>) -> Self {
116 self.sync_mode = value.into();
117 self
118 }
119
120 pub fn required_state(mut self, value: Vec<(StateEventType, String)>) -> Self {
122 self.required_state = value;
123 self
124 }
125
126 pub fn filters(mut self, value: Option<http::request::ListFilters>) -> Self {
128 self.filters = value;
129 self
130 }
131
132 pub fn timeline_limit(mut self, timeline_limit: Bound) -> Self {
134 self.timeline_limit = timeline_limit;
135 self
136 }
137
138 pub fn no_timeline_limit(mut self) -> Self {
140 self.timeline_limit = 0;
141 self
142 }
143
144 pub(in super::super) async fn set_cached_and_reload(
150 &mut self,
151 client: &Client,
152 storage_key: &str,
153 ) -> crate::Result<()> {
154 self.cache_policy = SlidingSyncListCachePolicy::Enabled;
155
156 if let Some(frozen_list) =
157 restore_sliding_sync_list(client.state_store(), storage_key, &self.name).await?
158 {
159 assert!(
160 self.reloaded_cached_data.is_none(),
161 "can't call `set_cached_and_reload` twice"
162 );
163 self.reloaded_cached_data = Some(SlidingSyncListCachedData {
164 maximum_number_of_rooms: frozen_list.maximum_number_of_rooms,
165 });
166 Ok(())
167 } else {
168 Ok(())
169 }
170 }
171
172 pub(in super::super) fn build(
174 self,
175 sliding_sync_internal_channel_sender: Sender<SlidingSyncInternalMessage>,
176 ) -> SlidingSyncList {
177 let list = SlidingSyncList {
178 inner: Arc::new(SlidingSyncListInner {
179 #[cfg(any(test, feature = "testing"))]
180 sync_mode: StdRwLock::new(self.sync_mode.clone()),
181
182 sticky: StdRwLock::new(SlidingSyncStickyManager::new(
184 SlidingSyncListStickyParameters::new(self.required_state, self.filters),
185 )),
186 timeline_limit: StdRwLock::new(self.timeline_limit),
187 name: self.name,
188 cache_policy: self.cache_policy,
189
190 request_generator: StdRwLock::new(SlidingSyncListRequestGenerator::new(
192 self.sync_mode,
193 )),
194
195 state: StdRwLock::new(Observable::new(Default::default())),
198 maximum_number_of_rooms: SharedObservable::new(None),
199
200 sliding_sync_internal_channel_sender,
202 }),
203 };
204
205 let once_built = self.once_built;
206
207 let list = once_built(list);
208
209 if let Some(SlidingSyncListCachedData { maximum_number_of_rooms }) =
217 self.reloaded_cached_data
218 {
219 Observable::set(
221 &mut list.inner.state.write().unwrap(),
222 SlidingSyncListLoadingState::Preloaded,
223 );
224
225 list.inner.maximum_number_of_rooms.set(maximum_number_of_rooms);
227 }
228
229 list
230 }
231}