summary refs log tree commit diff
diff options
context:
space:
mode:
authorErik Johnston <erik@matrix.org>2018-03-05 16:26:11 +0000
committerErik Johnston <erik@matrix.org>2018-03-22 13:25:51 +0000
commit3bf4d5e4654ed64bda5b0407f3ff821e3fcdeaf6 (patch)
tree705e5d85f3ea275f773c933e9a65ef9c8d910155
parentMake EventBase abstract base class (diff)
downloadsynapse-github/erikj/event_cleanup.tar.xz
-rw-r--r--synapse/events/__init__.py202
-rw-r--r--synapse/handlers/message.py2
-rw-r--r--synapse/storage/events.py4
-rw-r--r--synapse/storage/events_worker.py6
4 files changed, 207 insertions, 7 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
diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py
index 1ed0ffcc51..d017aa5963 100644
--- a/synapse/handlers/message.py
+++ b/synapse/handlers/message.py
@@ -261,6 +261,8 @@ class MessageHandler(BaseHandler):
 
         time_now = self.clock.time_msec()
 
+        logger.info("Returning event: %r", events)
+
         chunk = {
             "chunk": [
                 serialize_event(e, time_now, as_client_event)
diff --git a/synapse/storage/events.py b/synapse/storage/events.py
index 85ce6bea1a..f9cf9abaed 100644
--- a/synapse/storage/events.py
+++ b/synapse/storage/events.py
@@ -18,7 +18,7 @@ from synapse.storage.events_worker import EventsWorkerStore
 
 from twisted.internet import defer
 
-from synapse.events import USE_FROZEN_DICTS
+from synapse.events import USE_FROZEN_DICTS, CompactEvent
 
 from synapse.util.async import ObservableDeferred
 from synapse.util.logcontext import (
@@ -1254,7 +1254,7 @@ class EventsStore(EventsWorkerStore):
                 event = ev_map[row["event_id"]]
                 if not row["rejects"] and not row["redacts"]:
                     to_prefill.append(_EventCacheEntry(
-                        event=event,
+                        event=CompactEvent.from_event(event),
                         redacted_event=None,
                     ))
 
diff --git a/synapse/storage/events_worker.py b/synapse/storage/events_worker.py
index 2e23dd78ba..79c0c630b2 100644
--- a/synapse/storage/events_worker.py
+++ b/synapse/storage/events_worker.py
@@ -16,7 +16,7 @@ from ._base import SQLBaseStore
 
 from twisted.internet import defer, reactor
 
-from synapse.events import FrozenEvent
+from synapse.events import CompactEvent
 from synapse.events.utils import prune_event
 
 from synapse.util.logcontext import (
@@ -69,7 +69,7 @@ class EventsWorkerStore(SQLBaseStore):
                 False throw an exception.
 
         Returns:
-            Deferred : A FrozenEvent.
+            Deferred : A CompactEvent.
         """
         events = yield self._get_events(
             [event_id],
@@ -354,7 +354,7 @@ class EventsWorkerStore(SQLBaseStore):
                     desc="_get_event_from_row_rejected_reason",
                 )
 
-            original_ev = FrozenEvent(
+            original_ev = CompactEvent(
                 d,
                 internal_metadata_dict=internal_metadata,
                 rejected_reason=rejected_reason,