use std::{
convert::identity,
fmt,
sync::{Arc, RwLock as StdRwLock},
};
use eyeball::{Observable, SharedObservable};
use matrix_sdk_base::sliding_sync::http;
use ruma::events::StateEventType;
use tokio::sync::broadcast::Sender;
use super::{
super::SlidingSyncInternalMessage, Bound, SlidingSyncList, SlidingSyncListCachePolicy,
SlidingSyncListInner, SlidingSyncListLoadingState, SlidingSyncListRequestGenerator,
SlidingSyncListStickyParameters, SlidingSyncMode,
};
use crate::{
sliding_sync::{cache::restore_sliding_sync_list, sticky_parameters::SlidingSyncStickyManager},
Client,
};
#[derive(Clone)]
struct SlidingSyncListCachedData {
maximum_number_of_rooms: Option<u32>,
}
#[derive(Clone)]
pub struct SlidingSyncListBuilder {
sync_mode: SlidingSyncMode,
required_state: Vec<(StateEventType, String)>,
include_heroes: Option<bool>,
filters: Option<http::request::ListFilters>,
timeline_limit: Bound,
pub(crate) name: String,
cache_policy: SlidingSyncListCachePolicy,
reloaded_cached_data: Option<SlidingSyncListCachedData>,
once_built: Arc<Box<dyn Fn(SlidingSyncList) -> SlidingSyncList + Send + Sync>>,
}
#[cfg(not(tarpaulin_include))]
impl fmt::Debug for SlidingSyncListBuilder {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("SlidingSyncListBuilder")
.field("sync_mode", &self.sync_mode)
.field("required_state", &self.required_state)
.field("include_heroes", &self.include_heroes)
.field("filters", &self.filters)
.field("timeline_limit", &self.timeline_limit)
.field("name", &self.name)
.finish_non_exhaustive()
}
}
impl SlidingSyncListBuilder {
pub(super) fn new(name: impl Into<String>) -> Self {
Self {
sync_mode: SlidingSyncMode::default(),
required_state: vec![
(StateEventType::RoomEncryption, "".to_owned()),
(StateEventType::RoomTombstone, "".to_owned()),
],
include_heroes: None,
filters: None,
timeline_limit: 1,
name: name.into(),
reloaded_cached_data: None,
cache_policy: SlidingSyncListCachePolicy::Disabled,
once_built: Arc::new(Box::new(identity)),
}
}
pub fn once_built<C>(mut self, callback: C) -> Self
where
C: Fn(SlidingSyncList) -> SlidingSyncList + Send + Sync + 'static,
{
self.once_built = Arc::new(Box::new(callback));
self
}
pub fn sync_mode(mut self, value: impl Into<SlidingSyncMode>) -> Self {
self.sync_mode = value.into();
self
}
pub fn required_state(mut self, value: Vec<(StateEventType, String)>) -> Self {
self.required_state = value;
self
}
pub fn include_heroes(mut self, value: Option<bool>) -> Self {
self.include_heroes = value;
self
}
pub fn filters(mut self, value: Option<http::request::ListFilters>) -> Self {
self.filters = value;
self
}
pub fn timeline_limit(mut self, timeline_limit: Bound) -> Self {
self.timeline_limit = timeline_limit;
self
}
pub fn no_timeline_limit(mut self) -> Self {
self.timeline_limit = 0;
self
}
pub(in super::super) async fn set_cached_and_reload(
&mut self,
client: &Client,
storage_key: &str,
) -> crate::Result<()> {
self.cache_policy = SlidingSyncListCachePolicy::Enabled;
if let Some(frozen_list) =
restore_sliding_sync_list(client.store(), storage_key, &self.name).await?
{
assert!(
self.reloaded_cached_data.is_none(),
"can't call `set_cached_and_reload` twice"
);
self.reloaded_cached_data = Some(SlidingSyncListCachedData {
maximum_number_of_rooms: frozen_list.maximum_number_of_rooms,
});
Ok(())
} else {
Ok(())
}
}
pub(in super::super) fn build(
self,
sliding_sync_internal_channel_sender: Sender<SlidingSyncInternalMessage>,
) -> SlidingSyncList {
let list = SlidingSyncList {
inner: Arc::new(SlidingSyncListInner {
#[cfg(any(test, feature = "testing"))]
sync_mode: StdRwLock::new(self.sync_mode.clone()),
sticky: StdRwLock::new(SlidingSyncStickyManager::new(
SlidingSyncListStickyParameters::new(
self.required_state,
self.include_heroes,
self.filters,
),
)),
timeline_limit: StdRwLock::new(self.timeline_limit),
name: self.name,
cache_policy: self.cache_policy,
request_generator: StdRwLock::new(SlidingSyncListRequestGenerator::new(
self.sync_mode,
)),
state: StdRwLock::new(Observable::new(Default::default())),
maximum_number_of_rooms: SharedObservable::new(None),
sliding_sync_internal_channel_sender,
}),
};
let once_built = self.once_built;
let list = once_built(list);
if let Some(SlidingSyncListCachedData { maximum_number_of_rooms }) =
self.reloaded_cached_data
{
Observable::set(
&mut list.inner.state.write().unwrap(),
SlidingSyncListLoadingState::Preloaded,
);
list.inner.maximum_number_of_rooms.set(maximum_number_of_rooms);
}
list
}
}