2020)
2121from synapse .handlers .sync import SyncConfig
2222from synapse .types import StreamToken
23+ from synapse .events import FrozenEvent
2324from synapse .events .utils import (
2425 serialize_event , format_event_for_client_v2_without_event_id ,
2526)
@@ -256,7 +257,13 @@ def encode_room(room, filter, time_now, token_id, joined=True):
256257 :rtype: dict[str, object]
257258 """
258259 event_map = {}
259- state_events = filter .filter_room_state (room .state .values ())
260+ state_dict = room .state
261+ timeline_events = filter .filter_room_timeline (room .timeline .events )
262+
263+ state_dict = SyncRestServlet ._rollback_state_for_timeline (
264+ state_dict , timeline_events )
265+
266+ state_events = filter .filter_room_state (state_dict .values ())
260267 state_event_ids = []
261268 for event in state_events :
262269 # TODO(mjark): Respect formatting requirements in the filter.
@@ -266,7 +273,6 @@ def encode_room(room, filter, time_now, token_id, joined=True):
266273 )
267274 state_event_ids .append (event .event_id )
268275
269- timeline_events = filter .filter_room_timeline (room .timeline .events )
270276 timeline_event_ids = []
271277 for event in timeline_events :
272278 # TODO(mjark): Respect formatting requirements in the filter.
@@ -297,6 +303,63 @@ def encode_room(room, filter, time_now, token_id, joined=True):
297303
298304 return result
299305
306+ @staticmethod
307+ def _rollback_state_for_timeline (state , timeline ):
308+ """
309+ Wind the state dictionary backwards, so that it represents the
310+ state at the start of the timeline, rather than at the end.
311+
312+ :param dict[(str, str), synapse.events.EventBase] state: the
313+ state dictionary. Will be updated to the state before the timeline.
314+ :param list[synapse.events.EventBase] timeline: the event timeline
315+ :return: updated state dictionary
316+ """
317+ logger .debug ("Processing state dict %r; timeline %r" , state ,
318+ [e .get_dict () for e in timeline ])
319+
320+ result = state .copy ()
321+
322+ for timeline_event in reversed (timeline ):
323+ if not timeline_event .is_state ():
324+ continue
325+
326+ event_key = (timeline_event .type , timeline_event .state_key )
327+
328+ logger .debug ("Considering %s for removal" , event_key )
329+
330+ state_event = result .get (event_key )
331+ if (state_event is None or
332+ state_event .event_id != timeline_event .event_id ):
333+ # the event in the timeline isn't present in the state
334+ # dictionary.
335+ #
336+ # the most likely cause for this is that there was a fork in
337+ # the event graph, and the state is no longer valid. Really,
338+ # the event shouldn't be in the timeline. We're going to ignore
339+ # it for now, however.
340+ logger .warn ("Found state event %r in timeline which doesn't "
341+ "match state dictionary" , timeline_event )
342+ continue
343+
344+ prev_event_id = timeline_event .unsigned .get ("replaces_state" , None )
345+ logger .debug ("Replacing %s with %s in state dict" ,
346+ timeline_event .event_id , prev_event_id )
347+
348+ if prev_event_id is None :
349+ del result [event_key ]
350+ else :
351+ result [event_key ] = FrozenEvent ({
352+ "type" : timeline_event .type ,
353+ "state_key" : timeline_event .state_key ,
354+ "content" : timeline_event .unsigned ['prev_content' ],
355+ "sender" : timeline_event .unsigned ['prev_sender' ],
356+ "event_id" : prev_event_id ,
357+ "room_id" : timeline_event .room_id ,
358+ })
359+ logger .debug ("New value: %r" , result .get (event_key ))
360+
361+ return result
362+
300363
301364def register_servlets (hs , http_server ):
302365 SyncRestServlet (hs ).register (http_server )
0 commit comments