summary refs log tree commit diff
path: root/synapse/events/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'synapse/events/__init__.py')
-rw-r--r--synapse/events/__init__.py202
1 files changed, 200 insertions, 2 deletions
diff --git a/synapse/events/__init__.py b/synapse/events/__init__.py
index 95f0bdf3e9..d56f45bbf5 100644
--- a/synapse/events/__init__.py
+++ b/synapse/events/__init__.py
@@ -13,10 +13,11 @@
 # 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
+from synapse.util.frozenutils import freeze, unfreeze
+from synapse.util.caches import intern_dict, intern_string
 
 import abc
+import simplejson as json
 
 
 # Whether we should use frozen_dict in FrozenEvent. Using frozen_dicts prevents
@@ -229,3 +230,200 @@ class FrozenEvent(EventBase):
             self.get("type", None),
             self.get("state_key", None),
         )
+
+
+def _compact_property(key):
+    def getter(self):
+        try:
+            return self[key]
+        except KeyError:
+            raise AttributeError(
+                "AttributeError: '%s' object has no attribute '%s'" % (
+                    self.__name__, key,
+                )
+            )
+
+    return property(getter)
+
+
+class _Unsigned(object):
+    __slots__ = [
+        "age_ts",
+        "replaces_state",
+        "redacted_because",
+        "invite_room_state",
+        "prev_content",
+        "prev_sender",
+        "redacted_by",
+    ]
+
+    def __init__(self, **kwargs):
+        for s in self.__slots__:
+            try:
+                setattr(self, s, kwargs[s])
+            except KeyError:
+                continue
+
+    def __getitem__(self, field):
+        try:
+            return getattr(self, field)
+        except AttributeError:
+            raise KeyError(field)
+
+    def __setitem__(self, field, value):
+        try:
+            setattr(self, field, value)
+        except AttributeError:
+            raise KeyError(field)
+
+    def __delitem__(self, field):
+        try:
+            return delattr(self, field)
+        except AttributeError:
+            raise KeyError(field)
+
+    def __contains__(self, field):
+        return hasattr(self, field)
+
+    def get(self, key, default=None):
+        return getattr(self, key, default)
+
+    def pop(self, key, default):
+        r = self.get(key, default)
+        try:
+            delattr(self, key)
+        except AttributeError:
+            pass
+        return r
+
+    def __iter__(self):
+        for key in self.__slots__:
+            if hasattr(self, key):
+                yield (key, getattr(self, key))
+
+
+class CompactEvent(EventBase):
+    __slots__ = [
+        "event_json",
+
+        "internal_metadata",
+        "rejected_reason",
+
+        "signatures",
+        "unsigned",
+
+        "event_id",
+        "room_id",
+        "type",
+        "state_key",
+        "sender",
+    ]
+
+    def __init__(self, event_dict, internal_metadata_dict={}, rejected_reason=None):
+        event_dict = dict(unfreeze(event_dict))
+
+        object.__setattr__(self, "unsigned", _Unsigned(**event_dict.pop("unsigned", {})))
+
+        signatures = {
+            intern_string(name): {
+                intern_string(sig_id): sig.encode("utf-8")
+                for sig_id, sig in sigs.iteritems()
+            }
+            for name, sigs in event_dict.pop("signatures", {}).iteritems()
+        }
+        object.__setattr__(self, "signatures", signatures)
+
+        object.__setattr__(self, "event_json", json.dumps(event_dict))
+
+        object.__setattr__(self, "rejected_reason", rejected_reason)
+        object.__setattr__(self, "internal_metadata", _EventInternalMetadata(
+            internal_metadata_dict
+        ))
+
+        object.__setattr__(self, "event_id", event_dict["event_id"])
+        object.__setattr__(self, "room_id", event_dict["room_id"])
+        object.__setattr__(self, "type", event_dict["type"])
+        if "state_key" in event_dict:
+            object.__setattr__(self, "state_key", event_dict["state_key"])
+        object.__setattr__(self, "sender", event_dict["sender"])
+
+    auth_events = _compact_property("auth_events")
+    depth = _compact_property("depth")
+    content = _compact_property("content")
+    hashes = _compact_property("hashes")
+    origin = _compact_property("origin")
+    origin_server_ts = _compact_property("origin_server_ts")
+    prev_events = _compact_property("prev_events")
+    prev_state = _compact_property("prev_state")
+    redacts = _compact_property("redacts")
+
+    @property
+    def user_id(self):
+        return self.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 = json.loads(self.event_json)
+        d.update({
+            "signatures": dict(self.signatures),
+            "unsigned": dict(self.unsigned),
+        })
+
+        return d
+
+    def get(self, key, default=None):
+        if key in self.__slots__:
+            return freeze(getattr(self, key, default))
+
+        d = json.loads(self.event_json)
+        return d.get(key, default)
+
+    def get_internal_metadata_dict(self):
+        return self.internal_metadata.get_dict()
+
+    def __getitem__(self, field):
+        if field in self.__slots__:
+            try:
+                return freeze(getattr(self, field))
+            except AttributeError:
+                raise KeyError(field)
+
+        d = json.loads(self.event_json)
+        return d[field]
+
+    def __contains__(self, field):
+        if field in self.__slots__:
+            return hasattr(self, field)
+
+        d = json.loads(self.event_json)
+        return field in d
+
+    @staticmethod
+    def from_event(event):
+        return CompactEvent(
+            event.get_pdu_json(),
+            event.get_internal_metadata_dict(),
+            event.rejected_reason,
+        )
+
+    def __str__(self):
+        return self.__repr__()
+
+    def __repr__(self):
+        return "<CompactEvent event_id='%s', type='%s', state_key='%s'>" % (
+            self.get("event_id", None),
+            self.get("type", None),
+            self.get("state_key", None),
+        )
+
+    def iteritems(self):
+        return json.loads(self.event_json).iteritems()
+
+    def __eq__(self, other):
+        return self.event_id == other.event_id