diff --git a/synapse/events/snapshot.py b/synapse/events/snapshot.py
index e9a732ff03..8e684d91b5 100644
--- a/synapse/events/snapshot.py
+++ b/synapse/events/snapshot.py
@@ -13,6 +13,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from twisted.internet import defer
+
+from frozendict import frozendict
+
class EventContext(object):
"""
@@ -25,7 +29,9 @@ class EventContext(object):
The current state map excluding the current event.
(type, state_key) -> event_id
- state_group (int): state group id
+ state_group (int|None): state group id, if the state has been stored
+ as a state group. This is usually only None if e.g. the event is
+ an outlier.
rejected (bool|str): A rejection reason if the event was rejected, else
False
@@ -46,7 +52,6 @@ class EventContext(object):
"prev_state_ids",
"state_group",
"rejected",
- "push_actions",
"prev_group",
"delta_ids",
"prev_state_events",
@@ -61,7 +66,6 @@ class EventContext(object):
self.state_group = None
self.rejected = False
- self.push_actions = []
# A previously persisted state group and a delta between that
# and this state.
@@ -71,3 +75,98 @@ class EventContext(object):
self.prev_state_events = None
self.app_service = None
+
+ def serialize(self, event):
+ """Converts self to a type that can be serialized as JSON, and then
+ deserialized by `deserialize`
+
+ Args:
+ event (FrozenEvent): The event that this context relates to
+
+ Returns:
+ dict
+ """
+
+ # We don't serialize the full state dicts, instead they get pulled out
+ # of the DB on the other side. However, the other side can't figure out
+ # the prev_state_ids, so if we're a state event we include the event
+ # id that we replaced in the state.
+ if event.is_state():
+ prev_state_id = self.prev_state_ids.get((event.type, event.state_key))
+ else:
+ prev_state_id = None
+
+ return {
+ "prev_state_id": prev_state_id,
+ "event_type": event.type,
+ "event_state_key": event.state_key if event.is_state() else None,
+ "state_group": self.state_group,
+ "rejected": self.rejected,
+ "prev_group": self.prev_group,
+ "delta_ids": _encode_state_dict(self.delta_ids),
+ "prev_state_events": self.prev_state_events,
+ "app_service_id": self.app_service.id if self.app_service else None
+ }
+
+ @staticmethod
+ @defer.inlineCallbacks
+ def deserialize(store, input):
+ """Converts a dict that was produced by `serialize` back into a
+ EventContext.
+
+ Args:
+ store (DataStore): Used to convert AS ID to AS object
+ input (dict): A dict produced by `serialize`
+
+ Returns:
+ EventContext
+ """
+ context = EventContext()
+ context.state_group = input["state_group"]
+ context.rejected = input["rejected"]
+ context.prev_group = input["prev_group"]
+ context.delta_ids = _decode_state_dict(input["delta_ids"])
+ context.prev_state_events = input["prev_state_events"]
+
+ # We use the state_group and prev_state_id stuff to pull the
+ # current_state_ids out of the DB and construct prev_state_ids.
+ prev_state_id = input["prev_state_id"]
+ event_type = input["event_type"]
+ event_state_key = input["event_state_key"]
+
+ context.current_state_ids = yield store.get_state_ids_for_group(
+ context.state_group,
+ )
+ if prev_state_id and event_state_key:
+ context.prev_state_ids = dict(context.current_state_ids)
+ context.prev_state_ids[(event_type, event_state_key)] = prev_state_id
+ else:
+ context.prev_state_ids = context.current_state_ids
+
+ app_service_id = input["app_service_id"]
+ if app_service_id:
+ context.app_service = store.get_app_service_by_id(app_service_id)
+
+ defer.returnValue(context)
+
+
+def _encode_state_dict(state_dict):
+ """Since dicts of (type, state_key) -> event_id cannot be serialized in
+ JSON we need to convert them to a form that can.
+ """
+ if state_dict is None:
+ return None
+
+ return [
+ (etype, state_key, v)
+ for (etype, state_key), v in state_dict.iteritems()
+ ]
+
+
+def _decode_state_dict(input):
+ """Decodes a state dict encoded using `_encode_state_dict` above
+ """
+ if input is None:
+ return None
+
+ return frozendict({(etype, state_key,): v for etype, state_key, v in input})
|