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

Commit 7ccc251

Browse files
authored
Merge pull request #5859 from matrix-org/rei/msc2197
MSC2197 Search Filters over Federation
2 parents dfd10f5 + 5027287 commit 7ccc251

File tree

4 files changed

+96
-16
lines changed

4 files changed

+96
-16
lines changed

changelog.d/5859.feature

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add unstable support for MSC2197 (filtered search requests over federation), in order to allow upcoming room directory query performance improvements.

synapse/federation/transport/client.py

+31-15
Original file line numberDiff line numberDiff line change
@@ -327,21 +327,37 @@ def get_public_rooms(
327327
include_all_networks=False,
328328
third_party_instance_id=None,
329329
):
330-
path = _create_v1_path("/publicRooms")
331-
332-
args = {"include_all_networks": "true" if include_all_networks else "false"}
333-
if third_party_instance_id:
334-
args["third_party_instance_id"] = (third_party_instance_id,)
335-
if limit:
336-
args["limit"] = [str(limit)]
337-
if since_token:
338-
args["since"] = [since_token]
339-
340-
# TODO(erikj): Actually send the search_filter across federation.
341-
342-
response = yield self.client.get_json(
343-
destination=remote_server, path=path, args=args, ignore_backoff=True
344-
)
330+
if search_filter:
331+
# this uses MSC2197 (Search Filtering over Federation)
332+
path = _create_v1_path("/publicRooms")
333+
334+
data = {"include_all_networks": "true" if include_all_networks else "false"}
335+
if third_party_instance_id:
336+
data["third_party_instance_id"] = third_party_instance_id
337+
if limit:
338+
data["limit"] = str(limit)
339+
if since_token:
340+
data["since"] = since_token
341+
342+
data["filter"] = search_filter
343+
344+
response = yield self.client.post_json(
345+
destination=remote_server, path=path, data=data, ignore_backoff=True
346+
)
347+
else:
348+
path = _create_v1_path("/publicRooms")
349+
350+
args = {"include_all_networks": "true" if include_all_networks else "false"}
351+
if third_party_instance_id:
352+
args["third_party_instance_id"] = (third_party_instance_id,)
353+
if limit:
354+
args["limit"] = [str(limit)]
355+
if since_token:
356+
args["since"] = [since_token]
357+
358+
response = yield self.client.get_json(
359+
destination=remote_server, path=path, args=args, ignore_backoff=True
360+
)
345361

346362
return response
347363

synapse/federation/transport/server.py

+36
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,42 @@ async def on_GET(self, origin, content, query):
770770
)
771771
return 200, data
772772

773+
async def on_POST(self, origin, content, query):
774+
# This implements MSC2197 (Search Filtering over Federation)
775+
if not self.allow_access:
776+
raise FederationDeniedError(origin)
777+
778+
limit = int(content.get("limit", 100))
779+
since_token = content.get("since", None)
780+
search_filter = content.get("filter", None)
781+
782+
include_all_networks = content.get("include_all_networks", False)
783+
third_party_instance_id = content.get("third_party_instance_id", None)
784+
785+
if include_all_networks:
786+
network_tuple = None
787+
if third_party_instance_id is not None:
788+
raise SynapseError(
789+
400, "Can't use include_all_networks with an explicit network"
790+
)
791+
elif third_party_instance_id is None:
792+
network_tuple = ThirdPartyInstanceID(None, None)
793+
else:
794+
network_tuple = ThirdPartyInstanceID.from_string(third_party_instance_id)
795+
796+
if search_filter is None:
797+
logger.warning("Nonefilter")
798+
799+
data = await self.handler.get_local_public_room_list(
800+
limit=limit,
801+
since_token=since_token,
802+
search_filter=search_filter,
803+
network_tuple=network_tuple,
804+
from_federation=True,
805+
)
806+
807+
return 200, data
808+
773809

774810
class FederationVersionServlet(BaseFederationServlet):
775811
PATH = "/version"

synapse/handlers/room_list.py

+28-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from twisted.internet import defer
2626

2727
from synapse.api.constants import EventTypes, JoinRules
28+
from synapse.api.errors import Codes, HttpResponseException
2829
from synapse.types import ThirdPartyInstanceID
2930
from synapse.util.async_helpers import concurrently_execute
3031
from synapse.util.caches.descriptors import cachedInlineCallbacks
@@ -485,7 +486,33 @@ def get_remote_public_room_list(
485486
return {"chunk": [], "total_room_count_estimate": 0}
486487

487488
if search_filter:
488-
# We currently don't support searching across federation, so we have
489+
# Searching across federation is defined in MSC2197.
490+
# However, the remote homeserver may or may not actually support it.
491+
# So we first try an MSC2197 remote-filtered search, then fall back
492+
# to a locally-filtered search if we must.
493+
494+
try:
495+
res = yield self._get_remote_list_cached(
496+
server_name,
497+
limit=limit,
498+
since_token=since_token,
499+
include_all_networks=include_all_networks,
500+
third_party_instance_id=third_party_instance_id,
501+
search_filter=search_filter,
502+
)
503+
return res
504+
except HttpResponseException as hre:
505+
syn_err = hre.to_synapse_error()
506+
if hre.code in (404, 405) or syn_err.errcode in (
507+
Codes.UNRECOGNIZED,
508+
Codes.NOT_FOUND,
509+
):
510+
logger.debug("Falling back to locally-filtered /publicRooms")
511+
else:
512+
raise # Not an error that should trigger a fallback.
513+
514+
# if we reach this point, then we fall back to the situation where
515+
# we currently don't support searching across federation, so we have
489516
# to do it manually without pagination
490517
limit = None
491518
since_token = None

0 commit comments

Comments
 (0)