arminius_lib_sync/syncv4/plan/
apply_state.rs1mod tests;
9
10use std::collections::HashMap;
11
12use arminius_lib_db_sync::syncv4::{RoomInfo, RoomState};
13use arminius_lib_model::{
14 syncv4::{RoomConfig, StreamUpperBound},
15 types::StreamId,
16};
17use ruma::OwnedRoomId;
18
19use crate::syncv4::plan::MatchedRoom;
20
21#[derive(Debug)]
25pub enum RoomToSync {
26 Joined {
28 from_stream_id: StreamId,
30 room_config: RoomConfig,
32 initial: bool,
34 },
35 NeverJoined {
37 initial: bool,
39 },
40}
41
42impl RoomToSync {
43 #[must_use]
48 pub fn new_conditional(
49 was_ever_joined: bool,
50 room_config: RoomConfig,
51 sync_room_from: StreamId,
52 initial: bool,
53 ) -> Self {
54 match was_ever_joined {
55 true => RoomToSync::Joined { from_stream_id: sync_room_from, room_config, initial },
56 false => RoomToSync::NeverJoined { initial },
57 }
58 }
59}
60
61#[derive(Debug)]
63pub(super) struct AppliedState {
64 pub(super) rooms_to_sync: HashMap<OwnedRoomId, RoomToSync>,
66 pub(super) stale_rooms: Vec<OwnedRoomId>,
69}
70
71pub(super) fn apply_state(
76 prev_events_stream_id: StreamId,
77 matched_rooms: &HashMap<OwnedRoomId, MatchedRoom>,
78 user_rooms: &HashMap<OwnedRoomId, RoomInfo>,
79 rooms_states: &mut HashMap<OwnedRoomId, RoomState>,
80) -> AppliedState {
81 let rooms_to_sync = mark_rooms_to_sync(prev_events_stream_id, matched_rooms, rooms_states);
82 let stale_rooms =
83 mark_stale_rooms(rooms_states, user_rooms, &rooms_to_sync, prev_events_stream_id);
84
85 AppliedState { rooms_to_sync, stale_rooms }
86}
87
88fn mark_rooms_to_sync(
93 prev_events_stream_id: StreamId,
94 matched_rooms: &HashMap<OwnedRoomId, MatchedRoom>,
95 rooms_states: &mut HashMap<OwnedRoomId, RoomState>,
96) -> HashMap<OwnedRoomId, RoomToSync> {
97 let mut rooms_to_sync = HashMap::new();
98
99 for (room_id, MatchedRoom { room_info, room_config }) in matched_rooms {
100 match rooms_states.get(room_id) {
103 Some(prev_room_state) => {
105 if let Some(sync_from) =
106 if prev_room_state.events_stream_upper_bound
109 == StreamUpperBound::Live
110 && room_info.max_event_stream_id > prev_events_stream_id
111 {
112 Some(prev_events_stream_id)
113 }
114 else if let StreamUpperBound::Previously(up_to) =
117 prev_room_state.events_stream_upper_bound
118 && room_info.max_event_stream_id > up_to
119 {
120 Some(up_to)
121 }
122 else {
124 None
125 } {
126 rooms_to_sync.insert(
127 room_id.clone(),
128 RoomToSync::new_conditional(
129 room_info.was_ever_joined,
130 room_config.clone(),
131 sync_from,
132 false,
133 ),
134 );
135 } else {
136 continue;
137 }
138 }
139 None => {
141 rooms_to_sync.insert(
142 room_id.clone(),
143 RoomToSync::new_conditional(
144 room_info.was_ever_joined,
145 room_config.clone(),
146 0,
147 true,
148 ),
149 );
150 }
151 }
152
153 rooms_states.insert(
157 room_id.clone(),
158 RoomState { events_stream_upper_bound: StreamUpperBound::Live },
159 );
160 }
161
162 rooms_to_sync
163}
164
165pub(super) fn mark_stale_rooms(
172 rooms_states: &mut HashMap<OwnedRoomId, RoomState>,
173 user_rooms: &HashMap<OwnedRoomId, RoomInfo>,
174 rooms_to_sync: &HashMap<OwnedRoomId, RoomToSync>,
175 prev_events_stream_id: StreamId,
176) -> Vec<OwnedRoomId> {
177 rooms_states
178 .iter_mut()
179 .filter(|(room_id, room_state)| {
180 room_state.events_stream_upper_bound == StreamUpperBound::Live
182 && !rooms_to_sync.contains_key(*room_id)
184 && user_rooms.get(*room_id).is_some_and(|room_info| {
186 room_info.max_event_stream_id > prev_events_stream_id
187 })
188 })
189 .map(|(room_id, room_state)| {
190 room_state.events_stream_upper_bound =
192 StreamUpperBound::Previously(prev_events_stream_id);
193
194 room_id.clone()
195 })
196 .collect()
197}