forked from MirrorHub/synapse
Basic support for room versioning
This is the first tranche of support for room versioning. It includes: * setting the default room version in the config file * new room_version param on the createRoom API * storing the version of newly-created rooms in the m.room.create event * fishing the version of existing rooms out of the m.room.create event
This commit is contained in:
parent
15c1ae45e5
commit
0ca459ea33
7 changed files with 83 additions and 5 deletions
|
@ -1,6 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright 2014-2016 OpenMarket Ltd
|
# Copyright 2014-2016 OpenMarket Ltd
|
||||||
# Copyright 2017 Vector Creations Ltd
|
# Copyright 2017 Vector Creations Ltd
|
||||||
|
# Copyright 2018 New Vector Ltd.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
|
@ -94,3 +95,8 @@ class RoomCreationPreset(object):
|
||||||
class ThirdPartyEntityKind(object):
|
class ThirdPartyEntityKind(object):
|
||||||
USER = "user"
|
USER = "user"
|
||||||
LOCATION = "location"
|
LOCATION = "location"
|
||||||
|
|
||||||
|
|
||||||
|
# vdh-test-version is a placeholder to get room versioning support working and tested
|
||||||
|
# until we have a working v2.
|
||||||
|
KNOWN_ROOM_VERSIONS = {"1", "vdh-test-version"}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright 2014-2016 OpenMarket Ltd
|
# Copyright 2014-2016 OpenMarket Ltd
|
||||||
|
# Copyright 2018 New Vector Ltd.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
|
@ -56,6 +57,7 @@ class Codes(object):
|
||||||
CONSENT_NOT_GIVEN = "M_CONSENT_NOT_GIVEN"
|
CONSENT_NOT_GIVEN = "M_CONSENT_NOT_GIVEN"
|
||||||
CANNOT_LEAVE_SERVER_NOTICE_ROOM = "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM"
|
CANNOT_LEAVE_SERVER_NOTICE_ROOM = "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM"
|
||||||
MAU_LIMIT_EXCEEDED = "M_MAU_LIMIT_EXCEEDED"
|
MAU_LIMIT_EXCEEDED = "M_MAU_LIMIT_EXCEEDED"
|
||||||
|
UNSUPPORTED_ROOM_VERSION = "M_UNSUPPORTED_ROOM_VERSION"
|
||||||
|
|
||||||
|
|
||||||
class CodeMessageException(RuntimeError):
|
class CodeMessageException(RuntimeError):
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from synapse.api.constants import KNOWN_ROOM_VERSIONS
|
||||||
from synapse.http.endpoint import parse_and_validate_server_name
|
from synapse.http.endpoint import parse_and_validate_server_name
|
||||||
|
|
||||||
from ._base import Config, ConfigError
|
from ._base import Config, ConfigError
|
||||||
|
@ -75,6 +76,16 @@ class ServerConfig(Config):
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.max_mau_value = 0
|
self.max_mau_value = 0
|
||||||
|
|
||||||
|
# the version of rooms created by default on this server
|
||||||
|
self.default_room_version = str(config.get(
|
||||||
|
"default_room_version", "1",
|
||||||
|
))
|
||||||
|
if self.default_room_version not in KNOWN_ROOM_VERSIONS:
|
||||||
|
raise ConfigError("Unrecognised value '%s' for default_room_version" % (
|
||||||
|
self.default_room_version,
|
||||||
|
))
|
||||||
|
|
||||||
# FIXME: federation_domain_whitelist needs sytests
|
# FIXME: federation_domain_whitelist needs sytests
|
||||||
self.federation_domain_whitelist = None
|
self.federation_domain_whitelist = None
|
||||||
federation_domain_whitelist = config.get(
|
federation_domain_whitelist = config.get(
|
||||||
|
@ -249,6 +260,9 @@ class ServerConfig(Config):
|
||||||
# (except those sent by local server admins). The default is False.
|
# (except those sent by local server admins). The default is False.
|
||||||
# block_non_admin_invites: True
|
# block_non_admin_invites: True
|
||||||
|
|
||||||
|
# The room_version of rooms which are created by default by this server.
|
||||||
|
# default_room_version: 1
|
||||||
|
|
||||||
# Restrict federation to the following whitelist of domains.
|
# Restrict federation to the following whitelist of domains.
|
||||||
# N.B. we recommend also firewalling your federation listener to limit
|
# N.B. we recommend also firewalling your federation listener to limit
|
||||||
# inbound federation traffic as early as possible, rather than relying
|
# inbound federation traffic as early as possible, rather than relying
|
||||||
|
|
|
@ -21,9 +21,16 @@ import math
|
||||||
import string
|
import string
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
from six import string_types
|
||||||
|
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
|
|
||||||
from synapse.api.constants import EventTypes, JoinRules, RoomCreationPreset
|
from synapse.api.constants import (
|
||||||
|
KNOWN_ROOM_VERSIONS,
|
||||||
|
EventTypes,
|
||||||
|
JoinRules,
|
||||||
|
RoomCreationPreset,
|
||||||
|
)
|
||||||
from synapse.api.errors import AuthError, Codes, StoreError, SynapseError
|
from synapse.api.errors import AuthError, Codes, StoreError, SynapseError
|
||||||
from synapse.types import RoomAlias, RoomID, RoomStreamToken, StreamToken, UserID
|
from synapse.types import RoomAlias, RoomID, RoomStreamToken, StreamToken, UserID
|
||||||
from synapse.util import stringutils
|
from synapse.util import stringutils
|
||||||
|
@ -99,6 +106,21 @@ class RoomCreationHandler(BaseHandler):
|
||||||
if ratelimit:
|
if ratelimit:
|
||||||
yield self.ratelimit(requester)
|
yield self.ratelimit(requester)
|
||||||
|
|
||||||
|
room_version = config.get("room_version", self.hs.config.default_room_version)
|
||||||
|
if not isinstance(room_version, string_types):
|
||||||
|
raise SynapseError(
|
||||||
|
400,
|
||||||
|
"room_version must be a string",
|
||||||
|
Codes.BAD_JSON,
|
||||||
|
)
|
||||||
|
|
||||||
|
if room_version not in KNOWN_ROOM_VERSIONS:
|
||||||
|
raise SynapseError(
|
||||||
|
400,
|
||||||
|
"Your homeserver does not support this room version",
|
||||||
|
Codes.UNSUPPORTED_ROOM_VERSION,
|
||||||
|
)
|
||||||
|
|
||||||
if "room_alias_name" in config:
|
if "room_alias_name" in config:
|
||||||
for wchar in string.whitespace:
|
for wchar in string.whitespace:
|
||||||
if wchar in config["room_alias_name"]:
|
if wchar in config["room_alias_name"]:
|
||||||
|
@ -184,6 +206,9 @@ class RoomCreationHandler(BaseHandler):
|
||||||
|
|
||||||
creation_content = config.get("creation_content", {})
|
creation_content = config.get("creation_content", {})
|
||||||
|
|
||||||
|
# override any attempt to set room versions via the creation_content
|
||||||
|
creation_content["room_version"] = room_version
|
||||||
|
|
||||||
room_member_handler = self.hs.get_room_member_handler()
|
room_member_handler = self.hs.get_room_member_handler()
|
||||||
|
|
||||||
yield self._send_events_for_new_room(
|
yield self._send_events_for_new_room(
|
||||||
|
|
|
@ -44,8 +44,8 @@ class SlavedEventStore(EventFederationWorkerStore,
|
||||||
RoomMemberWorkerStore,
|
RoomMemberWorkerStore,
|
||||||
EventPushActionsWorkerStore,
|
EventPushActionsWorkerStore,
|
||||||
StreamWorkerStore,
|
StreamWorkerStore,
|
||||||
EventsWorkerStore,
|
|
||||||
StateGroupWorkerStore,
|
StateGroupWorkerStore,
|
||||||
|
EventsWorkerStore,
|
||||||
SignatureWorkerStore,
|
SignatureWorkerStore,
|
||||||
UserErasureWorkerStore,
|
UserErasureWorkerStore,
|
||||||
BaseSlavedStore):
|
BaseSlavedStore):
|
||||||
|
|
|
@ -21,15 +21,17 @@ from six.moves import range
|
||||||
|
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
|
|
||||||
|
from synapse.api.constants import EventTypes
|
||||||
|
from synapse.api.errors import NotFoundError
|
||||||
|
from synapse.storage._base import SQLBaseStore
|
||||||
from synapse.storage.background_updates import BackgroundUpdateStore
|
from synapse.storage.background_updates import BackgroundUpdateStore
|
||||||
from synapse.storage.engines import PostgresEngine
|
from synapse.storage.engines import PostgresEngine
|
||||||
|
from synapse.storage.events_worker import EventsWorkerStore
|
||||||
from synapse.util.caches import get_cache_factor_for, intern_string
|
from synapse.util.caches import get_cache_factor_for, intern_string
|
||||||
from synapse.util.caches.descriptors import cached, cachedList
|
from synapse.util.caches.descriptors import cached, cachedList
|
||||||
from synapse.util.caches.dictionary_cache import DictionaryCache
|
from synapse.util.caches.dictionary_cache import DictionaryCache
|
||||||
from synapse.util.stringutils import to_ascii
|
from synapse.util.stringutils import to_ascii
|
||||||
|
|
||||||
from ._base import SQLBaseStore
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,7 +48,8 @@ class _GetStateGroupDelta(namedtuple("_GetStateGroupDelta", ("prev_group", "delt
|
||||||
return len(self.delta_ids) if self.delta_ids else 0
|
return len(self.delta_ids) if self.delta_ids else 0
|
||||||
|
|
||||||
|
|
||||||
class StateGroupWorkerStore(SQLBaseStore):
|
# this inherits from EventsWorkerStore because it calls self.get_events
|
||||||
|
class StateGroupWorkerStore(EventsWorkerStore, SQLBaseStore):
|
||||||
"""The parts of StateGroupStore that can be called from workers.
|
"""The parts of StateGroupStore that can be called from workers.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -61,6 +64,30 @@ class StateGroupWorkerStore(SQLBaseStore):
|
||||||
"*stateGroupCache*", 500000 * get_cache_factor_for("stateGroupCache")
|
"*stateGroupCache*", 500000 * get_cache_factor_for("stateGroupCache")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def get_room_version(self, room_id):
|
||||||
|
"""Get the room_version of a given room
|
||||||
|
|
||||||
|
Args:
|
||||||
|
room_id (str)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Deferred[str]
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotFoundError if the room is unknown
|
||||||
|
"""
|
||||||
|
# for now we do this by looking at the create event. We may want to cache this
|
||||||
|
# more intelligently in future.
|
||||||
|
state_ids = yield self.get_current_state_ids(room_id)
|
||||||
|
create_id = state_ids.get((EventTypes.Create, ""))
|
||||||
|
|
||||||
|
if not create_id:
|
||||||
|
raise NotFoundError("Unknown room")
|
||||||
|
|
||||||
|
create_event = yield self.get_event(create_id)
|
||||||
|
defer.returnValue(create_event.content.get("room_version", "1"))
|
||||||
|
|
||||||
@cached(max_entries=100000, iterable=True)
|
@cached(max_entries=100000, iterable=True)
|
||||||
def get_current_state_ids(self, room_id):
|
def get_current_state_ids(self, room_id):
|
||||||
"""Get the current state event ids for a room based on the
|
"""Get the current state event ids for a room based on the
|
||||||
|
|
|
@ -74,6 +74,10 @@ def setup_test_homeserver(name="test", datastore=None, config=None, reactor=None
|
||||||
config.media_storage_providers = []
|
config.media_storage_providers = []
|
||||||
config.auto_join_rooms = []
|
config.auto_join_rooms = []
|
||||||
|
|
||||||
|
# we need a sane default_room_version, otherwise attempts to create rooms will
|
||||||
|
# fail.
|
||||||
|
config.default_room_version = "1"
|
||||||
|
|
||||||
# disable user directory updates, because they get done in the
|
# disable user directory updates, because they get done in the
|
||||||
# background, which upsets the test runner.
|
# background, which upsets the test runner.
|
||||||
config.update_user_directory = False
|
config.update_user_directory = False
|
||||||
|
|
Loading…
Reference in a new issue