Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Implement tracking event format versions #4403

Closed
wants to merge 9 commits into from
1 change: 1 addition & 0 deletions changelog.d/4403.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add concept of different event format versions
13 changes: 13 additions & 0 deletions synapse/api/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,19 @@ class RoomVersions(object):
RoomVersions.STATE_V2_TEST,
}


class EventFormatVersions(object):
"""This is an internal enum for tracking the version of the event format,
independently from the room version.
"""
V1 = 1


KNOWN_EVENT_FORMAT_VERSIONS = {
EventFormatVersions.V1,
}


ServerNoticeMsgType = "m.server_notice"
ServerNoticeLimitReached = "m.server_notice.usage_limit_reached"

Expand Down
43 changes: 43 additions & 0 deletions synapse/events/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@

import six

from synapse.api.constants import (
KNOWN_EVENT_FORMAT_VERSIONS,
KNOWN_ROOM_VERSIONS,
EventFormatVersions,
)
from synapse.util.caches import intern_dict
from synapse.util.frozenutils import freeze

Expand Down Expand Up @@ -179,6 +184,8 @@ def auth_event_ids(self):


class FrozenEvent(EventBase):
format_version = EventFormatVersions.V1 # All events of this type are V1

def __init__(self, event_dict, internal_metadata_dict={}, rejected_reason=None):
event_dict = dict(event_dict)

Expand Down Expand Up @@ -232,3 +239,39 @@ def __repr__(self):
self.get("type", None),
self.get("state_key", None),
)


def event_type_from_room_version(room_version):
"""Returns the python type to use to construct an Event object for the
erikjohnston marked this conversation as resolved.
Show resolved Hide resolved
given room version.

Args:
room_version (str): The room version

Returns:
type: A type that can be initialized as per the initializer of
`FrozenEvent`
"""
if room_version not in KNOWN_ROOM_VERSIONS:
raise Exception(
"No event format defined for version %r" % (room_version,)
)
return FrozenEvent


def event_type_from_format_version(format_version):
"""Returns the python type to use to construct an Event object for the
given event format version.

Args:
format_version (int): The event format version

Returns:
type: A type that can be initialized as per the initializer of
`FrozenEvent`
"""
if format_version not in KNOWN_EVENT_FORMAT_VERSIONS:
raise Exception(
"No event format %r" % (format_version,)
)
return FrozenEvent
51 changes: 50 additions & 1 deletion synapse/events/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,39 @@

import copy

from synapse.api.constants import RoomVersions
from synapse.types import EventID
from synapse.util.stringutils import random_string

from . import EventBase, FrozenEvent, _event_dict_property


def get_event_builder(room_version, key_values={}, internal_metadata_dict={}):
"""Generate an event builder appropriate for the given room version

Args:
room_version (str): Version of the room that we're creating an
event builder for
key_values (dict): Fields used as the basis of the new event
internal_metadata_dict (dict): Used to create the `_EventInternalMetadata`
object.

Returns:
EventBuilder
"""
if room_version in {
RoomVersions.V1,
RoomVersions.V2,
RoomVersions.VDH_TEST,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should consider dropping these test versions imho

RoomVersions.STATE_V2_TEST,
}:
return EventBuilder(key_values, internal_metadata_dict)
else:
raise Exception(
"No event format defined for version %r" % (room_version,)
)


class EventBuilder(EventBase):
def __init__(self, key_values={}, internal_metadata_dict={}):
signatures = copy.deepcopy(key_values.pop("signatures", {}))
Expand Down Expand Up @@ -58,7 +85,29 @@ def create_event_id(self):

return e_id.to_string()

def new(self, key_values={}):
def new(self, room_version, key_values={}):
"""Generate an event builder appropriate for the given room version

Args:
room_version (str): Version of the room that we're creating an
event builder for
key_values (dict): Fields used as the basis of the new event

Returns:
EventBuilder
"""

# There's currently only the one event version defined
if room_version not in {
RoomVersions.V1,
RoomVersions.V2,
RoomVersions.VDH_TEST,
RoomVersions.STATE_V2_TEST,
}:
raise Exception(
"No event format defined for version %r" % (room_version,)
)

key_values["event_id"] = self.create_event_id()

time_now = int(self.clock.time_msec())
Expand Down
23 changes: 14 additions & 9 deletions synapse/federation/federation_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from synapse.api.constants import MAX_DEPTH, EventTypes, Membership
from synapse.api.errors import Codes, SynapseError
from synapse.crypto.event_signing import check_event_content_hash
from synapse.events import FrozenEvent
from synapse.events import event_type_from_room_version
from synapse.events.utils import prune_event
from synapse.http.servlet import assert_params_in_dict
from synapse.types import get_domain_from_id
Expand All @@ -43,7 +43,8 @@ def __init__(self, hs):
self._clock = hs.get_clock()

@defer.inlineCallbacks
def _check_sigs_and_hash_and_fetch(self, origin, pdus, outlier=False,
def _check_sigs_and_hash_and_fetch(self, origin, pdus, room_version,
outlier=False,
include_none=False):
"""Takes a list of PDUs and checks the signatures and hashs of each
one. If a PDU fails its signature check then we check if we have it in
Expand All @@ -56,8 +57,12 @@ def _check_sigs_and_hash_and_fetch(self, origin, pdus, outlier=False,
a new list.

Args:
pdu (list)
outlier (bool)
origin (str): where the events came from
pdus (list)
room_version (str): The version of the room the events belong to
outlier (bool): Are the event outliers or not
include_none (bool): Whether the returned list should have `None`
for invalid PDUs or not

Returns:
Deferred : A list of PDUs that have valid signatures and hashes.
Expand All @@ -84,6 +89,7 @@ def handle_check_result(pdu, deferred):
res = yield self.get_pdu(
destinations=[pdu.origin],
event_id=pdu.event_id,
room_version=room_version,
outlier=outlier,
timeout=10000,
)
Expand Down Expand Up @@ -297,11 +303,12 @@ def _is_invite_via_3pid(event):
)


def event_from_pdu_json(pdu_json, outlier=False):
def event_from_pdu_json(pdu_json, room_version, outlier=False):
erikjohnston marked this conversation as resolved.
Show resolved Hide resolved
"""Construct a FrozenEvent from an event json received over federation

Args:
pdu_json (object): pdu as received over federation
pdu_json (object): PDU as received over federation
room_version (str): The version of the room this PDU belongs to
outlier (bool): True to mark this event as an outlier

Returns:
Expand All @@ -325,9 +332,7 @@ def event_from_pdu_json(pdu_json, outlier=False):
elif depth > MAX_DEPTH:
raise SynapseError(400, "Depth too large", Codes.BAD_JSON)

event = FrozenEvent(
pdu_json
)
event = event_type_from_room_version(room_version)(pdu_json)

event.internal_metadata.outlier = outlier

Expand Down
Loading