mirror of
https://mau.dev/maunium/synapse.git
synced 2024-10-01 01:36:05 -04:00
76503f95ed
Move the checks for whether an event is new state inside persist event itself. This was harder than expected because there wasn't enough information passed to persist event to correctly handle invites from remote servers for new rooms.
183 lines
5.4 KiB
Python
183 lines
5.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2014-2016 OpenMarket Ltd
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
from synapse.util.frozenutils import freeze
|
|
from synapse.util.caches import intern_dict
|
|
|
|
|
|
# Whether we should use frozen_dict in FrozenEvent. Using frozen_dicts prevents
|
|
# bugs where we accidentally share e.g. signature dicts. However, converting
|
|
# a dict to frozen_dicts is expensive.
|
|
USE_FROZEN_DICTS = True
|
|
|
|
|
|
class _EventInternalMetadata(object):
|
|
def __init__(self, internal_metadata_dict):
|
|
self.__dict__ = dict(internal_metadata_dict)
|
|
|
|
def get_dict(self):
|
|
return dict(self.__dict__)
|
|
|
|
def is_outlier(self):
|
|
return getattr(self, "outlier", False)
|
|
|
|
def is_invite_from_remote(self):
|
|
return getattr(self, "invite_from_remote", False)
|
|
|
|
|
|
def _event_dict_property(key):
|
|
def getter(self):
|
|
return self._event_dict[key]
|
|
|
|
def setter(self, v):
|
|
self._event_dict[key] = v
|
|
|
|
def delete(self):
|
|
del self._event_dict[key]
|
|
|
|
return property(
|
|
getter,
|
|
setter,
|
|
delete,
|
|
)
|
|
|
|
|
|
class EventBase(object):
|
|
def __init__(self, event_dict, signatures={}, unsigned={},
|
|
internal_metadata_dict={}, rejected_reason=None):
|
|
self.signatures = signatures
|
|
self.unsigned = unsigned
|
|
self.rejected_reason = rejected_reason
|
|
|
|
self._event_dict = event_dict
|
|
|
|
self.internal_metadata = _EventInternalMetadata(
|
|
internal_metadata_dict
|
|
)
|
|
|
|
auth_events = _event_dict_property("auth_events")
|
|
depth = _event_dict_property("depth")
|
|
content = _event_dict_property("content")
|
|
event_id = _event_dict_property("event_id")
|
|
hashes = _event_dict_property("hashes")
|
|
origin = _event_dict_property("origin")
|
|
origin_server_ts = _event_dict_property("origin_server_ts")
|
|
prev_events = _event_dict_property("prev_events")
|
|
prev_state = _event_dict_property("prev_state")
|
|
redacts = _event_dict_property("redacts")
|
|
room_id = _event_dict_property("room_id")
|
|
sender = _event_dict_property("sender")
|
|
state_key = _event_dict_property("state_key")
|
|
type = _event_dict_property("type")
|
|
user_id = _event_dict_property("sender")
|
|
|
|
@property
|
|
def membership(self):
|
|
return self.content["membership"]
|
|
|
|
def is_state(self):
|
|
return hasattr(self, "state_key") and self.state_key is not None
|
|
|
|
def get_dict(self):
|
|
d = dict(self._event_dict)
|
|
d.update({
|
|
"signatures": self.signatures,
|
|
"unsigned": dict(self.unsigned),
|
|
})
|
|
|
|
return d
|
|
|
|
def get(self, key, default):
|
|
return self._event_dict.get(key, default)
|
|
|
|
def get_internal_metadata_dict(self):
|
|
return self.internal_metadata.get_dict()
|
|
|
|
def get_pdu_json(self, time_now=None):
|
|
pdu_json = self.get_dict()
|
|
|
|
if time_now is not None and "age_ts" in pdu_json["unsigned"]:
|
|
age = time_now - pdu_json["unsigned"]["age_ts"]
|
|
pdu_json.setdefault("unsigned", {})["age"] = int(age)
|
|
del pdu_json["unsigned"]["age_ts"]
|
|
|
|
# This may be a frozen event
|
|
pdu_json["unsigned"].pop("redacted_because", None)
|
|
|
|
return pdu_json
|
|
|
|
def __set__(self, instance, value):
|
|
raise AttributeError("Unrecognized attribute %s" % (instance,))
|
|
|
|
def __getitem__(self, field):
|
|
return self._event_dict[field]
|
|
|
|
def __contains__(self, field):
|
|
return field in self._event_dict
|
|
|
|
def items(self):
|
|
return self._event_dict.items()
|
|
|
|
|
|
class FrozenEvent(EventBase):
|
|
def __init__(self, event_dict, internal_metadata_dict={}, rejected_reason=None):
|
|
event_dict = dict(event_dict)
|
|
|
|
# Signatures is a dict of dicts, and this is faster than doing a
|
|
# copy.deepcopy
|
|
signatures = {
|
|
name: {sig_id: sig for sig_id, sig in sigs.items()}
|
|
for name, sigs in event_dict.pop("signatures", {}).items()
|
|
}
|
|
|
|
unsigned = dict(event_dict.pop("unsigned", {}))
|
|
|
|
# We intern these strings because they turn up a lot (especially when
|
|
# caching).
|
|
event_dict = intern_dict(event_dict)
|
|
|
|
if USE_FROZEN_DICTS:
|
|
frozen_dict = freeze(event_dict)
|
|
else:
|
|
frozen_dict = event_dict
|
|
|
|
super(FrozenEvent, self).__init__(
|
|
frozen_dict,
|
|
signatures=signatures,
|
|
unsigned=unsigned,
|
|
internal_metadata_dict=internal_metadata_dict,
|
|
rejected_reason=rejected_reason,
|
|
)
|
|
|
|
@staticmethod
|
|
def from_event(event):
|
|
e = FrozenEvent(
|
|
event.get_pdu_json()
|
|
)
|
|
|
|
e.internal_metadata = event.internal_metadata
|
|
|
|
return e
|
|
|
|
def __str__(self):
|
|
return self.__repr__()
|
|
|
|
def __repr__(self):
|
|
return "<FrozenEvent event_id='%s', type='%s', state_key='%s'>" % (
|
|
self.get("event_id", None),
|
|
self.get("type", None),
|
|
self.get("state_key", None),
|
|
)
|