__init__.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2014-2016 OpenMarket Ltd
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. from synapse.util.frozenutils import freeze
  16. from synapse.util.caches import intern_dict
  17. # Whether we should use frozen_dict in FrozenEvent. Using frozen_dicts prevents
  18. # bugs where we accidentally share e.g. signature dicts. However, converting
  19. # a dict to frozen_dicts is expensive.
  20. USE_FROZEN_DICTS = True
  21. class _EventInternalMetadata(object):
  22. def __init__(self, internal_metadata_dict):
  23. self.__dict__ = dict(internal_metadata_dict)
  24. def get_dict(self):
  25. return dict(self.__dict__)
  26. def is_outlier(self):
  27. return getattr(self, "outlier", False)
  28. def is_invite_from_remote(self):
  29. return getattr(self, "invite_from_remote", False)
  30. def _event_dict_property(key):
  31. def getter(self):
  32. return self._event_dict[key]
  33. def setter(self, v):
  34. self._event_dict[key] = v
  35. def delete(self):
  36. del self._event_dict[key]
  37. return property(
  38. getter,
  39. setter,
  40. delete,
  41. )
  42. class EventBase(object):
  43. def __init__(self, event_dict, signatures={}, unsigned={},
  44. internal_metadata_dict={}, rejected_reason=None):
  45. self.signatures = signatures
  46. self.unsigned = unsigned
  47. self.rejected_reason = rejected_reason
  48. self._event_dict = event_dict
  49. self.internal_metadata = _EventInternalMetadata(
  50. internal_metadata_dict
  51. )
  52. auth_events = _event_dict_property("auth_events")
  53. depth = _event_dict_property("depth")
  54. content = _event_dict_property("content")
  55. event_id = _event_dict_property("event_id")
  56. hashes = _event_dict_property("hashes")
  57. origin = _event_dict_property("origin")
  58. origin_server_ts = _event_dict_property("origin_server_ts")
  59. prev_events = _event_dict_property("prev_events")
  60. prev_state = _event_dict_property("prev_state")
  61. redacts = _event_dict_property("redacts")
  62. room_id = _event_dict_property("room_id")
  63. sender = _event_dict_property("sender")
  64. state_key = _event_dict_property("state_key")
  65. type = _event_dict_property("type")
  66. user_id = _event_dict_property("sender")
  67. @property
  68. def membership(self):
  69. return self.content["membership"]
  70. def is_state(self):
  71. return hasattr(self, "state_key") and self.state_key is not None
  72. def get_dict(self):
  73. d = dict(self._event_dict)
  74. d.update({
  75. "signatures": self.signatures,
  76. "unsigned": dict(self.unsigned),
  77. })
  78. return d
  79. def get(self, key, default=None):
  80. return self._event_dict.get(key, default)
  81. def get_internal_metadata_dict(self):
  82. return self.internal_metadata.get_dict()
  83. def get_pdu_json(self, time_now=None):
  84. pdu_json = self.get_dict()
  85. if time_now is not None and "age_ts" in pdu_json["unsigned"]:
  86. age = time_now - pdu_json["unsigned"]["age_ts"]
  87. pdu_json.setdefault("unsigned", {})["age"] = int(age)
  88. del pdu_json["unsigned"]["age_ts"]
  89. # This may be a frozen event
  90. pdu_json["unsigned"].pop("redacted_because", None)
  91. return pdu_json
  92. def __set__(self, instance, value):
  93. raise AttributeError("Unrecognized attribute %s" % (instance,))
  94. def __getitem__(self, field):
  95. return self._event_dict[field]
  96. def __contains__(self, field):
  97. return field in self._event_dict
  98. def items(self):
  99. return self._event_dict.items()
  100. class FrozenEvent(EventBase):
  101. def __init__(self, event_dict, internal_metadata_dict={}, rejected_reason=None):
  102. event_dict = dict(event_dict)
  103. # Signatures is a dict of dicts, and this is faster than doing a
  104. # copy.deepcopy
  105. signatures = {
  106. name: {sig_id: sig for sig_id, sig in sigs.items()}
  107. for name, sigs in event_dict.pop("signatures", {}).items()
  108. }
  109. unsigned = dict(event_dict.pop("unsigned", {}))
  110. # We intern these strings because they turn up a lot (especially when
  111. # caching).
  112. event_dict = intern_dict(event_dict)
  113. if USE_FROZEN_DICTS:
  114. frozen_dict = freeze(event_dict)
  115. else:
  116. frozen_dict = event_dict
  117. super(FrozenEvent, self).__init__(
  118. frozen_dict,
  119. signatures=signatures,
  120. unsigned=unsigned,
  121. internal_metadata_dict=internal_metadata_dict,
  122. rejected_reason=rejected_reason,
  123. )
  124. @staticmethod
  125. def from_event(event):
  126. e = FrozenEvent(
  127. event.get_pdu_json()
  128. )
  129. e.internal_metadata = event.internal_metadata
  130. return e
  131. def __str__(self):
  132. return self.__repr__()
  133. def __repr__(self):
  134. return "<FrozenEvent event_id='%s', type='%s', state_key='%s'>" % (
  135. self.get("event_id", None),
  136. self.get("type", None),
  137. self.get("state_key", None),
  138. )