diff --git a/synapse/handlers/directory.py b/synapse/handlers/directory.py
index 4efecb1ffd..e0a778e7ff 100644
--- a/synapse/handlers/directory.py
+++ b/synapse/handlers/directory.py
@@ -216,7 +216,7 @@ class DirectoryHandler(BaseHandler):
aliases = yield self.store.get_aliases_for_room(room_id)
msg_handler = self.hs.get_handlers().message_handler
- yield msg_handler.create_and_send_event({
+ yield msg_handler.create_and_send_nonmember_event({
"type": EventTypes.Aliases,
"state_key": self.hs.hostname,
"room_id": room_id,
diff --git a/synapse/handlers/federation.py b/synapse/handlers/federation.py
index da55d43541..ac15f9e5dd 100644
--- a/synapse/handlers/federation.py
+++ b/synapse/handlers/federation.py
@@ -1658,7 +1658,7 @@ class FederationHandler(BaseHandler):
self.auth.check(event, context.current_state)
yield self._validate_keyserver(event, auth_events=context.current_state)
member_handler = self.hs.get_handlers().room_member_handler
- yield member_handler.send_membership_event(event, context)
+ yield member_handler.send_membership_event(event, context, from_client=False)
else:
destinations = set([x.split(":", 1)[-1] for x in (sender, room_id)])
yield self.replication_layer.forward_third_party_invite(
@@ -1687,7 +1687,7 @@ class FederationHandler(BaseHandler):
# TODO: Make sure the signatures actually are correct.
event.signatures.update(returned_invite.signatures)
member_handler = self.hs.get_handlers().room_member_handler
- yield member_handler.send_membership_event(event, context)
+ yield member_handler.send_membership_event(event, context, from_client=False)
@defer.inlineCallbacks
def add_display_name_to_third_party_invite(self, event_dict, event, context):
diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py
index a94fad1735..05dab172b8 100644
--- a/synapse/handlers/message.py
+++ b/synapse/handlers/message.py
@@ -16,7 +16,7 @@
from twisted.internet import defer
from synapse.api.constants import EventTypes, Membership
-from synapse.api.errors import AuthError, Codes
+from synapse.api.errors import AuthError, Codes, SynapseError
from synapse.streams.config import PaginationConfig
from synapse.events.utils import serialize_event
from synapse.events.validator import EventValidator
@@ -216,7 +216,7 @@ class MessageHandler(BaseHandler):
defer.returnValue((event, context))
@defer.inlineCallbacks
- def send_event(self, event, context, ratelimit=True, is_guest=False, room_hosts=None):
+ def send_nonmember_event(self, event, context, ratelimit=True):
"""
Persists and notifies local clients and federation of an event.
@@ -226,61 +226,63 @@ class MessageHandler(BaseHandler):
ratelimit (bool): Whether to rate limit this send.
is_guest (bool): Whether the sender is a guest.
"""
+ if event.type == EventTypes.Member:
+ raise SynapseError(
+ 500,
+ "Tried to send member even through non-member codepath"
+ )
+
user = UserID.from_string(event.sender)
assert self.hs.is_mine(user), "User must be our own: %s" % (user,)
if event.is_state():
- prev_state = context.current_state.get((event.type, event.state_key))
- if prev_state and event.user_id == prev_state.user_id:
- prev_content = encode_canonical_json(prev_state.content)
- next_content = encode_canonical_json(event.content)
- if prev_content == next_content:
- # Duplicate suppression for state updates with same sender
- # and content.
- defer.returnValue(prev_state)
+ prev_state = self.deduplicate_state_event(event, context)
+ if prev_state is not None:
+ defer.returnValue(prev_state)
- if event.type == EventTypes.Member:
- member_handler = self.hs.get_handlers().room_member_handler
- yield member_handler.send_membership_event(
- event,
- context,
- is_guest=is_guest,
- ratelimit=ratelimit,
- room_hosts=room_hosts
- )
- else:
- yield self.handle_new_client_event(
- event=event,
- context=context,
- ratelimit=ratelimit,
- )
+ yield self.handle_new_client_event(
+ event=event,
+ context=context,
+ ratelimit=ratelimit,
+ )
if event.type == EventTypes.Message:
presence = self.hs.get_handlers().presence_handler
with PreserveLoggingContext():
presence.bump_presence_active_time(user)
+ def deduplicate_state_event(self, event, context):
+ prev_state = context.current_state.get((event.type, event.state_key))
+ if prev_state and event.user_id == prev_state.user_id:
+ prev_content = encode_canonical_json(prev_state.content)
+ next_content = encode_canonical_json(event.content)
+ if prev_content == next_content:
+ return prev_state
+ return None
+
@defer.inlineCallbacks
- def create_and_send_event(self, event_dict, ratelimit=True,
- token_id=None, txn_id=None, is_guest=False,
- room_hosts=None):
+ def create_and_send_nonmember_event(
+ self,
+ event_dict,
+ ratelimit=True,
+ token_id=None,
+ txn_id=None
+ ):
"""
Creates an event, then sends it.
- See self.create_event and self.send_event.
+ See self.create_event and self.send_nonmember_event.
"""
event, context = yield self.create_event(
event_dict,
token_id=token_id,
txn_id=txn_id
)
- yield self.send_event(
+ yield self.send_nonmember_event(
event,
context,
ratelimit=ratelimit,
- is_guest=is_guest,
- room_hosts=room_hosts,
)
defer.returnValue(event)
diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py
index bdaa05e0b6..5d4e87b3b0 100644
--- a/synapse/handlers/room.py
+++ b/synapse/handlers/room.py
@@ -179,13 +179,24 @@ class RoomCreationHandler(BaseHandler):
)
msg_handler = self.hs.get_handlers().message_handler
+ room_member_handler = self.hs.get_handlers().room_member_handler
for event in creation_events:
- yield msg_handler.create_and_send_event(event, ratelimit=False)
+ if event["type"] == EventTypes.Member:
+ # TODO(danielwh): This is hideous
+ yield room_member_handler.update_membership(
+ requester,
+ user,
+ room_id,
+ "join",
+ ratelimit=False,
+ )
+ else:
+ yield msg_handler.create_and_send_nonmember_event(event, ratelimit=False)
if "name" in config:
name = config["name"]
- yield msg_handler.create_and_send_event({
+ yield msg_handler.create_and_send_nonmember_event({
"type": EventTypes.Name,
"room_id": room_id,
"sender": user_id,
@@ -195,7 +206,7 @@ class RoomCreationHandler(BaseHandler):
if "topic" in config:
topic = config["topic"]
- yield msg_handler.create_and_send_event({
+ yield msg_handler.create_and_send_nonmember_event({
"type": EventTypes.Topic,
"room_id": room_id,
"sender": user_id,
@@ -204,13 +215,13 @@ class RoomCreationHandler(BaseHandler):
}, ratelimit=False)
for invitee in invite_list:
- yield msg_handler.create_and_send_event({
- "type": EventTypes.Member,
- "state_key": invitee,
- "room_id": room_id,
- "sender": user_id,
- "content": {"membership": Membership.INVITE},
- }, ratelimit=False)
+ room_member_handler.update_membership(
+ requester,
+ UserID.from_string(invitee),
+ room_id,
+ "invite",
+ ratelimit=False,
+ )
for invite_3pid in invite_3pid_list:
id_server = invite_3pid["id_server"]
@@ -222,7 +233,7 @@ class RoomCreationHandler(BaseHandler):
medium,
address,
id_server,
- token_id=None,
+ requester,
txn_id=None,
)
@@ -439,12 +450,14 @@ class RoomMemberHandler(BaseHandler):
errcode=Codes.BAD_STATE
)
- yield msg_handler.send_event(
+ member_handler = self.hs.get_handlers().room_member_handler
+ yield member_handler.send_membership_event(
event,
context,
- ratelimit=ratelimit,
is_guest=requester.is_guest,
+ ratelimit=ratelimit,
room_hosts=room_hosts,
+ from_client=True,
)
if action == "forget":
@@ -452,7 +465,7 @@ class RoomMemberHandler(BaseHandler):
@defer.inlineCallbacks
def send_membership_event(
- self, event, context, is_guest=False, room_hosts=None, ratelimit=True
+ self, event, context, is_guest=False, room_hosts=None, ratelimit=True, from_client=True,
):
""" Change the membership status of a user in a room.
@@ -461,6 +474,16 @@ class RoomMemberHandler(BaseHandler):
Raises:
SynapseError if there was a problem changing the membership.
"""
+ if from_client:
+ user = UserID.from_string(event.sender)
+
+ assert self.hs.is_mine(user), "User must be our own: %s" % (user,)
+
+ if event.is_state():
+ prev_state = self.hs.get_handlers().message_handler.deduplicate_state_event(event, context)
+ if prev_state is not None:
+ return
+
target_user_id = event.state_key
target_user = UserID.from_string(event.state_key)
@@ -549,13 +572,11 @@ class RoomMemberHandler(BaseHandler):
room_id,
event.user_id
)
- defer.returnValue({"room_id": room_id})
return
# FIXME: This isn't idempotency.
if prev_state and prev_state.membership == event.membership:
# double same action, treat this event as a NOOP.
- defer.returnValue({})
return
yield self.handle_new_client_event(
@@ -569,8 +590,6 @@ class RoomMemberHandler(BaseHandler):
user = UserID.from_string(event.user_id)
user_left_room(self.distributor, user, event.room_id)
- defer.returnValue({"room_id": room_id})
-
@defer.inlineCallbacks
def lookup_room_alias(self, room_alias):
"""
@@ -657,7 +676,7 @@ class RoomMemberHandler(BaseHandler):
medium,
address,
id_server,
- token_id,
+ requester,
txn_id
):
invitee = yield self._lookup_3pid(
@@ -665,19 +684,12 @@ class RoomMemberHandler(BaseHandler):
)
if invitee:
- # make sure it looks like a user ID; it'll throw if it's invalid.
- UserID.from_string(invitee)
- yield self.hs.get_handlers().message_handler.create_and_send_event(
- {
- "type": EventTypes.Member,
- "content": {
- "membership": unicode("invite")
- },
- "room_id": room_id,
- "sender": inviter.to_string(),
- "state_key": invitee,
- },
- token_id=token_id,
+ handler = self.hs.get_handlers().room_member_handler
+ yield handler.update_membership(
+ requester,
+ UserID.from_string(invitee),
+ room_id,
+ "invite",
txn_id=txn_id,
)
else:
@@ -687,7 +699,7 @@ class RoomMemberHandler(BaseHandler):
address,
room_id,
inviter,
- token_id,
+ requester.access_token_id,
txn_id=txn_id
)
@@ -798,7 +810,7 @@ class RoomMemberHandler(BaseHandler):
)
)
msg_handler = self.hs.get_handlers().message_handler
- yield msg_handler.create_and_send_event(
+ yield msg_handler.create_and_send_nonmember_event(
{
"type": EventTypes.ThirdPartyInvite,
"content": {
|