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

Commit 8df862e

Browse files
authored
Add rooms.room_version column (#6729)
This is so that we don't have to rely on pulling it out from `current_state_events` table.
1 parent d5275fc commit 8df862e

File tree

11 files changed

+270
-73
lines changed

11 files changed

+270
-73
lines changed

changelog.d/6729.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Record room versions in the `rooms` table.

synapse/federation/federation_client.py

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import copy
1818
import itertools
1919
import logging
20+
from typing import Dict, Iterable
2021

2122
from prometheus_client import Counter
2223

@@ -29,6 +30,7 @@
2930
FederationDeniedError,
3031
HttpResponseException,
3132
SynapseError,
33+
UnsupportedRoomVersionError,
3234
)
3335
from synapse.api.room_versions import (
3436
KNOWN_ROOM_VERSIONS,
@@ -385,6 +387,8 @@ def _try_destination_list(self, description, destinations, callback):
385387
return res
386388
except InvalidResponseError as e:
387389
logger.warning("Failed to %s via %s: %s", description, destination, e)
390+
except UnsupportedRoomVersionError:
391+
raise
388392
except HttpResponseException as e:
389393
if not 500 <= e.code < 600:
390394
raise e.to_synapse_error()
@@ -404,7 +408,13 @@ def _try_destination_list(self, description, destinations, callback):
404408
raise SynapseError(502, "Failed to %s via any server" % (description,))
405409

406410
def make_membership_event(
407-
self, destinations, room_id, user_id, membership, content, params
411+
self,
412+
destinations: Iterable[str],
413+
room_id: str,
414+
user_id: str,
415+
membership: str,
416+
content: dict,
417+
params: Dict[str, str],
408418
):
409419
"""
410420
Creates an m.room.member event, with context, without participating in the room.
@@ -417,21 +427,23 @@ def make_membership_event(
417427
Note that this does not append any events to any graphs.
418428
419429
Args:
420-
destinations (Iterable[str]): Candidate homeservers which are probably
430+
destinations: Candidate homeservers which are probably
421431
participating in the room.
422-
room_id (str): The room in which the event will happen.
423-
user_id (str): The user whose membership is being evented.
424-
membership (str): The "membership" property of the event. Must be
425-
one of "join" or "leave".
426-
content (dict): Any additional data to put into the content field
427-
of the event.
428-
params (dict[str, str|Iterable[str]]): Query parameters to include in the
429-
request.
432+
room_id: The room in which the event will happen.
433+
user_id: The user whose membership is being evented.
434+
membership: The "membership" property of the event. Must be one of
435+
"join" or "leave".
436+
content: Any additional data to put into the content field of the
437+
event.
438+
params: Query parameters to include in the request.
430439
Return:
431-
Deferred[tuple[str, FrozenEvent, int]]: resolves to a tuple of
432-
`(origin, event, event_format)` where origin is the remote
433-
homeserver which generated the event, and event_format is one of
434-
`synapse.api.room_versions.EventFormatVersions`.
440+
Deferred[Tuple[str, FrozenEvent, RoomVersion]]: resolves to a tuple of
441+
`(origin, event, room_version)` where origin is the remote
442+
homeserver which generated the event, and room_version is the
443+
version of the room.
444+
445+
Fails with a `UnsupportedRoomVersionError` if remote responds with
446+
a room version we don't understand.
435447
436448
Fails with a ``SynapseError`` if the chosen remote server
437449
returns a 300/400 code.
@@ -453,8 +465,12 @@ def send_request(destination):
453465

454466
# Note: If not supplied, the room version may be either v1 or v2,
455467
# however either way the event format version will be v1.
456-
room_version = ret.get("room_version", RoomVersions.V1.identifier)
457-
event_format = room_version_to_event_format(room_version)
468+
room_version_id = ret.get("room_version", RoomVersions.V1.identifier)
469+
room_version = KNOWN_ROOM_VERSIONS.get(room_version_id)
470+
if not room_version:
471+
raise UnsupportedRoomVersionError()
472+
473+
event_format = room_version_to_event_format(room_version_id)
458474

459475
pdu_dict = ret.get("event", None)
460476
if not isinstance(pdu_dict, dict):
@@ -478,7 +494,7 @@ def send_request(destination):
478494
event_dict=pdu_dict,
479495
)
480496

481-
return (destination, ev, event_format)
497+
return (destination, ev, room_version)
482498

483499
return self._try_destination_list(
484500
"make_" + membership, destinations, send_request

synapse/handlers/federation.py

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@
4444
StoreError,
4545
SynapseError,
4646
)
47-
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS, RoomVersions
47+
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS, RoomVersion, RoomVersions
4848
from synapse.crypto.event_signing import compute_event_signature
4949
from synapse.event_auth import auth_types_for_event
50-
from synapse.events import EventBase
50+
from synapse.events import EventBase, room_version_to_event_format
5151
from synapse.events.snapshot import EventContext
5252
from synapse.events.validator import EventValidator
5353
from synapse.logging.context import (
@@ -703,8 +703,20 @@ async def _process_received_pdu(
703703

704704
if not room:
705705
try:
706+
prev_state_ids = await context.get_prev_state_ids()
707+
create_event = await self.store.get_event(
708+
prev_state_ids[(EventTypes.Create, "")]
709+
)
710+
711+
room_version_id = create_event.content.get(
712+
"room_version", RoomVersions.V1.identifier
713+
)
714+
706715
await self.store.store_room(
707-
room_id=room_id, room_creator_user_id="", is_public=False
716+
room_id=room_id,
717+
room_creator_user_id="",
718+
is_public=False,
719+
room_version=KNOWN_ROOM_VERSIONS[room_version_id],
708720
)
709721
except StoreError:
710722
logger.exception("Failed to store room.")
@@ -1186,7 +1198,7 @@ def do_invite_join(self, target_hosts, room_id, joinee, content):
11861198
"""
11871199
logger.debug("Joining %s to %s", joinee, room_id)
11881200

1189-
origin, event, event_format_version = yield self._make_and_verify_event(
1201+
origin, event, room_version = yield self._make_and_verify_event(
11901202
target_hosts,
11911203
room_id,
11921204
joinee,
@@ -1214,6 +1226,8 @@ def do_invite_join(self, target_hosts, room_id, joinee, content):
12141226
target_hosts.insert(0, origin)
12151227
except ValueError:
12161228
pass
1229+
1230+
event_format_version = room_version_to_event_format(room_version.identifier)
12171231
ret = yield self.federation_client.send_join(
12181232
target_hosts, event, event_format_version
12191233
)
@@ -1234,13 +1248,18 @@ def do_invite_join(self, target_hosts, room_id, joinee, content):
12341248

12351249
try:
12361250
yield self.store.store_room(
1237-
room_id=room_id, room_creator_user_id="", is_public=False
1251+
room_id=room_id,
1252+
room_creator_user_id="",
1253+
is_public=False,
1254+
room_version=room_version,
12381255
)
12391256
except Exception:
12401257
# FIXME
12411258
pass
12421259

1243-
yield self._persist_auth_tree(origin, auth_chain, state, event)
1260+
yield self._persist_auth_tree(
1261+
origin, auth_chain, state, event, room_version
1262+
)
12441263

12451264
# Check whether this room is the result of an upgrade of a room we already know
12461265
# about. If so, migrate over user information
@@ -1486,7 +1505,7 @@ def on_invite_request(self, origin, pdu):
14861505

14871506
@defer.inlineCallbacks
14881507
def do_remotely_reject_invite(self, target_hosts, room_id, user_id, content):
1489-
origin, event, event_format_version = yield self._make_and_verify_event(
1508+
origin, event, room_version = yield self._make_and_verify_event(
14901509
target_hosts, room_id, user_id, "leave", content=content
14911510
)
14921511
# Mark as outlier as we don't have any state for this event; we're not
@@ -1513,7 +1532,11 @@ def do_remotely_reject_invite(self, target_hosts, room_id, user_id, content):
15131532
def _make_and_verify_event(
15141533
self, target_hosts, room_id, user_id, membership, content={}, params=None
15151534
):
1516-
origin, event, format_ver = yield self.federation_client.make_membership_event(
1535+
(
1536+
origin,
1537+
event,
1538+
room_version,
1539+
) = yield self.federation_client.make_membership_event(
15171540
target_hosts, room_id, user_id, membership, content, params=params
15181541
)
15191542

@@ -1525,7 +1548,7 @@ def _make_and_verify_event(
15251548
assert event.user_id == user_id
15261549
assert event.state_key == user_id
15271550
assert event.room_id == room_id
1528-
return origin, event, format_ver
1551+
return origin, event, room_version
15291552

15301553
@defer.inlineCallbacks
15311554
@log_function
@@ -1810,7 +1833,14 @@ def prep(ev_info: _NewEventInfo):
18101833
)
18111834

18121835
@defer.inlineCallbacks
1813-
def _persist_auth_tree(self, origin, auth_events, state, event):
1836+
def _persist_auth_tree(
1837+
self,
1838+
origin: str,
1839+
auth_events: List[EventBase],
1840+
state: List[EventBase],
1841+
event: EventBase,
1842+
room_version: RoomVersion,
1843+
):
18141844
"""Checks the auth chain is valid (and passes auth checks) for the
18151845
state and event. Then persists the auth chain and state atomically.
18161846
Persists the event separately. Notifies about the persisted events
@@ -1819,10 +1849,12 @@ def _persist_auth_tree(self, origin, auth_events, state, event):
18191849
Will attempt to fetch missing auth events.
18201850
18211851
Args:
1822-
origin (str): Where the events came from
1823-
auth_events (list)
1824-
state (list)
1825-
event (Event)
1852+
origin: Where the events came from
1853+
auth_events
1854+
state
1855+
event
1856+
room_version: The room version we expect this room to have, and
1857+
will raise if it doesn't match the version in the create event.
18261858
18271859
Returns:
18281860
Deferred
@@ -1848,10 +1880,13 @@ def _persist_auth_tree(self, origin, auth_events, state, event):
18481880
# invalid, and it would fail auth checks anyway.
18491881
raise SynapseError(400, "No create event in state")
18501882

1851-
room_version = create_event.content.get(
1883+
room_version_id = create_event.content.get(
18521884
"room_version", RoomVersions.V1.identifier
18531885
)
18541886

1887+
if room_version.identifier != room_version_id:
1888+
raise SynapseError(400, "Room version mismatch")
1889+
18551890
missing_auth_events = set()
18561891
for e in itertools.chain(auth_events, state, [event]):
18571892
for e_id in e.auth_event_ids():

synapse/handlers/room.py

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
from synapse.api.constants import EventTypes, JoinRules, RoomCreationPreset
3131
from synapse.api.errors import AuthError, Codes, NotFoundError, StoreError, SynapseError
32-
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
32+
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS, RoomVersion
3333
from synapse.http.endpoint import parse_and_validate_server_name
3434
from synapse.storage.state import StateFilter
3535
from synapse.types import (
@@ -100,13 +100,15 @@ def __init__(self, hs):
100100
self.third_party_event_rules = hs.get_third_party_event_rules()
101101

102102
@defer.inlineCallbacks
103-
def upgrade_room(self, requester, old_room_id, new_version):
103+
def upgrade_room(
104+
self, requester: Requester, old_room_id: str, new_version: RoomVersion
105+
):
104106
"""Replace a room with a new room with a different version
105107
106108
Args:
107-
requester (synapse.types.Requester): the user requesting the upgrade
108-
old_room_id (unicode): the id of the room to be replaced
109-
new_version (unicode): the new room version to use
109+
requester: the user requesting the upgrade
110+
old_room_id: the id of the room to be replaced
111+
new_version: the new room version to use
110112
111113
Returns:
112114
Deferred[unicode]: the new room id
@@ -151,7 +153,7 @@ def _upgrade_room(self, requester, old_room_id, new_version):
151153
if r is None:
152154
raise NotFoundError("Unknown room id %s" % (old_room_id,))
153155
new_room_id = yield self._generate_room_id(
154-
creator_id=user_id, is_public=r["is_public"]
156+
creator_id=user_id, is_public=r["is_public"], room_version=new_version,
155157
)
156158

157159
logger.info("Creating new room %s to replace %s", new_room_id, old_room_id)
@@ -299,18 +301,22 @@ def _update_upgraded_room_pls(
299301

300302
@defer.inlineCallbacks
301303
def clone_existing_room(
302-
self, requester, old_room_id, new_room_id, new_room_version, tombstone_event_id
304+
self,
305+
requester: Requester,
306+
old_room_id: str,
307+
new_room_id: str,
308+
new_room_version: RoomVersion,
309+
tombstone_event_id: str,
303310
):
304311
"""Populate a new room based on an old room
305312
306313
Args:
307-
requester (synapse.types.Requester): the user requesting the upgrade
308-
old_room_id (unicode): the id of the room to be replaced
309-
new_room_id (unicode): the id to give the new room (should already have been
314+
requester: the user requesting the upgrade
315+
old_room_id : the id of the room to be replaced
316+
new_room_id: the id to give the new room (should already have been
310317
created with _gemerate_room_id())
311-
new_room_version (unicode): the new room version to use
312-
tombstone_event_id (unicode|str): the ID of the tombstone event in the old
313-
room.
318+
new_room_version: the new room version to use
319+
tombstone_event_id: the ID of the tombstone event in the old room.
314320
Returns:
315321
Deferred
316322
"""
@@ -320,7 +326,7 @@ def clone_existing_room(
320326
raise SynapseError(403, "You are not permitted to create rooms")
321327

322328
creation_content = {
323-
"room_version": new_room_version,
329+
"room_version": new_room_version.identifier,
324330
"predecessor": {"room_id": old_room_id, "event_id": tombstone_event_id},
325331
}
326332

@@ -577,14 +583,15 @@ def create_room(self, requester, config, ratelimit=True, creator_join_profile=No
577583
if ratelimit:
578584
yield self.ratelimit(requester)
579585

580-
room_version = config.get(
586+
room_version_id = config.get(
581587
"room_version", self.config.default_room_version.identifier
582588
)
583589

584-
if not isinstance(room_version, string_types):
590+
if not isinstance(room_version_id, string_types):
585591
raise SynapseError(400, "room_version must be a string", Codes.BAD_JSON)
586592

587-
if room_version not in KNOWN_ROOM_VERSIONS:
593+
room_version = KNOWN_ROOM_VERSIONS.get(room_version_id)
594+
if room_version is None:
588595
raise SynapseError(
589596
400,
590597
"Your homeserver does not support this room version",
@@ -631,7 +638,9 @@ def create_room(self, requester, config, ratelimit=True, creator_join_profile=No
631638
visibility = config.get("visibility", None)
632639
is_public = visibility == "public"
633640

634-
room_id = yield self._generate_room_id(creator_id=user_id, is_public=is_public)
641+
room_id = yield self._generate_room_id(
642+
creator_id=user_id, is_public=is_public, room_version=room_version,
643+
)
635644

636645
directory_handler = self.hs.get_handlers().directory_handler
637646
if room_alias:
@@ -660,7 +669,7 @@ def create_room(self, requester, config, ratelimit=True, creator_join_profile=No
660669
creation_content = config.get("creation_content", {})
661670

662671
# override any attempt to set room versions via the creation_content
663-
creation_content["room_version"] = room_version
672+
creation_content["room_version"] = room_version.identifier
664673

665674
yield self._send_events_for_new_room(
666675
requester,
@@ -849,7 +858,9 @@ def send(etype, content, **kwargs):
849858
yield send(etype=etype, state_key=state_key, content=content)
850859

851860
@defer.inlineCallbacks
852-
def _generate_room_id(self, creator_id, is_public):
861+
def _generate_room_id(
862+
self, creator_id: str, is_public: str, room_version: RoomVersion,
863+
):
853864
# autogen room IDs and try to create it. We may clash, so just
854865
# try a few times till one goes through, giving up eventually.
855866
attempts = 0
@@ -863,6 +874,7 @@ def _generate_room_id(self, creator_id, is_public):
863874
room_id=gen_room_id,
864875
room_creator_user_id=creator_id,
865876
is_public=is_public,
877+
room_version=room_version,
866878
)
867879
return gen_room_id
868880
except StoreError:

0 commit comments

Comments
 (0)