mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2024-10-01 11:49:51 -04:00
Merge pull request #2976 from matrix-org/erikj/replication_registry
Split out edu/query registration to a separate class
This commit is contained in:
commit
141c343e03
@ -17,7 +17,7 @@ import logging
|
|||||||
import simplejson as json
|
import simplejson as json
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
|
|
||||||
from synapse.api.errors import AuthError, FederationError, SynapseError
|
from synapse.api.errors import AuthError, FederationError, SynapseError, NotFoundError
|
||||||
from synapse.crypto.event_signing import compute_event_signature
|
from synapse.crypto.event_signing import compute_event_signature
|
||||||
from synapse.federation.federation_base import (
|
from synapse.federation.federation_base import (
|
||||||
FederationBase,
|
FederationBase,
|
||||||
@ -56,6 +56,8 @@ class FederationServer(FederationBase):
|
|||||||
self._server_linearizer = async.Linearizer("fed_server")
|
self._server_linearizer = async.Linearizer("fed_server")
|
||||||
self._transaction_linearizer = async.Linearizer("fed_txn_handler")
|
self._transaction_linearizer = async.Linearizer("fed_txn_handler")
|
||||||
|
|
||||||
|
self.registry = hs.get_federation_registry()
|
||||||
|
|
||||||
# We cache responses to state queries, as they take a while and often
|
# We cache responses to state queries, as they take a while and often
|
||||||
# come in waves.
|
# come in waves.
|
||||||
self._state_resp_cache = ResponseCache(hs, timeout_ms=30000)
|
self._state_resp_cache = ResponseCache(hs, timeout_ms=30000)
|
||||||
@ -67,35 +69,6 @@ class FederationServer(FederationBase):
|
|||||||
"""
|
"""
|
||||||
self.handler = handler
|
self.handler = handler
|
||||||
|
|
||||||
def register_edu_handler(self, edu_type, handler):
|
|
||||||
if edu_type in self.edu_handlers:
|
|
||||||
raise KeyError("Already have an EDU handler for %s" % (edu_type,))
|
|
||||||
|
|
||||||
self.edu_handlers[edu_type] = handler
|
|
||||||
|
|
||||||
def register_query_handler(self, query_type, handler):
|
|
||||||
"""Sets the handler callable that will be used to handle an incoming
|
|
||||||
federation Query of the given type.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
query_type (str): Category name of the query, which should match
|
|
||||||
the string used by make_query.
|
|
||||||
handler (callable): Invoked to handle incoming queries of this type
|
|
||||||
|
|
||||||
handler is invoked as:
|
|
||||||
result = handler(args)
|
|
||||||
|
|
||||||
where 'args' is a dict mapping strings to strings of the query
|
|
||||||
arguments. It should return a Deferred that will eventually yield an
|
|
||||||
object to encode as JSON.
|
|
||||||
"""
|
|
||||||
if query_type in self.query_handlers:
|
|
||||||
raise KeyError(
|
|
||||||
"Already have a Query handler for %s" % (query_type,)
|
|
||||||
)
|
|
||||||
|
|
||||||
self.query_handlers[query_type] = handler
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
@log_function
|
@log_function
|
||||||
def on_backfill_request(self, origin, room_id, versions, limit):
|
def on_backfill_request(self, origin, room_id, versions, limit):
|
||||||
@ -229,16 +202,7 @@ class FederationServer(FederationBase):
|
|||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def received_edu(self, origin, edu_type, content):
|
def received_edu(self, origin, edu_type, content):
|
||||||
received_edus_counter.inc()
|
received_edus_counter.inc()
|
||||||
|
yield self.registry.on_edu(edu_type, origin, content)
|
||||||
if edu_type in self.edu_handlers:
|
|
||||||
try:
|
|
||||||
yield self.edu_handlers[edu_type](origin, content)
|
|
||||||
except SynapseError as e:
|
|
||||||
logger.info("Failed to handle edu %r: %r", edu_type, e)
|
|
||||||
except Exception as e:
|
|
||||||
logger.exception("Failed to handle edu %r", edu_type)
|
|
||||||
else:
|
|
||||||
logger.warn("Received EDU of type %s with no handler", edu_type)
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
@log_function
|
@log_function
|
||||||
@ -328,14 +292,8 @@ class FederationServer(FederationBase):
|
|||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_query_request(self, query_type, args):
|
def on_query_request(self, query_type, args):
|
||||||
received_queries_counter.inc(query_type)
|
received_queries_counter.inc(query_type)
|
||||||
|
resp = yield self.registry.on_query(query_type, args)
|
||||||
if query_type in self.query_handlers:
|
defer.returnValue((200, resp))
|
||||||
response = yield self.query_handlers[query_type](args)
|
|
||||||
defer.returnValue((200, response))
|
|
||||||
else:
|
|
||||||
defer.returnValue(
|
|
||||||
(404, "No handler for Query type '%s'" % (query_type,))
|
|
||||||
)
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_make_join_request(self, room_id, user_id):
|
def on_make_join_request(self, room_id, user_id):
|
||||||
@ -607,3 +565,66 @@ class FederationServer(FederationBase):
|
|||||||
origin, room_id, event_dict
|
origin, room_id, event_dict
|
||||||
)
|
)
|
||||||
defer.returnValue(ret)
|
defer.returnValue(ret)
|
||||||
|
|
||||||
|
|
||||||
|
class FederationHandlerRegistry(object):
|
||||||
|
"""Allows classes to register themselves as handlers for a given EDU or
|
||||||
|
query type for incoming federation traffic.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self.edu_handlers = {}
|
||||||
|
self.query_handlers = {}
|
||||||
|
|
||||||
|
def register_edu_handler(self, edu_type, handler):
|
||||||
|
"""Sets the handler callable that will be used to handle an incoming
|
||||||
|
federation EDU of the given type.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
edu_type (str): The type of the incoming EDU to register handler for
|
||||||
|
handler (Callable[[str, dict]]): A callable invoked on incoming EDU
|
||||||
|
of the given type. The arguments are the origin server name and
|
||||||
|
the EDU contents.
|
||||||
|
"""
|
||||||
|
if edu_type in self.edu_handlers:
|
||||||
|
raise KeyError("Already have an EDU handler for %s" % (edu_type,))
|
||||||
|
|
||||||
|
self.edu_handlers[edu_type] = handler
|
||||||
|
|
||||||
|
def register_query_handler(self, query_type, handler):
|
||||||
|
"""Sets the handler callable that will be used to handle an incoming
|
||||||
|
federation query of the given type.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query_type (str): Category name of the query, which should match
|
||||||
|
the string used by make_query.
|
||||||
|
handler (Callable[[dict], Deferred[dict]]): Invoked to handle
|
||||||
|
incoming queries of this type. The return will be yielded
|
||||||
|
on and the result used as the response to the query request.
|
||||||
|
"""
|
||||||
|
if query_type in self.query_handlers:
|
||||||
|
raise KeyError(
|
||||||
|
"Already have a Query handler for %s" % (query_type,)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.query_handlers[query_type] = handler
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_edu(self, edu_type, origin, content):
|
||||||
|
handler = self.edu_handlers.get(edu_type)
|
||||||
|
if not handler:
|
||||||
|
logger.warn("No handler registered for EDU type %s", edu_type)
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield handler(origin, content)
|
||||||
|
except SynapseError as e:
|
||||||
|
logger.info("Failed to handle edu %r: %r", edu_type, e)
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception("Failed to handle edu %r", edu_type)
|
||||||
|
|
||||||
|
def on_query(self, query_type, args):
|
||||||
|
handler = self.query_handlers.get(query_type)
|
||||||
|
if not handler:
|
||||||
|
logger.warn("No handler registered for query type %s", query_type)
|
||||||
|
raise NotFoundError("No handler for Query type '%s'" % (query_type,))
|
||||||
|
|
||||||
|
return handler(args)
|
||||||
|
@ -41,10 +41,12 @@ class DeviceHandler(BaseHandler):
|
|||||||
|
|
||||||
self._edu_updater = DeviceListEduUpdater(hs, self)
|
self._edu_updater = DeviceListEduUpdater(hs, self)
|
||||||
|
|
||||||
self.federation.register_edu_handler(
|
federation_registry = hs.get_federation_registry()
|
||||||
|
|
||||||
|
federation_registry.register_edu_handler(
|
||||||
"m.device_list_update", self._edu_updater.incoming_device_list_update,
|
"m.device_list_update", self._edu_updater.incoming_device_list_update,
|
||||||
)
|
)
|
||||||
self.federation.register_query_handler(
|
federation_registry.register_query_handler(
|
||||||
"user_devices", self.on_federation_query_user_devices,
|
"user_devices", self.on_federation_query_user_devices,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ class DeviceMessageHandler(object):
|
|||||||
self.is_mine = hs.is_mine
|
self.is_mine = hs.is_mine
|
||||||
self.federation = hs.get_federation_sender()
|
self.federation = hs.get_federation_sender()
|
||||||
|
|
||||||
hs.get_replication_layer().register_edu_handler(
|
hs.get_federation_registry().register_edu_handler(
|
||||||
"m.direct_to_device", self.on_direct_to_device_edu
|
"m.direct_to_device", self.on_direct_to_device_edu
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ class DirectoryHandler(BaseHandler):
|
|||||||
self.event_creation_handler = hs.get_event_creation_handler()
|
self.event_creation_handler = hs.get_event_creation_handler()
|
||||||
|
|
||||||
self.federation = hs.get_replication_layer()
|
self.federation = hs.get_replication_layer()
|
||||||
self.federation.register_query_handler(
|
hs.get_federation_registry().register_query_handler(
|
||||||
"directory", self.on_directory_query
|
"directory", self.on_directory_query
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ class E2eKeysHandler(object):
|
|||||||
# doesn't really work as part of the generic query API, because the
|
# doesn't really work as part of the generic query API, because the
|
||||||
# query request requires an object POST, but we abuse the
|
# query request requires an object POST, but we abuse the
|
||||||
# "query handler" interface.
|
# "query handler" interface.
|
||||||
self.federation.register_query_handler(
|
hs.get_federation_registry().register_query_handler(
|
||||||
"client_keys", self.on_federation_query_client_keys
|
"client_keys", self.on_federation_query_client_keys
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -98,24 +98,26 @@ class PresenceHandler(object):
|
|||||||
|
|
||||||
self.state = hs.get_state_handler()
|
self.state = hs.get_state_handler()
|
||||||
|
|
||||||
self.replication.register_edu_handler(
|
federation_registry = hs.get_federation_registry()
|
||||||
|
|
||||||
|
federation_registry.register_edu_handler(
|
||||||
"m.presence", self.incoming_presence
|
"m.presence", self.incoming_presence
|
||||||
)
|
)
|
||||||
self.replication.register_edu_handler(
|
federation_registry.register_edu_handler(
|
||||||
"m.presence_invite",
|
"m.presence_invite",
|
||||||
lambda origin, content: self.invite_presence(
|
lambda origin, content: self.invite_presence(
|
||||||
observed_user=UserID.from_string(content["observed_user"]),
|
observed_user=UserID.from_string(content["observed_user"]),
|
||||||
observer_user=UserID.from_string(content["observer_user"]),
|
observer_user=UserID.from_string(content["observer_user"]),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.replication.register_edu_handler(
|
federation_registry.register_edu_handler(
|
||||||
"m.presence_accept",
|
"m.presence_accept",
|
||||||
lambda origin, content: self.accept_presence(
|
lambda origin, content: self.accept_presence(
|
||||||
observed_user=UserID.from_string(content["observed_user"]),
|
observed_user=UserID.from_string(content["observed_user"]),
|
||||||
observer_user=UserID.from_string(content["observer_user"]),
|
observer_user=UserID.from_string(content["observer_user"]),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.replication.register_edu_handler(
|
federation_registry.register_edu_handler(
|
||||||
"m.presence_deny",
|
"m.presence_deny",
|
||||||
lambda origin, content: self.deny_presence(
|
lambda origin, content: self.deny_presence(
|
||||||
observed_user=UserID.from_string(content["observed_user"]),
|
observed_user=UserID.from_string(content["observed_user"]),
|
||||||
|
@ -32,7 +32,7 @@ class ProfileHandler(BaseHandler):
|
|||||||
super(ProfileHandler, self).__init__(hs)
|
super(ProfileHandler, self).__init__(hs)
|
||||||
|
|
||||||
self.federation = hs.get_replication_layer()
|
self.federation = hs.get_replication_layer()
|
||||||
self.federation.register_query_handler(
|
hs.get_federation_registry().register_query_handler(
|
||||||
"profile", self.on_profile_query
|
"profile", self.on_profile_query
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ class ReceiptsHandler(BaseHandler):
|
|||||||
self.store = hs.get_datastore()
|
self.store = hs.get_datastore()
|
||||||
self.hs = hs
|
self.hs = hs
|
||||||
self.federation = hs.get_federation_sender()
|
self.federation = hs.get_federation_sender()
|
||||||
hs.get_replication_layer().register_edu_handler(
|
hs.get_federation_registry().register_edu_handler(
|
||||||
"m.receipt", self._received_remote_receipt
|
"m.receipt", self._received_remote_receipt
|
||||||
)
|
)
|
||||||
self.clock = self.hs.get_clock()
|
self.clock = self.hs.get_clock()
|
||||||
|
@ -56,7 +56,7 @@ class TypingHandler(object):
|
|||||||
|
|
||||||
self.federation = hs.get_federation_sender()
|
self.federation = hs.get_federation_sender()
|
||||||
|
|
||||||
hs.get_replication_layer().register_edu_handler("m.typing", self._recv_edu)
|
hs.get_federation_registry().register_edu_handler("m.typing", self._recv_edu)
|
||||||
|
|
||||||
hs.get_distributor().observe("user_left_room", self.user_left_room)
|
hs.get_distributor().observe("user_left_room", self.user_left_room)
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ from synapse.events.builder import EventBuilderFactory
|
|||||||
from synapse.events.spamcheck import SpamChecker
|
from synapse.events.spamcheck import SpamChecker
|
||||||
from synapse.federation import initialize_http_replication
|
from synapse.federation import initialize_http_replication
|
||||||
from synapse.federation.send_queue import FederationRemoteSendQueue
|
from synapse.federation.send_queue import FederationRemoteSendQueue
|
||||||
|
from synapse.federation.federation_server import FederationHandlerRegistry
|
||||||
from synapse.federation.transport.client import TransportLayerClient
|
from synapse.federation.transport.client import TransportLayerClient
|
||||||
from synapse.federation.transaction_queue import TransactionQueue
|
from synapse.federation.transaction_queue import TransactionQueue
|
||||||
from synapse.handlers import Handlers
|
from synapse.handlers import Handlers
|
||||||
@ -147,6 +148,7 @@ class HomeServer(object):
|
|||||||
'groups_attestation_renewer',
|
'groups_attestation_renewer',
|
||||||
'spam_checker',
|
'spam_checker',
|
||||||
'room_member_handler',
|
'room_member_handler',
|
||||||
|
'federation_registry',
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, hostname, **kwargs):
|
def __init__(self, hostname, **kwargs):
|
||||||
@ -387,6 +389,9 @@ class HomeServer(object):
|
|||||||
def build_room_member_handler(self):
|
def build_room_member_handler(self):
|
||||||
return RoomMemberHandler(self)
|
return RoomMemberHandler(self)
|
||||||
|
|
||||||
|
def build_federation_registry(self):
|
||||||
|
return FederationHandlerRegistry()
|
||||||
|
|
||||||
def remove_pusher(self, app_id, push_key, user_id):
|
def remove_pusher(self, app_id, push_key, user_id):
|
||||||
return self.get_pusherpool().remove_pusher(app_id, push_key, user_id)
|
return self.get_pusherpool().remove_pusher(app_id, push_key, user_id)
|
||||||
|
|
||||||
|
@ -35,21 +35,20 @@ class DirectoryTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.mock_federation = Mock(spec=[
|
self.mock_federation = Mock()
|
||||||
"make_query",
|
self.mock_registry = Mock()
|
||||||
"register_edu_handler",
|
|
||||||
])
|
|
||||||
|
|
||||||
self.query_handlers = {}
|
self.query_handlers = {}
|
||||||
|
|
||||||
def register_query_handler(query_type, handler):
|
def register_query_handler(query_type, handler):
|
||||||
self.query_handlers[query_type] = handler
|
self.query_handlers[query_type] = handler
|
||||||
self.mock_federation.register_query_handler = register_query_handler
|
self.mock_registry.register_query_handler = register_query_handler
|
||||||
|
|
||||||
hs = yield setup_test_homeserver(
|
hs = yield setup_test_homeserver(
|
||||||
http_client=None,
|
http_client=None,
|
||||||
resource_for_federation=Mock(),
|
resource_for_federation=Mock(),
|
||||||
replication_layer=self.mock_federation,
|
replication_layer=self.mock_federation,
|
||||||
|
federation_registry=self.mock_registry,
|
||||||
)
|
)
|
||||||
hs.handlers = DirectoryHandlers(hs)
|
hs.handlers = DirectoryHandlers(hs)
|
||||||
|
|
||||||
|
@ -37,23 +37,22 @@ class ProfileTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.mock_federation = Mock(spec=[
|
self.mock_federation = Mock()
|
||||||
"make_query",
|
self.mock_registry = Mock()
|
||||||
"register_edu_handler",
|
|
||||||
])
|
|
||||||
|
|
||||||
self.query_handlers = {}
|
self.query_handlers = {}
|
||||||
|
|
||||||
def register_query_handler(query_type, handler):
|
def register_query_handler(query_type, handler):
|
||||||
self.query_handlers[query_type] = handler
|
self.query_handlers[query_type] = handler
|
||||||
|
|
||||||
self.mock_federation.register_query_handler = register_query_handler
|
self.mock_registry.register_query_handler = register_query_handler
|
||||||
|
|
||||||
hs = yield setup_test_homeserver(
|
hs = yield setup_test_homeserver(
|
||||||
http_client=None,
|
http_client=None,
|
||||||
handlers=None,
|
handlers=None,
|
||||||
resource_for_federation=Mock(),
|
resource_for_federation=Mock(),
|
||||||
replication_layer=self.mock_federation,
|
replication_layer=self.mock_federation,
|
||||||
|
federation_registry=self.mock_registry,
|
||||||
ratelimiter=NonCallableMock(spec_set=[
|
ratelimiter=NonCallableMock(spec_set=[
|
||||||
"send_message",
|
"send_message",
|
||||||
])
|
])
|
||||||
|
Loading…
Reference in New Issue
Block a user