diff --git a/synapse/federation/federation_client.py b/synapse/federation/federation_client.py
index f5b430e046..723f571284 100644
--- a/synapse/federation/federation_client.py
+++ b/synapse/federation/federation_client.py
@@ -17,6 +17,7 @@
from twisted.internet import defer
from .federation_base import FederationBase
+from synapse.api.constants import Membership
from .units import Edu
from synapse.api.errors import (
@@ -357,7 +358,34 @@ class FederationClient(FederationBase):
defer.returnValue(signed_auth)
@defer.inlineCallbacks
- def make_join(self, destinations, room_id, user_id, content):
+ def make_membership_event(self, destinations, room_id, user_id, membership, content):
+ """
+ Creates an m.room.member event, with context, without participating in the room.
+
+ Does so by asking one of the already participating servers to create an
+ event with proper context.
+
+ Note that this does not append any events to any graphs.
+
+ Args:
+ destinations (str): Candidate homeservers which are probably
+ participating in the room.
+ room_id (str): The room in which the event will happen.
+ user_id (str): The user whose membership is being evented.
+ membership (str): The "membership" property of the event. Must be
+ one of "join" or "leave".
+ content (object): Any additional data to put into the content field
+ of the event.
+ Return:
+ A tuple of (origin (str), event (object)) where origin is the remote
+ homeserver which generated the event.
+ """
+ valid_memberships = {Membership.JOIN, Membership.LEAVE}
+ if membership not in valid_memberships:
+ raise RuntimeError(
+ "make_membership_event called with membership='%s', must be one of %s" %
+ (membership, ",".join(valid_memberships))
+ )
for destination in destinations:
if destination == self.server_name:
continue
@@ -368,13 +396,13 @@ class FederationClient(FederationBase):
content["third_party_invite"]
)
try:
- ret = yield self.transport_layer.make_join(
- destination, room_id, user_id, args
+ ret = yield self.transport_layer.make_membership_event(
+ destination, room_id, user_id, membership, args
)
pdu_dict = ret["event"]
- logger.debug("Got response to make_join: %s", pdu_dict)
+ logger.debug("Got response to make_%s: %s", membership, pdu_dict)
defer.returnValue(
(destination, self.event_from_pdu_json(pdu_dict))
@@ -384,8 +412,8 @@ class FederationClient(FederationBase):
raise
except Exception as e:
logger.warn(
- "Failed to make_join via %s: %s",
- destination, e.message
+ "Failed to make_%s via %s: %s",
+ membership, destination, e.message
)
raise RuntimeError("Failed to send to any server.")
@@ -492,6 +520,33 @@ class FederationClient(FederationBase):
defer.returnValue(pdu)
@defer.inlineCallbacks
+ def send_leave(self, destinations, pdu):
+ for destination in destinations:
+ if destination == self.server_name:
+ continue
+
+ try:
+ time_now = self._clock.time_msec()
+ _, content = yield self.transport_layer.send_leave(
+ destination=destination,
+ room_id=pdu.room_id,
+ event_id=pdu.event_id,
+ content=pdu.get_pdu_json(time_now),
+ )
+
+ logger.debug("Got content: %s", content)
+ defer.returnValue(None)
+ except CodeMessageException:
+ raise
+ except Exception as e:
+ logger.exception(
+ "Failed to send_leave via %s: %s",
+ destination, e.message
+ )
+
+ raise RuntimeError("Failed to send to any server.")
+
+ @defer.inlineCallbacks
def query_auth(self, destination, room_id, event_id, local_auth):
"""
Params:
diff --git a/synapse/federation/federation_server.py b/synapse/federation/federation_server.py
index 7934f740e0..9e2d9ee74c 100644
--- a/synapse/federation/federation_server.py
+++ b/synapse/federation/federation_server.py
@@ -268,6 +268,20 @@ class FederationServer(FederationBase):
}))
@defer.inlineCallbacks
+ def on_make_leave_request(self, room_id, user_id):
+ pdu = yield self.handler.on_make_leave_request(room_id, user_id)
+ time_now = self._clock.time_msec()
+ defer.returnValue({"event": pdu.get_pdu_json(time_now)})
+
+ @defer.inlineCallbacks
+ def on_send_leave_request(self, origin, content):
+ logger.debug("on_send_leave_request: content: %s", content)
+ pdu = self.event_from_pdu_json(content)
+ logger.debug("on_send_leave_request: pdu sigs: %s", pdu.signatures)
+ yield self.handler.on_send_leave_request(origin, pdu)
+ defer.returnValue((200, {}))
+
+ @defer.inlineCallbacks
def on_event_auth(self, origin, room_id, event_id):
time_now = self._clock.time_msec()
auth_pdus = yield self.handler.on_event_auth(event_id)
diff --git a/synapse/federation/transport/client.py b/synapse/federation/transport/client.py
index ae4195e83a..a81b3c4345 100644
--- a/synapse/federation/transport/client.py
+++ b/synapse/federation/transport/client.py
@@ -14,6 +14,7 @@
# limitations under the License.
from twisted.internet import defer
+from synapse.api.constants import Membership
from synapse.api.urls import FEDERATION_PREFIX as PREFIX
from synapse.util.logutils import log_function
@@ -160,8 +161,14 @@ class TransportLayerClient(object):
@defer.inlineCallbacks
@log_function
- def make_join(self, destination, room_id, user_id, args={}):
- path = PREFIX + "/make_join/%s/%s" % (room_id, user_id)
+ def make_membership_event(self, destination, room_id, user_id, membership, args={}):
+ valid_memberships = {Membership.JOIN, Membership.LEAVE}
+ if membership not in valid_memberships:
+ raise RuntimeError(
+ "make_membership_event called with membership='%s', must be one of %s" %
+ (membership, ",".join(valid_memberships))
+ )
+ path = PREFIX + "/make_%s/%s/%s" % (membership, room_id, user_id)
content = yield self.client.get_json(
destination=destination,
@@ -187,6 +194,19 @@ class TransportLayerClient(object):
@defer.inlineCallbacks
@log_function
+ def send_leave(self, destination, room_id, event_id, content):
+ path = PREFIX + "/send_leave/%s/%s" % (room_id, event_id)
+
+ response = yield self.client.put_json(
+ destination=destination,
+ path=path,
+ data=content,
+ )
+
+ defer.returnValue(response)
+
+ @defer.inlineCallbacks
+ @log_function
def send_invite(self, destination, room_id, event_id, content):
path = PREFIX + "/invite/%s/%s" % (room_id, event_id)
diff --git a/synapse/federation/transport/server.py b/synapse/federation/transport/server.py
index 6e394f039e..8184159210 100644
--- a/synapse/federation/transport/server.py
+++ b/synapse/federation/transport/server.py
@@ -296,6 +296,24 @@ class FederationMakeJoinServlet(BaseFederationServlet):
defer.returnValue((200, content))
+class FederationMakeLeaveServlet(BaseFederationServlet):
+ PATH = "/make_leave/([^/]*)/([^/]*)"
+
+ @defer.inlineCallbacks
+ def on_GET(self, origin, content, query, context, user_id):
+ content = yield self.handler.on_make_leave_request(context, user_id)
+ defer.returnValue((200, content))
+
+
+class FederationSendLeaveServlet(BaseFederationServlet):
+ PATH = "/send_leave/([^/]*)/([^/]*)"
+
+ @defer.inlineCallbacks
+ def on_PUT(self, origin, content, query, room_id, txid):
+ content = yield self.handler.on_send_leave_request(origin, content)
+ defer.returnValue((200, content))
+
+
class FederationEventAuthServlet(BaseFederationServlet):
PATH = "/event_auth/([^/]*)/([^/]*)"
@@ -385,8 +403,10 @@ SERVLET_CLASSES = (
FederationBackfillServlet,
FederationQueryServlet,
FederationMakeJoinServlet,
+ FederationMakeLeaveServlet,
FederationEventServlet,
FederationSendJoinServlet,
+ FederationSendLeaveServlet,
FederationInviteServlet,
FederationQueryAuthServlet,
FederationGetMissingEventsServlet,
|