diff --git a/setup.py b/setup.py index 9b38f790b9..d1b8f0680a 100755 --- a/setup.py +++ b/setup.py @@ -41,6 +41,7 @@ setup( "pynacl", "daemonize", "py-bcrypt", + "frozendict>=0.4", ], dependency_links=[ "https://github.com/matrix-org/syutil/tarball/v0.0.2#egg=syutil-0.0.2", diff --git a/synapse/events/__init__.py b/synapse/events/__init__.py new file mode 100644 index 0000000000..eefc9d3b30 --- /dev/null +++ b/synapse/events/__init__.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- +# Copyright 2014 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 frozendict import frozendict + + +class _EventInternalMetadata(object): + def __init__(self, internal_metadata_dict): + self.__dict__ = internal_metadata_dict + + def get_dict(self): + return dict(self.__dict__) + + +class Event(object): + def __init__(self, event_dict, internal_metadata_dict={}): + self._signatures = event_dict.get("signatures", {}) + self._unsigned = event_dict.get("unsigned", {}) + + self._original = { + k: v + for k, v in event_dict.items() + if k not in ["signatures", "unsigned"] + } + + self._event_dict = frozendict(self._original) + + self.internal_metadata = _EventInternalMetadata( + internal_metadata_dict + ) + + @property + def auth_events(self): + return self._event_dict["auth_events"] + + @property + def content(self): + return self._event_dict["content"] + + @property + def event_id(self): + return self._event_dict["event_id"] + + @property + def hashes(self): + return self._event_dict["hashes"] + + @property + def origin(self): + return self._event_dict["origin"] + + @property + def prev_events(self): + return self._event_dict["prev_events"] + + @property + def prev_state(self): + return self._event_dict["prev_state"] + + @property + def room_id(self): + return self._event_dict["room_id"] + + @property + def signatures(self): + return self._signatures + + @property + def state_key(self): + return self._event_dict["state_key"] + + @property + def type(self): + return self._event_dict["type"] + + @property + def unsigned(self): + return self._unsigned + + @property + def user_id(self): + return self._event_dict["sender"] + + @property + def sender(self): + return self._event_dict["sender"] + + def get_dict(self): + d = dict(self._original) + d.update({ + "signatures": self._signatures, + "unsigned": self._unsigned, + }) + + return d + + 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"] + + return pdu_json \ No newline at end of file diff --git a/synapse/events/builder.py b/synapse/events/builder.py new file mode 100644 index 0000000000..d741795bc5 --- /dev/null +++ b/synapse/events/builder.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +# Copyright 2014 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 . import Event + +from synapse.types import EventID + +from synapse.util.stringutils import random_string + + +class EventBuilder(object): + def __init__(self, key_values={}): + self._event_dict = dict(key_values) + self._metadata = {} + + def update_event_key(self, key, value): + self._event_dict[key] = value + + def update_event_keys(self, other_dict): + self._event_dict.update(other_dict) + + def update_internal_key(self, key, value): + self._metadata[key] = value + + def build(self): + return Event( + self._event_dict, + self._metadata, + ) + + +class EventBuilderFactory(object): + def __init__(self, clock, hostname): + self.clock = clock + self.hostname = hostname + + self.event_id_count = 0 + + def create_event_id(self): + i = str(self.event_id_count) + self.event_id_count += 1 + + local_part = str(int(self.clock.time())) + i + random_string(5) + + e_id = EventID.create(local_part, self.hostname) + + return e_id.to_string() + + def new(self, key_values={}): + if "event_id" not in key_values: + key_values["event_id"] = self.create_event_id() + + time_now = self.clock.time_msec() + + key_values.setdefault("origin", self.hostname) + key_values.setdefault("origin_server_ts", time_now) + + if "unsigned" in key_values: + age = key_values["unsigned"].pop("age", 0) + key_values["unsigned"].setdefault("age_ts", time_now - age) + + return EventBuilder(key_values=key_values,) \ No newline at end of file