From 89fc09c3d11b3574919a311dbf68816116873abb Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Wed, 7 Jan 2015 13:56:56 +0000 Subject: Bump version and changelog --- synapse/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'synapse') diff --git a/synapse/__init__.py b/synapse/__init__.py index 06167e3c1a..c3f1ac63be 100644 --- a/synapse/__init__.py +++ b/synapse/__init__.py @@ -16,4 +16,4 @@ """ This is a reference implementation of a synapse home server. """ -__version__ = "0.6.0" +__version__ = "0.6.1" -- cgit 1.5.1 From 9b8e348b15faba1469a93c7daa009e27ee377bc0 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 7 Jan 2015 15:08:22 +0000 Subject: *cough* --- synapse/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'synapse') diff --git a/synapse/__init__.py b/synapse/__init__.py index c3f1ac63be..9bfa09edfd 100644 --- a/synapse/__init__.py +++ b/synapse/__init__.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -""" This is a reference implementation of a synapse home server. +""" This is a reference implementation of a Matrix home server. """ __version__ = "0.6.1" -- cgit 1.5.1 From 9cb4f75d53d99634e79e791de22cb7de718248d6 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 7 Jan 2015 15:16:31 +0000 Subject: SYN-154: Better error messages when joining an unknown room by ID. The simple fix doesn't work here because room creation also involves unknown room IDs. The check relies on the presence of m.room.create for rooms being created, whereas bogus room IDs have no state events at all. --- synapse/api/auth.py | 11 ++++++++++- synapse/handlers/federation.py | 4 ++-- synapse/handlers/room.py | 8 +++++--- 3 files changed, 17 insertions(+), 6 deletions(-) (limited to 'synapse') diff --git a/synapse/api/auth.py b/synapse/api/auth.py index e31482cfaa..8a3455ec54 100644 --- a/synapse/api/auth.py +++ b/synapse/api/auth.py @@ -98,7 +98,16 @@ class Auth(object): defer.returnValue(member) @defer.inlineCallbacks - def check_host_in_room(self, room_id, host): + def check_host_in_room(self, room_id, host, context=None): + if context: + # XXX: check_host_in_room should really return True for a new + # room created by this home server. There are no m.room.member + # join events yet so we need to check for the m.room.create event + # instead. + if (u"m.room.create", u"") in context.auth_events: + defer.returnValue(True) + return + curr_state = yield self.state.get_current_state(room_id) for event in curr_state: diff --git a/synapse/handlers/federation.py b/synapse/handlers/federation.py index d26975a88a..d0de6fd04d 100644 --- a/synapse/handlers/federation.py +++ b/synapse/handlers/federation.py @@ -617,8 +617,8 @@ class FederationHandler(BaseHandler): @defer.inlineCallbacks @log_function - def on_backfill_request(self, origin, context, pdu_list, limit): - in_room = yield self.auth.check_host_in_room(context, origin) + def on_backfill_request(self, origin, room_id, pdu_list, limit): + in_room = yield self.auth.check_host_in_room(room_id, origin) if not in_room: raise AuthError(403, "Host not in room.") diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py index 59719a1fae..3cb7e324fc 100644 --- a/synapse/handlers/room.py +++ b/synapse/handlers/room.py @@ -423,12 +423,13 @@ class RoomMemberHandler(BaseHandler): is_host_in_room = yield self.auth.check_host_in_room( event.room_id, - self.hs.hostname + self.hs.hostname, + context=context ) if is_host_in_room: should_do_dance = False - elif room_host: + elif room_host: # TODO: Shouldn't this be remote_room_host? should_do_dance = True else: # TODO(markjh): get prev_state from snapshot @@ -442,7 +443,8 @@ class RoomMemberHandler(BaseHandler): should_do_dance = not self.hs.is_mine(inviter) room_host = inviter.domain else: - should_do_dance = False + # return the same error as join_room_alias does + raise SynapseError(404, "No known servers") if should_do_dance: handler = self.hs.get_handlers().federation_handler -- cgit 1.5.1 From 4c68460392ef032b156b8d006f4aec5496ceedcb Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 7 Jan 2015 16:09:00 +0000 Subject: SYN-154: Tweak how the m.room.create check is done. Don't perform the check in auth.is_host_in_room but instead do it in _do_join and also assert that there are no m.room.members in the room before doing so. --- synapse/api/auth.py | 11 +---------- synapse/handlers/room.py | 13 +++++++++++-- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'synapse') diff --git a/synapse/api/auth.py b/synapse/api/auth.py index 8a3455ec54..e31482cfaa 100644 --- a/synapse/api/auth.py +++ b/synapse/api/auth.py @@ -98,16 +98,7 @@ class Auth(object): defer.returnValue(member) @defer.inlineCallbacks - def check_host_in_room(self, room_id, host, context=None): - if context: - # XXX: check_host_in_room should really return True for a new - # room created by this home server. There are no m.room.member - # join events yet so we need to check for the m.room.create event - # instead. - if (u"m.room.create", u"") in context.auth_events: - defer.returnValue(True) - return - + def check_host_in_room(self, room_id, host): curr_state = yield self.state.get_current_state(room_id) for event in curr_state: diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py index 3cb7e324fc..16c6628292 100644 --- a/synapse/handlers/room.py +++ b/synapse/handlers/room.py @@ -423,9 +423,18 @@ class RoomMemberHandler(BaseHandler): is_host_in_room = yield self.auth.check_host_in_room( event.room_id, - self.hs.hostname, - context=context + self.hs.hostname ) + if not is_host_in_room: + # is *anyone* in the room? + room_member_keys = [ + v for (k,v) in context.current_state.keys() if k == "m.room.member" + ] + if len(room_member_keys) == 0: + # has the room been created so we can join it? + create_event = context.current_state.get(("m.room.create", "")) + if create_event: + is_host_in_room = True if is_host_in_room: should_do_dance = False -- cgit 1.5.1 From 333836ff9205a53934cf0c412b75916740e407b5 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 7 Jan 2015 16:18:12 +0000 Subject: PEP8 and pyflakes warnings --- synapse/handlers/federation.py | 2 +- synapse/handlers/room.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'synapse') diff --git a/synapse/handlers/federation.py b/synapse/handlers/federation.py index d0de6fd04d..195f7c618a 100644 --- a/synapse/handlers/federation.py +++ b/synapse/handlers/federation.py @@ -623,7 +623,7 @@ class FederationHandler(BaseHandler): raise AuthError(403, "Host not in room.") events = yield self.store.get_backfill_events( - context, + room_id, pdu_list, limit ) diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py index 16c6628292..6d0db18e51 100644 --- a/synapse/handlers/room.py +++ b/synapse/handlers/room.py @@ -428,7 +428,9 @@ class RoomMemberHandler(BaseHandler): if not is_host_in_room: # is *anyone* in the room? room_member_keys = [ - v for (k,v) in context.current_state.keys() if k == "m.room.member" + v for (k, v) in context.current_state.keys() if ( + k == "m.room.member" + ) ] if len(room_member_keys) == 0: # has the room been created so we can join it? -- cgit 1.5.1 From 76e1565200dda04e4091be761c737042f9a15e67 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 7 Jan 2015 17:11:19 +0000 Subject: Change error message for missing pillow libs. --- synapse/media/v1/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'synapse') diff --git a/synapse/media/v1/__init__.py b/synapse/media/v1/__init__.py index 619999d268..d6c6690577 100644 --- a/synapse/media/v1/__init__.py +++ b/synapse/media/v1/__init__.py @@ -22,7 +22,8 @@ except IOError as e: if str(e).startswith("decoder jpeg not available"): raise Exception( "FATAL: jpeg codec not supported. Install pillow correctly! " - " 'sudo apt-get install libjpeg-dev' then 'pip install -I pillow'" + " 'sudo apt-get install libjpeg-dev' then 'pip uninstall pillow &&" + " pip install pillow --user'" ) except Exception: # any other exception is fine @@ -36,7 +37,8 @@ except IOError as e: if str(e).startswith("decoder zip not available"): raise Exception( "FATAL: zip codec not supported. Install pillow correctly! " - " 'sudo apt-get install libjpeg-dev' then 'pip install -I pillow'" + " 'sudo apt-get install libjpeg-dev' then 'pip uninstall pillow &&" + " pip install pillow --user'" ) except Exception: # any other exception is fine -- cgit 1.5.1 From 42507b0011a1285645206f5bd627809a8a6337e2 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Wed, 7 Jan 2015 17:25:28 +0000 Subject: Log server version on startup --- synapse/app/homeserver.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'synapse') diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py index 5fec8da7ca..fba43aa2bf 100755 --- a/synapse/app/homeserver.py +++ b/synapse/app/homeserver.py @@ -39,6 +39,8 @@ from synapse.util.logcontext import LoggingContext from daemonize import Daemonize import twisted.manhole.telnet +import synapse + import logging import os import re @@ -199,6 +201,7 @@ def setup(): config.setup_logging() logger.info("Server hostname: %s", config.server_name) + logger.info("Server version: %s", synapse.__version__) if re.search(":[0-9]+$", config.server_name): domain_with_port = config.server_name -- cgit 1.5.1 From c9d2cecac9727ac3be8ad8cab21dc78b9dffe7a2 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Thu, 8 Jan 2015 09:41:11 +0000 Subject: SYN-231: User agent header broken --- synapse/http/client.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'synapse') diff --git a/synapse/http/client.py b/synapse/http/client.py index e5d4939e2d..7793bab106 100644 --- a/synapse/http/client.py +++ b/synapse/http/client.py @@ -53,7 +53,7 @@ class SimpleHttpClient(object): uri.encode("ascii"), headers=Headers({ b"Content-Type": [b"application/x-www-form-urlencoded"], - b"User-Agent": AGENT_NAME, + b"User-Agent": [AGENT_NAME], }), bodyProducer=FileBodyProducer(StringIO(query_bytes)) ) @@ -89,7 +89,7 @@ class SimpleHttpClient(object): "GET", uri.encode("ascii"), headers=Headers({ - b"User-Agent": AGENT_NAME, + b"User-Agent": [AGENT_NAME], }) ) @@ -114,7 +114,7 @@ class CaptchaServerHttpClient(SimpleHttpClient): bodyProducer=FileBodyProducer(StringIO(query_bytes)), headers=Headers({ b"Content-Type": [b"application/x-www-form-urlencoded"], - b"User-Agent": AGENT_NAME, + b"User-Agent": [AGENT_NAME], }) ) -- cgit 1.5.1 From 5a0e687d5cfbb01d817a2ea5a795d3fee7ca5083 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Thu, 8 Jan 2015 09:42:23 +0000 Subject: Bump version --- VERSION | 2 +- synapse/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'synapse') diff --git a/VERSION b/VERSION index ee6cdce3c2..8b9dea59dc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.6.1 +0.6.1a diff --git a/synapse/__init__.py b/synapse/__init__.py index c3f1ac63be..2195ad3177 100644 --- a/synapse/__init__.py +++ b/synapse/__init__.py @@ -16,4 +16,4 @@ """ This is a reference implementation of a synapse home server. """ -__version__ = "0.6.1" +__version__ = "0.6.1a" -- cgit 1.5.1 From 5720ab59e03d6f5ab48c3be22e8957a8891ea56c Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 8 Jan 2015 13:57:29 +0000 Subject: Add 'raw' query parameter to expose the event graph and signatures to savvy clients. --- synapse/events/utils.py | 17 +++++++++-------- synapse/handlers/events.py | 7 +++++-- synapse/handlers/message.py | 6 ++++-- synapse/rest/events.py | 5 ++++- synapse/rest/initial_sync.py | 5 ++++- synapse/server.py | 4 ++-- 6 files changed, 28 insertions(+), 16 deletions(-) (limited to 'synapse') diff --git a/synapse/events/utils.py b/synapse/events/utils.py index 4f4914467c..258dedb27c 100644 --- a/synapse/events/utils.py +++ b/synapse/events/utils.py @@ -89,7 +89,7 @@ def prune_event(event): return type(event)(allowed_fields) -def serialize_event(hs, e): +def serialize_event(hs, e, remove_data=True): # FIXME(erikj): To handle the case of presence events and the like if not isinstance(e, EventBase): return e @@ -122,12 +122,13 @@ def serialize_event(hs, e): d["prev_content"] = e.unsigned["prev_content"] del d["unsigned"]["prev_content"] - del d["auth_events"] - del d["prev_events"] - del d["hashes"] - del d["signatures"] - d.pop("depth", None) - d.pop("unsigned", None) - d.pop("origin", None) + if remove_data: + del d["auth_events"] + del d["prev_events"] + del d["hashes"] + del d["signatures"] + d.pop("depth", None) + d.pop("unsigned", None) + d.pop("origin", None) return d diff --git a/synapse/handlers/events.py b/synapse/handlers/events.py index 808219bd10..4e805606b8 100644 --- a/synapse/handlers/events.py +++ b/synapse/handlers/events.py @@ -46,7 +46,8 @@ class EventStreamHandler(BaseHandler): @defer.inlineCallbacks @log_function - def get_stream(self, auth_user_id, pagin_config, timeout=0): + def get_stream(self, auth_user_id, pagin_config, timeout=0, + trim_events=True): auth_user = self.hs.parse_userid(auth_user_id) try: @@ -78,7 +79,9 @@ class EventStreamHandler(BaseHandler): auth_user, room_ids, pagin_config, timeout ) - chunks = [self.hs.serialize_event(e) for e in events] + chunks = [ + self.hs.serialize_event(e, trim_events) for e in events + ] chunk = { "chunk": chunks, diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py index 7195de98b5..b2bbcfc6e2 100644 --- a/synapse/handlers/message.py +++ b/synapse/handlers/message.py @@ -211,7 +211,7 @@ class MessageHandler(BaseHandler): @defer.inlineCallbacks def snapshot_all_rooms(self, user_id=None, pagin_config=None, - feedback=False): + feedback=False, trim_events=True): """Retrieve a snapshot of all rooms the user is invited or has joined. This snapshot may include messages for all rooms where the user is @@ -280,7 +280,9 @@ class MessageHandler(BaseHandler): end_token = now_token.copy_and_replace("room_key", token[1]) d["messages"] = { - "chunk": [self.hs.serialize_event(m) for m in messages], + "chunk": [ + self.hs.serialize_event(m, trim_events) for m in messages + ], "start": start_token.to_string(), "end": end_token.to_string(), } diff --git a/synapse/rest/events.py b/synapse/rest/events.py index cf6d13f817..ac1a75a559 100644 --- a/synapse/rest/events.py +++ b/synapse/rest/events.py @@ -44,8 +44,11 @@ class EventStreamRestServlet(RestServlet): except ValueError: raise SynapseError(400, "timeout must be in milliseconds.") + trim_events = "raw" not in request.args + chunk = yield handler.get_stream( - auth_user.to_string(), pagin_config, timeout=timeout + auth_user.to_string(), pagin_config, timeout=timeout, + trim_events=trim_events ) except: logger.exception("Event stream failed") diff --git a/synapse/rest/initial_sync.py b/synapse/rest/initial_sync.py index a571589581..d2c0c63aa6 100644 --- a/synapse/rest/initial_sync.py +++ b/synapse/rest/initial_sync.py @@ -27,12 +27,15 @@ class InitialSyncRestServlet(RestServlet): def on_GET(self, request): user = yield self.auth.get_user_by_req(request) with_feedback = "feedback" in request.args + trim_events = "raw" not in request.args pagination_config = PaginationConfig.from_request(request) handler = self.handlers.message_handler content = yield handler.snapshot_all_rooms( user_id=user.to_string(), pagin_config=pagination_config, - feedback=with_feedback) + feedback=with_feedback, + trim_events=trim_events + ) defer.returnValue((200, content)) diff --git a/synapse/server.py b/synapse/server.py index c3bf46abbf..88161107af 100644 --- a/synapse/server.py +++ b/synapse/server.py @@ -149,8 +149,8 @@ class BaseHomeServer(object): object.""" return EventID.from_string(s) - def serialize_event(self, e): - return serialize_event(self, e) + def serialize_event(self, e, remove_data=True): + return serialize_event(self, e, remove_data) def get_ip_from_request(self, request): # May be an X-Forwarding-For header depending on config -- cgit 1.5.1 From 5940ec993bf75d5d05885544e811da88703f1800 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 8 Jan 2015 13:59:29 +0000 Subject: Add missing continuation indent. --- synapse/handlers/message.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'synapse') diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py index b2bbcfc6e2..9b20e4f50e 100644 --- a/synapse/handlers/message.py +++ b/synapse/handlers/message.py @@ -281,7 +281,8 @@ class MessageHandler(BaseHandler): d["messages"] = { "chunk": [ - self.hs.serialize_event(m, trim_events) for m in messages + self.hs.serialize_event(m, trim_events) + for m in messages ], "start": start_token.to_string(), "end": end_token.to_string(), -- cgit 1.5.1 From edb557b2ad98d3260caaba41ef2278b3eafc7e85 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 8 Jan 2015 14:27:04 +0000 Subject: Return the raw federation event rather than adding extra keys for federation data. --- synapse/events/utils.py | 25 ++++++++++++++++--------- synapse/handlers/events.py | 4 ++-- synapse/handlers/message.py | 5 +++-- synapse/rest/events.py | 4 ++-- synapse/rest/initial_sync.py | 4 ++-- synapse/server.py | 4 ++-- 6 files changed, 27 insertions(+), 19 deletions(-) (limited to 'synapse') diff --git a/synapse/events/utils.py b/synapse/events/utils.py index 258dedb27c..4687d96f26 100644 --- a/synapse/events/utils.py +++ b/synapse/events/utils.py @@ -89,13 +89,21 @@ def prune_event(event): return type(event)(allowed_fields) -def serialize_event(hs, e, remove_data=True): +def serialize_event(hs, e, client_event=True): # FIXME(erikj): To handle the case of presence events and the like if not isinstance(e, EventBase): return e # Should this strip out None's? d = {k: v for k, v in e.get_dict().items()} + + if not client_event: + # set the age and keep all other keys + if "age_ts" in d["unsigned"]: + now = int(hs.get_clock().time_msec()) + d["unsigned"]["age"] = now - d["unsigned"]["age_ts"] + return d + if "age_ts" in d["unsigned"]: now = int(hs.get_clock().time_msec()) d["unsigned"]["age"] = now - d["unsigned"]["age_ts"] @@ -122,13 +130,12 @@ def serialize_event(hs, e, remove_data=True): d["prev_content"] = e.unsigned["prev_content"] del d["unsigned"]["prev_content"] - if remove_data: - del d["auth_events"] - del d["prev_events"] - del d["hashes"] - del d["signatures"] - d.pop("depth", None) - d.pop("unsigned", None) - d.pop("origin", None) + del d["auth_events"] + del d["prev_events"] + del d["hashes"] + del d["signatures"] + d.pop("depth", None) + d.pop("unsigned", None) + d.pop("origin", None) return d diff --git a/synapse/handlers/events.py b/synapse/handlers/events.py index 4e805606b8..c9ade253dd 100644 --- a/synapse/handlers/events.py +++ b/synapse/handlers/events.py @@ -47,7 +47,7 @@ class EventStreamHandler(BaseHandler): @defer.inlineCallbacks @log_function def get_stream(self, auth_user_id, pagin_config, timeout=0, - trim_events=True): + as_client_event=True): auth_user = self.hs.parse_userid(auth_user_id) try: @@ -80,7 +80,7 @@ class EventStreamHandler(BaseHandler): ) chunks = [ - self.hs.serialize_event(e, trim_events) for e in events + self.hs.serialize_event(e, as_client_event) for e in events ] chunk = { diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py index 9b20e4f50e..30f5a08b59 100644 --- a/synapse/handlers/message.py +++ b/synapse/handlers/message.py @@ -211,7 +211,7 @@ class MessageHandler(BaseHandler): @defer.inlineCallbacks def snapshot_all_rooms(self, user_id=None, pagin_config=None, - feedback=False, trim_events=True): + feedback=False, as_client_event=True): """Retrieve a snapshot of all rooms the user is invited or has joined. This snapshot may include messages for all rooms where the user is @@ -222,6 +222,7 @@ class MessageHandler(BaseHandler): pagin_config (synapse.api.streams.PaginationConfig): The pagination config used to determine how many messages *PER ROOM* to return. feedback (bool): True to get feedback along with these messages. + as_client_event (bool): True to get events in client-server format. Returns: A list of dicts with "room_id" and "membership" keys for all rooms the user is currently invited or joined in on. Rooms where the user @@ -281,7 +282,7 @@ class MessageHandler(BaseHandler): d["messages"] = { "chunk": [ - self.hs.serialize_event(m, trim_events) + self.hs.serialize_event(m, as_client_event) for m in messages ], "start": start_token.to_string(), diff --git a/synapse/rest/events.py b/synapse/rest/events.py index ac1a75a559..bedcb2bcc6 100644 --- a/synapse/rest/events.py +++ b/synapse/rest/events.py @@ -44,11 +44,11 @@ class EventStreamRestServlet(RestServlet): except ValueError: raise SynapseError(400, "timeout must be in milliseconds.") - trim_events = "raw" not in request.args + as_client_event = "raw" not in request.args chunk = yield handler.get_stream( auth_user.to_string(), pagin_config, timeout=timeout, - trim_events=trim_events + as_client_event=as_client_event ) except: logger.exception("Event stream failed") diff --git a/synapse/rest/initial_sync.py b/synapse/rest/initial_sync.py index d2c0c63aa6..b13d56b286 100644 --- a/synapse/rest/initial_sync.py +++ b/synapse/rest/initial_sync.py @@ -27,14 +27,14 @@ class InitialSyncRestServlet(RestServlet): def on_GET(self, request): user = yield self.auth.get_user_by_req(request) with_feedback = "feedback" in request.args - trim_events = "raw" not in request.args + as_client_event = "raw" not in request.args pagination_config = PaginationConfig.from_request(request) handler = self.handlers.message_handler content = yield handler.snapshot_all_rooms( user_id=user.to_string(), pagin_config=pagination_config, feedback=with_feedback, - trim_events=trim_events + as_client_event=as_client_event ) defer.returnValue((200, content)) diff --git a/synapse/server.py b/synapse/server.py index 88161107af..d861efd2fd 100644 --- a/synapse/server.py +++ b/synapse/server.py @@ -149,8 +149,8 @@ class BaseHomeServer(object): object.""" return EventID.from_string(s) - def serialize_event(self, e, remove_data=True): - return serialize_event(self, e, remove_data) + def serialize_event(self, e, as_client_event=True): + return serialize_event(self, e, as_client_event) def get_ip_from_request(self, request): # May be an X-Forwarding-For header depending on config -- cgit 1.5.1 From 379a653ae3e46bc27b8ad4bde9bb7c25d0e048f9 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 8 Jan 2015 14:32:53 +0000 Subject: Add better help message for --server-name config option. --- synapse/config/server.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'synapse') diff --git a/synapse/config/server.py b/synapse/config/server.py index 4f73c85466..31e44cc857 100644 --- a/synapse/config/server.py +++ b/synapse/config/server.py @@ -47,8 +47,12 @@ class ServerConfig(Config): def add_arguments(cls, parser): super(ServerConfig, cls).add_arguments(parser) server_group = parser.add_argument_group("server") - server_group.add_argument("-H", "--server-name", default="localhost", - help="The name of the server") + server_group.add_argument( + "-H", "--server-name", default="localhost", + help="The domain name of the server, with optional explicit port. " + "This is used by remote servers to connect to this server, " + "e.g. matrix.org, localhost:8080, etc." + ) server_group.add_argument("--signing-key-path", help="The signing key to sign messages with") server_group.add_argument("-p", "--bind-port", metavar="PORT", -- cgit 1.5.1 From b5924cae04e549b3e19addc9257b462627f3d334 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 8 Jan 2015 14:36:33 +0000 Subject: Add raw query param for scrollback. --- synapse/handlers/message.py | 7 +++++-- synapse/rest/room.py | 5 ++++- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'synapse') diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py index 30f5a08b59..f2a2f16933 100644 --- a/synapse/handlers/message.py +++ b/synapse/handlers/message.py @@ -67,7 +67,7 @@ class MessageHandler(BaseHandler): @defer.inlineCallbacks def get_messages(self, user_id=None, room_id=None, pagin_config=None, - feedback=False): + feedback=False, as_client_event=True): """Get messages in a room. Args: @@ -76,6 +76,7 @@ class MessageHandler(BaseHandler): pagin_config (synapse.api.streams.PaginationConfig): The pagination config rules to apply, if any. feedback (bool): True to get compressed feedback with the messages + as_client_event (bool): True to get events in client-server format. Returns: dict: Pagination API results """ @@ -99,7 +100,9 @@ class MessageHandler(BaseHandler): ) chunk = { - "chunk": [self.hs.serialize_event(e) for e in events], + "chunk": [ + self.hs.serialize_event(e, as_client_event) for e in events + ], "start": pagin_config.from_token.to_string(), "end": next_token.to_string(), } diff --git a/synapse/rest/room.py b/synapse/rest/room.py index e40773758a..caafa959e6 100644 --- a/synapse/rest/room.py +++ b/synapse/rest/room.py @@ -314,12 +314,15 @@ class RoomMessageListRestServlet(RestServlet): request, default_limit=10, ) with_feedback = "feedback" in request.args + as_client_event = "raw" not in request.args handler = self.handlers.message_handler msgs = yield handler.get_messages( room_id=room_id, user_id=user.to_string(), pagin_config=pagination_config, - feedback=with_feedback) + feedback=with_feedback, + as_client_event=as_client_event + ) defer.returnValue((200, msgs)) -- cgit 1.5.1 From 7f83613733bc39a14b4eaff78313047d0fc50739 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 8 Jan 2015 15:11:22 +0000 Subject: make our JPEG thumbnail quality less horrifically ugly --- synapse/media/v1/thumbnailer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'synapse') diff --git a/synapse/media/v1/thumbnailer.py b/synapse/media/v1/thumbnailer.py index bc86efea8f..28404f2b7b 100644 --- a/synapse/media/v1/thumbnailer.py +++ b/synapse/media/v1/thumbnailer.py @@ -82,7 +82,7 @@ class Thumbnailer(object): def save_image(self, output_image, output_type, output_path): output_bytes_io = BytesIO() - output_image.save(output_bytes_io, self.FORMATS[output_type]) + output_image.save(output_bytes_io, self.FORMATS[output_type], quality=70) output_bytes = output_bytes_io.getvalue() with open(output_path, "wb") as output_file: output_file.write(output_bytes) -- cgit 1.5.1 From 9d0dcf2e3ca8b8c9cc8d87a451ed901f102dc2c6 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 8 Jan 2015 15:31:06 +0000 Subject: SYN-142: Rotate logs if logging to file. Fixed to a 4 file rotate with 100MB/file for now. --- synapse/config/logger.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'synapse') diff --git a/synapse/config/logger.py b/synapse/config/logger.py index 15383b3184..f9568ebd21 100644 --- a/synapse/config/logger.py +++ b/synapse/config/logger.py @@ -66,7 +66,10 @@ class LoggingConfig(Config): formatter = logging.Formatter(log_format) if self.log_file: - handler = logging.FileHandler(self.log_file) + # TODO: Customisable file size / backup count + handler = logging.handlers.RotatingFileHandler( + self.log_file, maxBytes=(1000 * 1000 * 100), backupCount=3 + ) else: handler = logging.StreamHandler() handler.setFormatter(formatter) -- cgit 1.5.1 From 63403aa7a57704cde86344b48390d16b1d74b035 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Thu, 8 Jan 2015 17:07:28 +0000 Subject: Check the existance and versions of necessary modules when starting synapse, log which modules are used --- synapse/app/homeserver.py | 5 +++ synapse/python_dependencies.py | 80 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 synapse/python_dependencies.py (limited to 'synapse') diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py index fba43aa2bf..43b5c26144 100755 --- a/synapse/app/homeserver.py +++ b/synapse/app/homeserver.py @@ -18,6 +18,8 @@ from synapse.storage import prepare_database, UpgradeDatabaseException from synapse.server import HomeServer +from synapse.python_dependencies import check_requirements + from twisted.internet import reactor from twisted.enterprise import adbapi from twisted.web.resource import Resource @@ -200,6 +202,8 @@ def setup(): config.setup_logging() + check_requirements() + logger.info("Server hostname: %s", config.server_name) logger.info("Server version: %s", synapse.__version__) @@ -280,6 +284,7 @@ def run(): def main(): with LoggingContext("main"): + check_requirements() setup() diff --git a/synapse/python_dependencies.py b/synapse/python_dependencies.py new file mode 100644 index 0000000000..b1fae991e0 --- /dev/null +++ b/synapse/python_dependencies.py @@ -0,0 +1,80 @@ +import logging +from distutils.version import LooseVersion + +logger = logging.getLogger(__name__) + +REQUIREMENTS = { + "syutil==0.0.2": ["syutil"], + "matrix_angular_sdk==0.6.0": ["syweb==0.6.0"], + "Twisted>=14.0.0": ["twisted>=14.0.0"], + "service_identity>=1.0.0": ["service_identity>=1.0.0"], + "pyopenssl>=0.14": ["OpenSSL>=0.14"], + "pyyaml": ["yaml"], + "pyasn1": ["pyasn1"], + "pynacl": ["nacl"], + "daemonize": ["daemonize"], + "py-bcrypt": ["bcrypt"], + "frozendict>=0.4": ["frozendict"], + "pillow": ["PIL"], +} + + +class MissingRequirementError(Exception): + pass + + +def check_requirements(): + """Checks that all the modules needed by synapse have been correctly + installed and are at the correct version""" + for dependency, module_requirements in REQUIREMENTS.items(): + for module_requirement in module_requirements: + if ">=" in module_requirement: + module_name, required_version = module_requirement.split(">=") + version_test = ">=" + elif "==" in module_requirement: + module_name, required_version = module_requirement.split("==") + version_test = "==" + else: + module_name = module_requirement + version_test = None + + try: + module = __import__(module_name) + except ImportError: + logging.exception( + "Can't import %r which is part of %r", + module_name, dependency + ) + raise MissingRequirementError( + "Can't import %r which is part of %r" + % (module_name, dependency) + ) + version = getattr(module, "__version__", None) + file_path = getattr(module, "__file__", None) + logger.info( + "Using %r version %r from %r to satisfy %r", + module_name, version, file_path, dependency + ) + + if version_test == ">=": + if version is None: + raise MissingRequirementError( + "Version of %r isn't set as __version__ of module %r" + % (dependency, module_name) + ) + if LooseVersion(version) < LooseVersion(required_version): + raise MissingRequirementError( + "Version of %r in %r is too old. %r < %r" + % (dependency, file_path, version, required_version) + ) + elif version_test == "==": + if version is None: + raise MissingRequirementError( + "Version of %r isn't set as __version__ of module %r" + % (dependency, module_name) + ) + if LooseVersion(version) != LooseVersion(required_version): + raise MissingRequirementError( + "Unexpected version of %r in %r. %r != %r" + % (dependency, file_path, version, required_version) + ) -- cgit 1.5.1 From c43d8981191ea993d78dea8be93fe513ad107c3e Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Mon, 12 Jan 2015 17:38:30 +0000 Subject: SYN-178: Fix off by one. --- synapse/storage/stream.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'synapse') diff --git a/synapse/storage/stream.py b/synapse/storage/stream.py index bedc3c6c52..744c821dfe 100644 --- a/synapse/storage/stream.py +++ b/synapse/storage/stream.py @@ -284,8 +284,12 @@ class StreamStore(SQLBaseStore): rows.reverse() # As we selected with reverse ordering if rows: - topo = rows[0]["topological_ordering"] - toke = rows[0]["stream_ordering"] + # XXX: Always subtract 1 since the start token always goes + # backwards (parity with paginate_room_events). It isn't + # obvious that this is correct; we should clarify the algorithm + # used here. + topo = rows[0]["topological_ordering"] - 1 + toke = rows[0]["stream_ordering"] - 1 start_token = "t%s-%s" % (topo, toke) token = (start_token, end_token) -- cgit 1.5.1 From 67d8305aea65d52abe4ce1c40bf78fdab3dc6471 Mon Sep 17 00:00:00 2001 From: "Paul \"LeoNerd\" Evans" Date: Mon, 12 Jan 2015 18:22:00 +0000 Subject: Make typing notification timeouts print a (debug) logging message --- synapse/handlers/typing.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'synapse') diff --git a/synapse/handlers/typing.py b/synapse/handlers/typing.py index ab698b36e1..15039ff0da 100644 --- a/synapse/handlers/typing.py +++ b/synapse/handlers/typing.py @@ -83,9 +83,15 @@ class TypingNotificationHandler(BaseHandler): if member in self._member_typing_timer: self.clock.cancel_call_later(self._member_typing_timer[member]) + def _cb(): + logger.debug( + "%s has timed out in %s", target_user.to_string(), room_id + ) + self._stopped_typing(member) + self._member_typing_until[member] = until self._member_typing_timer[member] = self.clock.call_later( - timeout / 1000, lambda: self._stopped_typing(member) + timeout / 1000, _cb ) if was_present: -- cgit 1.5.1 From 02ffbb20d00dbda213ba9321537ac12e347dcc35 Mon Sep 17 00:00:00 2001 From: "Paul \"LeoNerd\" Evans" Date: Mon, 12 Jan 2015 19:09:14 +0000 Subject: Use float rather than integer divisions to turn msec into sec - so timeouts under 1000msec will actually work --- synapse/handlers/typing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'synapse') diff --git a/synapse/handlers/typing.py b/synapse/handlers/typing.py index 15039ff0da..22ce7873d0 100644 --- a/synapse/handlers/typing.py +++ b/synapse/handlers/typing.py @@ -91,7 +91,7 @@ class TypingNotificationHandler(BaseHandler): self._member_typing_until[member] = until self._member_typing_timer[member] = self.clock.call_later( - timeout / 1000, _cb + timeout / 1000.0, _cb ) if was_present: -- cgit 1.5.1 From 39585bf5560e64bf6fca7d043cc3357b5dba59de Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Tue, 13 Jan 2015 09:57:32 +0000 Subject: Insert 'age' into top level when returning events to clients --- synapse/events/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'synapse') diff --git a/synapse/events/utils.py b/synapse/events/utils.py index 4f4914467c..4ad37188ba 100644 --- a/synapse/events/utils.py +++ b/synapse/events/utils.py @@ -98,7 +98,7 @@ def serialize_event(hs, e): d = {k: v for k, v in e.get_dict().items()} if "age_ts" in d["unsigned"]: now = int(hs.get_clock().time_msec()) - d["unsigned"]["age"] = now - d["unsigned"]["age_ts"] + d["age"] = now - d["unsigned"]["age_ts"] del d["unsigned"]["age_ts"] d["user_id"] = d.pop("sender", None) -- cgit 1.5.1 From 1d3d37937d680e460d1931dd36f36bf59c606561 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Tue, 13 Jan 2015 09:59:47 +0000 Subject: Bump version --- VERSION | 2 +- synapse/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'synapse') diff --git a/VERSION b/VERSION index 8b9dea59dc..3b3e723172 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.6.1a +0.6.1b diff --git a/synapse/__init__.py b/synapse/__init__.py index 2195ad3177..e7e27b06ec 100644 --- a/synapse/__init__.py +++ b/synapse/__init__.py @@ -16,4 +16,4 @@ """ This is a reference implementation of a synapse home server. """ -__version__ = "0.6.1a" +__version__ = "0.6.1b" -- cgit 1.5.1 From 895fcb377e3ebc43d67df1ac66413d92aacffca1 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Tue, 13 Jan 2015 14:14:21 +0000 Subject: Fix stream token ordering --- synapse/storage/stream.py | 173 +++++++++++++++++++++++++++------------------- 1 file changed, 101 insertions(+), 72 deletions(-) (limited to 'synapse') diff --git a/synapse/storage/stream.py b/synapse/storage/stream.py index 744c821dfe..563c8e3bbb 100644 --- a/synapse/storage/stream.py +++ b/synapse/storage/stream.py @@ -39,6 +39,8 @@ from ._base import SQLBaseStore from synapse.api.errors import SynapseError from synapse.util.logutils import log_function +from collections import namedtuple + import logging @@ -52,58 +54,76 @@ _STREAM_TOKEN = "stream" _TOPOLOGICAL_TOKEN = "topological" -def _parse_stream_token(string): - try: - if string[0] != 's': - raise - return int(string[1:]) - except: - raise SynapseError(400, "Invalid token") - - -def _parse_topological_token(string): - try: - if string[0] != 't': - raise - parts = string[1:].split('-', 1) - return (int(parts[0]), int(parts[1])) - except: - raise SynapseError(400, "Invalid token") - - -def is_stream_token(string): - try: - _parse_stream_token(string) - return True - except: - return False - - -def is_topological_token(string): - try: - _parse_topological_token(string) - return True - except: - return False - - -def _get_token_bound(token, comparison): - try: - s = _parse_stream_token(token) - return "%s %s %d" % ("stream_ordering", comparison, s) - except: - pass - - try: - top, stream = _parse_topological_token(token) - return "%s %s %d AND %s %s %d" % ( - "topological_ordering", comparison, top, - "stream_ordering", comparison, stream, - ) - except: - pass +class _StreamToken(namedtuple("_StreamToken", "topological stream")): + """Tokens are positions between events. The token "s1" comes after event 1. + + s0 s1 + | | + [0] V [1] V [2] + + Tokens can either be a point in the live event stream or a cursor going + through historic events. + + When traversing the live event stream events are ordered by when they + arrived at the homeserver. + + When traversing historic events the events are ordered by their depth in + the event graph "topological_ordering" and then by when they arrived at the + homeserver "stream_ordering". + + Live tokens start with an "s" followed by the "stream_ordering" id of the + event it comes after. Historic tokens start with a "t" followed by the + "topological_ordering" id of the event it comes after, follewed by "-", + followed by the "stream_ordering" id of the event it comes after. + """ + __slots__ = [] + + @classmethod + def parse(cls, string): + try: + if string[0] == 's': + return cls(None, int(string[1:])) + if string[0] == 't': + parts = string[1:].split('-', 1) + return cls(int(parts[1]), int(parts[0])) + except: + pass + raise SynapseError(400, "Invalid token %r" % (string,)) + + @classmethod + def parse_stream_token(cls, string): + try: + if string[0] == 's': + return cls(None, int(string[1:])) + except: + pass + raise SynapseError(400, "Invalid token %r" % (string,)) + + def __str__(self): + if self.topological is not None: + return "t%d-%d" % (self.topological, self.stream) + else: + return "s%d" % (self.stream,) + + def lower_bound(self): + if self.topological is None: + return "(%d < %s)" % (self.stream, "stream_ordering") + else: + return "(%d < %s OR (%d == %s AND %d < %s))" % ( + self.topological, "topological_ordering", + self.topological, "topological_ordering", + self.stream, "stream_ordering", + ) - raise SynapseError(400, "Invalid token") + def upper_bound(self): + if self.topological is None: + return "(%d >= %s)" % (self.stream, "stream_ordering") + else: + return "(%d > %s OR (%d == %s AND %d >= %s))" % ( + self.topological, "topological_ordering", + self.topological, "topological_ordering", + self.stream, "stream_ordering", + ) class StreamStore(SQLBaseStore): @@ -162,8 +182,8 @@ class StreamStore(SQLBaseStore): limit = MAX_STREAM_SIZE # From and to keys should be integers from ordering. - from_id = _parse_stream_token(from_key) - to_id = _parse_stream_token(to_key) + from_id = _StreamToken.parse_stream_token(from_key) + to_id = _StreamToken.parse_stream_token(to_key) if from_key == to_key: return defer.succeed(([], to_key)) @@ -181,7 +201,7 @@ class StreamStore(SQLBaseStore): } def f(txn): - txn.execute(sql, (user_id, user_id, from_id, to_id,)) + txn.execute(sql, (user_id, user_id, from_id.stream, to_id.stream,)) rows = self.cursor_to_dict(txn) @@ -211,17 +231,21 @@ class StreamStore(SQLBaseStore): # Tokens really represent positions between elements, but we use # the convention of pointing to the event before the gap. Hence # we have a bit of asymmetry when it comes to equalities. - from_comp = '<=' if direction == 'b' else '>' - to_comp = '>' if direction == 'b' else '<=' - order = "DESC" if direction == 'b' else "ASC" - args = [room_id] - - bounds = _get_token_bound(from_key, from_comp) - if to_key: - bounds = "%s AND %s" % ( - bounds, _get_token_bound(to_key, to_comp) - ) + if direction == 'b': + order = "DESC" + bounds = _StreamToken.parse(from_key).upper_bound() + if to_key: + bounds = "%s AND %s" % ( + bounds, _StreamToken.parse(to_key).lower_bound() + ) + else: + order = "ASC" + bounds = _StreamToken.parse(from_key).lower_bound() + if to_key: + bounds = "%s AND %s" % ( + bounds, _StreamToken.parse(to_key).upper_bound() + ) if int(limit) > 0: args.append(int(limit)) @@ -249,9 +273,13 @@ class StreamStore(SQLBaseStore): topo = rows[-1]["topological_ordering"] toke = rows[-1]["stream_ordering"] if direction == 'b': - topo -= 1 + # Tokens are positions between events. + # This token points *after* the last event in the chunk. + # We need it to point to the event before it in the chunk + # when we are going backwards so we subtract one from the + # stream part. toke -= 1 - next_token = "t%s-%s" % (topo, toke) + next_token = str(_StreamToken(topo, toke)) else: # TODO (erikj): We should work out what to do here instead. next_token = to_key if to_key else from_key @@ -284,13 +312,14 @@ class StreamStore(SQLBaseStore): rows.reverse() # As we selected with reverse ordering if rows: - # XXX: Always subtract 1 since the start token always goes - # backwards (parity with paginate_room_events). It isn't - # obvious that this is correct; we should clarify the algorithm - # used here. - topo = rows[0]["topological_ordering"] - 1 + # Tokens are positions between events. + # This token points *after* the last event in the chunk. + # We need it to point to the event before it in the chunk + # since we are going backwards so we subtract one from the + # stream part. + topo = rows[0]["topological_ordering"] toke = rows[0]["stream_ordering"] - 1 - start_token = "t%s-%s" % (topo, toke) + start_token = str(_StreamToken(topo, toke)) token = (start_token, end_token) else: -- cgit 1.5.1 From fda63064fc21881c8aabbfef36916b3b00af5299 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Tue, 13 Jan 2015 14:43:26 +0000 Subject: get_room_events isn't called anywhere --- synapse/storage/stream.py | 30 ------------------------------ 1 file changed, 30 deletions(-) (limited to 'synapse') diff --git a/synapse/storage/stream.py b/synapse/storage/stream.py index 563c8e3bbb..8ac2adab05 100644 --- a/synapse/storage/stream.py +++ b/synapse/storage/stream.py @@ -127,36 +127,6 @@ class _StreamToken(namedtuple("_StreamToken", "topological stream")): class StreamStore(SQLBaseStore): - @log_function - def get_room_events(self, user_id, from_key, to_key, room_id, limit=0, - direction='f', with_feedback=False): - # We deal with events request in two different ways depending on if - # this looks like an /events request or a pagination request. - is_events = ( - direction == 'f' - and user_id - and is_stream_token(from_key) - and to_key and is_stream_token(to_key) - ) - - if is_events: - return self.get_room_events_stream( - user_id=user_id, - from_key=from_key, - to_key=to_key, - room_id=room_id, - limit=limit, - with_feedback=with_feedback, - ) - else: - return self.paginate_room_events( - from_key=from_key, - to_key=to_key, - room_id=room_id, - limit=limit, - with_feedback=with_feedback, - ) - @log_function def get_room_events_stream(self, user_id, from_key, to_key, room_id, limit=0, with_feedback=False): -- cgit 1.5.1 From 3891597eb3666bbcbe325e38798b9d78b5d70bcc Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Tue, 13 Jan 2015 15:57:26 +0000 Subject: Remove unused functions --- synapse/events/builder.py | 6 ------ synapse/storage/room.py | 7 ------- synapse/storage/state.py | 6 ------ tests/storage/test_room.py | 11 ----------- 4 files changed, 30 deletions(-) (limited to 'synapse') diff --git a/synapse/events/builder.py b/synapse/events/builder.py index d4cb602ebb..a9b1b99a10 100644 --- a/synapse/events/builder.py +++ b/synapse/events/builder.py @@ -33,12 +33,6 @@ class EventBuilder(EventBase): unsigned=unsigned ) - def update_event_key(self, key, value): - self._event_dict[key] = value - - def update_event_keys(self, other_dict): - self._event_dict.update(other_dict) - def build(self): return FrozenEvent.from_event(self) diff --git a/synapse/storage/room.py b/synapse/storage/room.py index 978b2c4a48..6542f8e4f8 100644 --- a/synapse/storage/room.py +++ b/synapse/storage/room.py @@ -58,13 +58,6 @@ class RoomStore(SQLBaseStore): logger.error("store_room with room_id=%s failed: %s", room_id, e) raise StoreError(500, "Problem creating room.") - def store_room_config(self, room_id, visibility): - return self._simple_update_one( - table=RoomsTable.table_name, - keyvalues={"room_id": room_id}, - updatevalues={"is_public": visibility} - ) - def get_room(self, room_id): """Retrieve a room. diff --git a/synapse/storage/state.py b/synapse/storage/state.py index 5327517704..71db16d0e5 100644 --- a/synapse/storage/state.py +++ b/synapse/storage/state.py @@ -78,12 +78,6 @@ class StateStore(SQLBaseStore): f, ) - def store_state_groups(self, event): - return self.runInteraction( - "store_state_groups", - self._store_state_groups_txn, event - ) - def _store_state_groups_txn(self, txn, event, context): if context.current_state is None: return diff --git a/tests/storage/test_room.py b/tests/storage/test_room.py index 11761fe29a..e7739776ec 100644 --- a/tests/storage/test_room.py +++ b/tests/storage/test_room.py @@ -56,17 +56,6 @@ class RoomStoreTestCase(unittest.TestCase): (yield self.store.get_room(self.room.to_string())) ) - @defer.inlineCallbacks - def test_store_room_config(self): - yield self.store.store_room_config(self.room.to_string(), - visibility=False - ) - - self.assertObjectHasAttributes( - {"is_public": False}, - (yield self.store.get_room(self.room.to_string())) - ) - @defer.inlineCallbacks def test_get_rooms(self): # get_rooms does an INNER JOIN on the room_aliases table :( -- cgit 1.5.1 From c2e7c84e5887de9b622a7cd2cc861f5eef3866c1 Mon Sep 17 00:00:00 2001 From: "Paul \"LeoNerd\" Evans" Date: Tue, 13 Jan 2015 16:57:28 +0000 Subject: Don't try to cancel already-expired timers - SYN-230 --- synapse/handlers/typing.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'synapse') diff --git a/synapse/handlers/typing.py b/synapse/handlers/typing.py index 22ce7873d0..cd9638dd04 100644 --- a/synapse/handlers/typing.py +++ b/synapse/handlers/typing.py @@ -120,6 +120,10 @@ class TypingNotificationHandler(BaseHandler): member = RoomMember(room_id=room_id, user=target_user) + if member in self._member_typing_timer: + self.clock.cancel_call_later(self._member_typing_timer[member]) + del self._member_typing_timer[member] + yield self._stopped_typing(member) @defer.inlineCallbacks @@ -142,8 +146,10 @@ class TypingNotificationHandler(BaseHandler): del self._member_typing_until[member] - self.clock.cancel_call_later(self._member_typing_timer[member]) - del self._member_typing_timer[member] + if member in self._member_typing_timer: + # Don't cancel it - either it already expired, or the real + # stopped_typing() will cancel it + del self._member_typing_timer[member] @defer.inlineCallbacks def _push_update(self, room_id, user, typing): -- cgit 1.5.1 From 34a5fbe2b7162c545ab5ae9403147bdd925a58f9 Mon Sep 17 00:00:00 2001 From: "Paul \"LeoNerd\" Evans" Date: Tue, 13 Jan 2015 17:29:24 +0000 Subject: Have /join/:room_id return the room ID in response anyway, for consistency of clients (SYN-234) --- synapse/rest/room.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'synapse') diff --git a/synapse/rest/room.py b/synapse/rest/room.py index caafa959e6..48bba2a5f3 100644 --- a/synapse/rest/room.py +++ b/synapse/rest/room.py @@ -246,7 +246,7 @@ class JoinRoomAliasServlet(RestServlet): } ) - defer.returnValue((200, {})) + defer.returnValue((200, {"room_id": identifier.to_string()})) @defer.inlineCallbacks def on_PUT(self, request, room_identifier, txn_id): -- cgit 1.5.1 From 2bdee982695345e676cc1667c8011b88e0a4cf66 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Fri, 16 Jan 2015 19:00:40 +0000 Subject: Remove temporary debug logging that was accidentally committed --- synapse/handlers/events.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'synapse') diff --git a/synapse/handlers/events.py b/synapse/handlers/events.py index c9ade253dd..103bc67c42 100644 --- a/synapse/handlers/events.py +++ b/synapse/handlers/events.py @@ -70,10 +70,8 @@ class EventStreamHandler(BaseHandler): pagin_config.from_token = None rm_handler = self.hs.get_handlers().room_member_handler - logger.debug("BETA") room_ids = yield rm_handler.get_rooms_for_user(auth_user) - logger.debug("ALPHA") with PreserveLoggingContext(): events, tokens = yield self.notifier.get_events_for( auth_user, room_ids, pagin_config, timeout -- cgit 1.5.1 From 602684eac5b7acf61e10d7fabed4977635d3fb46 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Fri, 16 Jan 2015 13:21:14 +0000 Subject: Split transport layer into client and server parts --- synapse/federation/transport.py | 598 ------------------------------- synapse/federation/transport/__init__.py | 62 ++++ synapse/federation/transport/client.py | 257 +++++++++++++ synapse/federation/transport/server.py | 328 +++++++++++++++++ 4 files changed, 647 insertions(+), 598 deletions(-) delete mode 100644 synapse/federation/transport.py create mode 100644 synapse/federation/transport/__init__.py create mode 100644 synapse/federation/transport/client.py create mode 100644 synapse/federation/transport/server.py (limited to 'synapse') diff --git a/synapse/federation/transport.py b/synapse/federation/transport.py deleted file mode 100644 index 1f0f06e0fe..0000000000 --- a/synapse/federation/transport.py +++ /dev/null @@ -1,598 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright 2014, 2015 OpenMarket Ltd -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""The transport layer is responsible for both sending transactions to remote -home servers and receiving a variety of requests from other home servers. - -Typically, this is done over HTTP (and all home servers are required to -support HTTP), however individual pairings of servers may decide to communicate -over a different (albeit still reliable) protocol. -""" - -from twisted.internet import defer - -from synapse.api.urls import FEDERATION_PREFIX as PREFIX -from synapse.api.errors import Codes, SynapseError -from synapse.util.logutils import log_function - -import logging -import json -import re - - -logger = logging.getLogger(__name__) - - -class TransportLayer(object): - """This is a basic implementation of the transport layer that translates - transactions and other requests to/from HTTP. - - Attributes: - server_name (str): Local home server host - - server (synapse.http.server.HttpServer): the http server to - register listeners on - - client (synapse.http.client.HttpClient): the http client used to - send requests - - request_handler (TransportRequestHandler): The handler to fire when we - receive requests for data. - - received_handler (TransportReceivedHandler): The handler to fire when - we receive data. - """ - - def __init__(self, homeserver, server_name, server, client): - """ - Args: - server_name (str): Local home server host - server (synapse.protocol.http.HttpServer): the http server to - register listeners on - client (synapse.protocol.http.HttpClient): the http client used to - send requests - """ - self.keyring = homeserver.get_keyring() - self.server_name = server_name - self.server = server - self.client = client - self.request_handler = None - self.received_handler = None - - @log_function - def get_context_state(self, destination, context, event_id=None): - """ Requests all state for a given context (i.e. room) from the - given server. - - Args: - destination (str): The host name of the remote home server we want - to get the state from. - context (str): The name of the context we want the state of - - Returns: - Deferred: Results in a dict received from the remote homeserver. - """ - logger.debug("get_context_state dest=%s, context=%s", - destination, context) - - subpath = "/state/%s/" % context - - args = {} - if event_id: - args["event_id"] = event_id - - return self._do_request_for_transaction( - destination, subpath, args=args - ) - - @log_function - def get_event(self, destination, event_id): - """ Requests the pdu with give id and origin from the given server. - - Args: - destination (str): The host name of the remote home server we want - to get the state from. - event_id (str): The id of the event being requested. - - Returns: - Deferred: Results in a dict received from the remote homeserver. - """ - logger.debug("get_pdu dest=%s, event_id=%s", - destination, event_id) - - subpath = "/event/%s/" % (event_id, ) - - return self._do_request_for_transaction(destination, subpath) - - @log_function - def backfill(self, dest, context, event_tuples, limit): - """ Requests `limit` previous PDUs in a given context before list of - PDUs. - - Args: - dest (str) - context (str) - event_tuples (list) - limt (int) - - Returns: - Deferred: Results in a dict received from the remote homeserver. - """ - logger.debug( - "backfill dest=%s, context=%s, event_tuples=%s, limit=%s", - dest, context, repr(event_tuples), str(limit) - ) - - if not event_tuples: - # TODO: raise? - return - - subpath = "/backfill/%s/" % (context,) - - args = { - "v": event_tuples, - "limit": [str(limit)], - } - - return self._do_request_for_transaction( - dest, - subpath, - args=args, - ) - - @defer.inlineCallbacks - @log_function - def send_transaction(self, transaction, json_data_callback=None): - """ Sends the given Transaction to its destination - - Args: - transaction (Transaction) - - Returns: - Deferred: Results of the deferred is a tuple in the form of - (response_code, response_body) where the response_body is a - python dict decoded from json - """ - logger.debug( - "send_data dest=%s, txid=%s", - transaction.destination, transaction.transaction_id - ) - - if transaction.destination == self.server_name: - raise RuntimeError("Transport layer cannot send to itself!") - - # FIXME: This is only used by the tests. The actual json sent is - # generated by the json_data_callback. - json_data = transaction.get_dict() - - code, response = yield self.client.put_json( - transaction.destination, - path=PREFIX + "/send/%s/" % transaction.transaction_id, - data=json_data, - json_data_callback=json_data_callback, - ) - - logger.debug( - "send_data dest=%s, txid=%s, got response: %d", - transaction.destination, transaction.transaction_id, code - ) - - defer.returnValue((code, response)) - - @defer.inlineCallbacks - @log_function - def make_query(self, destination, query_type, args, retry_on_dns_fail): - path = PREFIX + "/query/%s" % query_type - - response = yield self.client.get_json( - destination=destination, - path=path, - args=args, - retry_on_dns_fail=retry_on_dns_fail, - ) - - defer.returnValue(response) - - @defer.inlineCallbacks - @log_function - def make_join(self, destination, context, user_id, retry_on_dns_fail=True): - path = PREFIX + "/make_join/%s/%s" % (context, user_id,) - - response = yield self.client.get_json( - destination=destination, - path=path, - retry_on_dns_fail=retry_on_dns_fail, - ) - - defer.returnValue(response) - - @defer.inlineCallbacks - @log_function - def send_join(self, destination, context, event_id, content): - path = PREFIX + "/send_join/%s/%s" % ( - context, - event_id, - ) - - code, content = yield self.client.put_json( - destination=destination, - path=path, - data=content, - ) - - if not 200 <= code < 300: - raise RuntimeError("Got %d from send_join", code) - - defer.returnValue(json.loads(content)) - - @defer.inlineCallbacks - @log_function - def send_invite(self, destination, context, event_id, content): - path = PREFIX + "/invite/%s/%s" % ( - context, - event_id, - ) - - code, content = yield self.client.put_json( - destination=destination, - path=path, - data=content, - ) - - if not 200 <= code < 300: - raise RuntimeError("Got %d from send_invite", code) - - defer.returnValue(json.loads(content)) - - @defer.inlineCallbacks - @log_function - def get_event_auth(self, destination, context, event_id): - path = PREFIX + "/event_auth/%s/%s" % ( - context, - event_id, - ) - - response = yield self.client.get_json( - destination=destination, - path=path, - ) - - defer.returnValue(response) - - @defer.inlineCallbacks - def _authenticate_request(self, request): - json_request = { - "method": request.method, - "uri": request.uri, - "destination": self.server_name, - "signatures": {}, - } - - content = None - origin = None - - if request.method == "PUT": - # TODO: Handle other method types? other content types? - try: - content_bytes = request.content.read() - content = json.loads(content_bytes) - json_request["content"] = content - except: - raise SynapseError(400, "Unable to parse JSON", Codes.BAD_JSON) - - def parse_auth_header(header_str): - try: - params = auth.split(" ")[1].split(",") - param_dict = dict(kv.split("=") for kv in params) - - def strip_quotes(value): - if value.startswith("\""): - return value[1:-1] - else: - return value - - origin = strip_quotes(param_dict["origin"]) - key = strip_quotes(param_dict["key"]) - sig = strip_quotes(param_dict["sig"]) - return (origin, key, sig) - except: - raise SynapseError( - 400, "Malformed Authorization header", Codes.UNAUTHORIZED - ) - - auth_headers = request.requestHeaders.getRawHeaders(b"Authorization") - - if not auth_headers: - raise SynapseError( - 401, "Missing Authorization headers", Codes.UNAUTHORIZED, - ) - - for auth in auth_headers: - if auth.startswith("X-Matrix"): - (origin, key, sig) = parse_auth_header(auth) - json_request["origin"] = origin - json_request["signatures"].setdefault(origin, {})[key] = sig - - if not json_request["signatures"]: - raise SynapseError( - 401, "Missing Authorization headers", Codes.UNAUTHORIZED, - ) - - yield self.keyring.verify_json_for_server(origin, json_request) - - defer.returnValue((origin, content)) - - def _with_authentication(self, handler): - @defer.inlineCallbacks - def new_handler(request, *args, **kwargs): - try: - (origin, content) = yield self._authenticate_request(request) - response = yield handler( - origin, content, request.args, *args, **kwargs - ) - except: - logger.exception("_authenticate_request failed") - raise - defer.returnValue(response) - return new_handler - - @log_function - def register_received_handler(self, handler): - """ Register a handler that will be fired when we receive data. - - Args: - handler (TransportReceivedHandler) - """ - self.received_handler = handler - - # This is when someone is trying to send us a bunch of data. - self.server.register_path( - "PUT", - re.compile("^" + PREFIX + "/send/([^/]*)/$"), - self._with_authentication(self._on_send_request) - ) - - @log_function - def register_request_handler(self, handler): - """ Register a handler that will be fired when we get asked for data. - - Args: - handler (TransportRequestHandler) - """ - self.request_handler = handler - - # TODO(markjh): Namespace the federation URI paths - - # This is for when someone asks us for everything since version X - self.server.register_path( - "GET", - re.compile("^" + PREFIX + "/pull/$"), - self._with_authentication( - lambda origin, content, query: - handler.on_pull_request(query["origin"][0], query["v"]) - ) - ) - - # This is when someone asks for a data item for a given server - # data_id pair. - self.server.register_path( - "GET", - re.compile("^" + PREFIX + "/event/([^/]*)/$"), - self._with_authentication( - lambda origin, content, query, event_id: - handler.on_pdu_request(origin, event_id) - ) - ) - - # This is when someone asks for all data for a given context. - self.server.register_path( - "GET", - re.compile("^" + PREFIX + "/state/([^/]*)/$"), - self._with_authentication( - lambda origin, content, query, context: - handler.on_context_state_request( - origin, - context, - query.get("event_id", [None])[0], - ) - ) - ) - - self.server.register_path( - "GET", - re.compile("^" + PREFIX + "/backfill/([^/]*)/$"), - self._with_authentication( - lambda origin, content, query, context: - self._on_backfill_request( - origin, context, query["v"], query["limit"] - ) - ) - ) - - # This is when we receive a server-server Query - self.server.register_path( - "GET", - re.compile("^" + PREFIX + "/query/([^/]*)$"), - self._with_authentication( - lambda origin, content, query, query_type: - handler.on_query_request( - query_type, - {k: v[0].decode("utf-8") for k, v in query.items()} - ) - ) - ) - - self.server.register_path( - "GET", - re.compile("^" + PREFIX + "/make_join/([^/]*)/([^/]*)$"), - self._with_authentication( - lambda origin, content, query, context, user_id: - self._on_make_join_request( - origin, content, query, context, user_id - ) - ) - ) - - self.server.register_path( - "GET", - re.compile("^" + PREFIX + "/event_auth/([^/]*)/([^/]*)$"), - self._with_authentication( - lambda origin, content, query, context, event_id: - handler.on_event_auth( - origin, context, event_id, - ) - ) - ) - - self.server.register_path( - "PUT", - re.compile("^" + PREFIX + "/send_join/([^/]*)/([^/]*)$"), - self._with_authentication( - lambda origin, content, query, context, event_id: - self._on_send_join_request( - origin, content, query, - ) - ) - ) - - self.server.register_path( - "PUT", - re.compile("^" + PREFIX + "/invite/([^/]*)/([^/]*)$"), - self._with_authentication( - lambda origin, content, query, context, event_id: - self._on_invite_request( - origin, content, query, - ) - ) - ) - - @defer.inlineCallbacks - @log_function - def _on_send_request(self, origin, content, query, transaction_id): - """ Called on PUT /send// - - Args: - request (twisted.web.http.Request): The HTTP request. - transaction_id (str): The transaction_id associated with this - request. This is *not* None. - - Returns: - Deferred: Results in a tuple of `(code, response)`, where - `response` is a python dict to be converted into JSON that is - used as the response body. - """ - # Parse the request - try: - transaction_data = content - - logger.debug( - "Decoded %s: %s", - transaction_id, str(transaction_data) - ) - - # We should ideally be getting this from the security layer. - # origin = body["origin"] - - # Add some extra data to the transaction dict that isn't included - # in the request body. - transaction_data.update( - transaction_id=transaction_id, - destination=self.server_name - ) - - except Exception as e: - logger.exception(e) - defer.returnValue((400, {"error": "Invalid transaction"})) - return - - try: - handler = self.received_handler - code, response = yield handler.on_incoming_transaction( - transaction_data - ) - except: - logger.exception("on_incoming_transaction failed") - raise - - defer.returnValue((code, response)) - - @defer.inlineCallbacks - @log_function - def _do_request_for_transaction(self, destination, subpath, args={}): - """ - Args: - destination (str) - path (str) - args (dict): This is parsed directly to the HttpClient. - - Returns: - Deferred: Results in a dict. - """ - - data = yield self.client.get_json( - destination, - path=PREFIX + subpath, - args=args, - ) - - # Add certain keys to the JSON, ready for decoding as a Transaction - data.update( - origin=destination, - destination=self.server_name, - transaction_id=None - ) - - defer.returnValue(data) - - @log_function - def _on_backfill_request(self, origin, context, v_list, limits): - if not limits: - return defer.succeed( - (400, {"error": "Did not include limit param"}) - ) - - limit = int(limits[-1]) - - versions = v_list - - return self.request_handler.on_backfill_request( - origin, context, versions, limit - ) - - @defer.inlineCallbacks - @log_function - def _on_make_join_request(self, origin, content, query, context, user_id): - content = yield self.request_handler.on_make_join_request( - context, user_id, - ) - defer.returnValue((200, content)) - - @defer.inlineCallbacks - @log_function - def _on_send_join_request(self, origin, content, query): - content = yield self.request_handler.on_send_join_request( - origin, content, - ) - - defer.returnValue((200, content)) - - @defer.inlineCallbacks - @log_function - def _on_invite_request(self, origin, content, query): - content = yield self.request_handler.on_invite_request( - origin, content, - ) - - defer.returnValue((200, content)) diff --git a/synapse/federation/transport/__init__.py b/synapse/federation/transport/__init__.py new file mode 100644 index 0000000000..6800ac46c5 --- /dev/null +++ b/synapse/federation/transport/__init__.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +# Copyright 2014, 2015 OpenMarket Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""The transport layer is responsible for both sending transactions to remote +home servers and receiving a variety of requests from other home servers. + +By default this is done over HTTPS (and all home servers are required to +support HTTPS), however individual pairings of servers may decide to +communicate over a different (albeit still reliable) protocol. +""" + +from .server import TransportLayerServer +from .client import TransportLayerClient + + +class TransportLayer(TransportLayerServer, TransportLayerClient): + """This is a basic implementation of the transport layer that translates + transactions and other requests to/from HTTP. + + Attributes: + server_name (str): Local home server host + + server (synapse.http.server.HttpServer): the http server to + register listeners on + + client (synapse.http.client.HttpClient): the http client used to + send requests + + request_handler (TransportRequestHandler): The handler to fire when we + receive requests for data. + + received_handler (TransportReceivedHandler): The handler to fire when + we receive data. + """ + + def __init__(self, homeserver, server_name, server, client): + """ + Args: + server_name (str): Local home server host + server (synapse.protocol.http.HttpServer): the http server to + register listeners on + client (synapse.protocol.http.HttpClient): the http client used to + send requests + """ + self.keyring = homeserver.get_keyring() + self.server_name = server_name + self.server = server + self.client = client + self.request_handler = None + self.received_handler = None diff --git a/synapse/federation/transport/client.py b/synapse/federation/transport/client.py new file mode 100644 index 0000000000..604ade683b --- /dev/null +++ b/synapse/federation/transport/client.py @@ -0,0 +1,257 @@ +# -*- coding: utf-8 -*- +# Copyright 2014, 2015 OpenMarket Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from twisted.internet import defer + +from synapse.api.urls import FEDERATION_PREFIX as PREFIX +from synapse.util.logutils import log_function + +import logging +import json + + +logger = logging.getLogger(__name__) + + +class TransportLayerClient(object): + """Sends federation HTTP requests to other servers""" + + @log_function + def get_context_state(self, destination, context, event_id=None): + """ Requests all state for a given context (i.e. room) from the + given server. + + Args: + destination (str): The host name of the remote home server we want + to get the state from. + context (str): The name of the context we want the state of + + Returns: + Deferred: Results in a dict received from the remote homeserver. + """ + logger.debug("get_context_state dest=%s, context=%s", + destination, context) + + subpath = "/state/%s/" % context + + args = {} + if event_id: + args["event_id"] = event_id + + return self._do_request_for_transaction( + destination, subpath, args=args + ) + + @log_function + def get_event(self, destination, event_id): + """ Requests the pdu with give id and origin from the given server. + + Args: + destination (str): The host name of the remote home server we want + to get the state from. + event_id (str): The id of the event being requested. + + Returns: + Deferred: Results in a dict received from the remote homeserver. + """ + logger.debug("get_pdu dest=%s, event_id=%s", + destination, event_id) + + subpath = "/event/%s/" % (event_id, ) + + return self._do_request_for_transaction(destination, subpath) + + @log_function + def backfill(self, dest, context, event_tuples, limit): + """ Requests `limit` previous PDUs in a given context before list of + PDUs. + + Args: + dest (str) + context (str) + event_tuples (list) + limt (int) + + Returns: + Deferred: Results in a dict received from the remote homeserver. + """ + logger.debug( + "backfill dest=%s, context=%s, event_tuples=%s, limit=%s", + dest, context, repr(event_tuples), str(limit) + ) + + if not event_tuples: + # TODO: raise? + return + + subpath = "/backfill/%s/" % (context,) + + args = { + "v": event_tuples, + "limit": [str(limit)], + } + + return self._do_request_for_transaction( + dest, + subpath, + args=args, + ) + + @defer.inlineCallbacks + @log_function + def send_transaction(self, transaction, json_data_callback=None): + """ Sends the given Transaction to its destination + + Args: + transaction (Transaction) + + Returns: + Deferred: Results of the deferred is a tuple in the form of + (response_code, response_body) where the response_body is a + python dict decoded from json + """ + logger.debug( + "send_data dest=%s, txid=%s", + transaction.destination, transaction.transaction_id + ) + + if transaction.destination == self.server_name: + raise RuntimeError("Transport layer cannot send to itself!") + + # FIXME: This is only used by the tests. The actual json sent is + # generated by the json_data_callback. + json_data = transaction.get_dict() + + code, response = yield self.client.put_json( + transaction.destination, + path=PREFIX + "/send/%s/" % transaction.transaction_id, + data=json_data, + json_data_callback=json_data_callback, + ) + + logger.debug( + "send_data dest=%s, txid=%s, got response: %d", + transaction.destination, transaction.transaction_id, code + ) + + defer.returnValue((code, response)) + + @defer.inlineCallbacks + @log_function + def make_query(self, destination, query_type, args, retry_on_dns_fail): + path = PREFIX + "/query/%s" % query_type + + response = yield self.client.get_json( + destination=destination, + path=path, + args=args, + retry_on_dns_fail=retry_on_dns_fail, + ) + + defer.returnValue(response) + + @defer.inlineCallbacks + @log_function + def make_join(self, destination, context, user_id, retry_on_dns_fail=True): + path = PREFIX + "/make_join/%s/%s" % (context, user_id,) + + response = yield self.client.get_json( + destination=destination, + path=path, + retry_on_dns_fail=retry_on_dns_fail, + ) + + defer.returnValue(response) + + @defer.inlineCallbacks + @log_function + def send_join(self, destination, context, event_id, content): + path = PREFIX + "/send_join/%s/%s" % ( + context, + event_id, + ) + + code, content = yield self.client.put_json( + destination=destination, + path=path, + data=content, + ) + + if not 200 <= code < 300: + raise RuntimeError("Got %d from send_join", code) + + defer.returnValue(json.loads(content)) + + @defer.inlineCallbacks + @log_function + def send_invite(self, destination, context, event_id, content): + path = PREFIX + "/invite/%s/%s" % ( + context, + event_id, + ) + + code, content = yield self.client.put_json( + destination=destination, + path=path, + data=content, + ) + + if not 200 <= code < 300: + raise RuntimeError("Got %d from send_invite", code) + + defer.returnValue(json.loads(content)) + + @defer.inlineCallbacks + @log_function + def get_event_auth(self, destination, context, event_id): + path = PREFIX + "/event_auth/%s/%s" % ( + context, + event_id, + ) + + response = yield self.client.get_json( + destination=destination, + path=path, + ) + + defer.returnValue(response) + + @defer.inlineCallbacks + @log_function + def _do_request_for_transaction(self, destination, subpath, args={}): + """ + Args: + destination (str) + path (str) + args (dict): This is parsed directly to the HttpClient. + + Returns: + Deferred: Results in a dict. + """ + + data = yield self.client.get_json( + destination, + path=PREFIX + subpath, + args=args, + ) + + # Add certain keys to the JSON, ready for decoding as a Transaction + data.update( + origin=destination, + destination=self.server_name, + transaction_id=None + ) + + defer.returnValue(data) diff --git a/synapse/federation/transport/server.py b/synapse/federation/transport/server.py new file mode 100644 index 0000000000..34b50def7d --- /dev/null +++ b/synapse/federation/transport/server.py @@ -0,0 +1,328 @@ +# -*- coding: utf-8 -*- +# Copyright 2014, 2015 OpenMarket Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from twisted.internet import defer + +from synapse.api.urls import FEDERATION_PREFIX as PREFIX +from synapse.api.errors import Codes, SynapseError +from synapse.util.logutils import log_function + +import logging +import json +import re + + +logger = logging.getLogger(__name__) + + +class TransportLayerServer(object): + """Handles incoming federation HTTP requests""" + + @defer.inlineCallbacks + def _authenticate_request(self, request): + json_request = { + "method": request.method, + "uri": request.uri, + "destination": self.server_name, + "signatures": {}, + } + + content = None + origin = None + + if request.method == "PUT": + # TODO: Handle other method types? other content types? + try: + content_bytes = request.content.read() + content = json.loads(content_bytes) + json_request["content"] = content + except: + raise SynapseError(400, "Unable to parse JSON", Codes.BAD_JSON) + + def parse_auth_header(header_str): + try: + params = auth.split(" ")[1].split(",") + param_dict = dict(kv.split("=") for kv in params) + + def strip_quotes(value): + if value.startswith("\""): + return value[1:-1] + else: + return value + + origin = strip_quotes(param_dict["origin"]) + key = strip_quotes(param_dict["key"]) + sig = strip_quotes(param_dict["sig"]) + return (origin, key, sig) + except: + raise SynapseError( + 400, "Malformed Authorization header", Codes.UNAUTHORIZED + ) + + auth_headers = request.requestHeaders.getRawHeaders(b"Authorization") + + if not auth_headers: + raise SynapseError( + 401, "Missing Authorization headers", Codes.UNAUTHORIZED, + ) + + for auth in auth_headers: + if auth.startswith("X-Matrix"): + (origin, key, sig) = parse_auth_header(auth) + json_request["origin"] = origin + json_request["signatures"].setdefault(origin, {})[key] = sig + + if not json_request["signatures"]: + raise SynapseError( + 401, "Missing Authorization headers", Codes.UNAUTHORIZED, + ) + + yield self.keyring.verify_json_for_server(origin, json_request) + + defer.returnValue((origin, content)) + + def _with_authentication(self, handler): + @defer.inlineCallbacks + def new_handler(request, *args, **kwargs): + try: + (origin, content) = yield self._authenticate_request(request) + response = yield handler( + origin, content, request.args, *args, **kwargs + ) + except: + logger.exception("_authenticate_request failed") + raise + defer.returnValue(response) + return new_handler + + @log_function + def register_received_handler(self, handler): + """ Register a handler that will be fired when we receive data. + + Args: + handler (TransportReceivedHandler) + """ + self.received_handler = handler + + # This is when someone is trying to send us a bunch of data. + self.server.register_path( + "PUT", + re.compile("^" + PREFIX + "/send/([^/]*)/$"), + self._with_authentication(self._on_send_request) + ) + + @log_function + def register_request_handler(self, handler): + """ Register a handler that will be fired when we get asked for data. + + Args: + handler (TransportRequestHandler) + """ + self.request_handler = handler + + # This is for when someone asks us for everything since version X + self.server.register_path( + "GET", + re.compile("^" + PREFIX + "/pull/$"), + self._with_authentication( + lambda origin, content, query: + handler.on_pull_request(query["origin"][0], query["v"]) + ) + ) + + # This is when someone asks for a data item for a given server + # data_id pair. + self.server.register_path( + "GET", + re.compile("^" + PREFIX + "/event/([^/]*)/$"), + self._with_authentication( + lambda origin, content, query, event_id: + handler.on_pdu_request(origin, event_id) + ) + ) + + # This is when someone asks for all data for a given context. + self.server.register_path( + "GET", + re.compile("^" + PREFIX + "/state/([^/]*)/$"), + self._with_authentication( + lambda origin, content, query, context: + handler.on_context_state_request( + origin, + context, + query.get("event_id", [None])[0], + ) + ) + ) + + self.server.register_path( + "GET", + re.compile("^" + PREFIX + "/backfill/([^/]*)/$"), + self._with_authentication( + lambda origin, content, query, context: + self._on_backfill_request( + origin, context, query["v"], query["limit"] + ) + ) + ) + + # This is when we receive a server-server Query + self.server.register_path( + "GET", + re.compile("^" + PREFIX + "/query/([^/]*)$"), + self._with_authentication( + lambda origin, content, query, query_type: + handler.on_query_request( + query_type, + {k: v[0].decode("utf-8") for k, v in query.items()} + ) + ) + ) + + self.server.register_path( + "GET", + re.compile("^" + PREFIX + "/make_join/([^/]*)/([^/]*)$"), + self._with_authentication( + lambda origin, content, query, context, user_id: + self._on_make_join_request( + origin, content, query, context, user_id + ) + ) + ) + + self.server.register_path( + "GET", + re.compile("^" + PREFIX + "/event_auth/([^/]*)/([^/]*)$"), + self._with_authentication( + lambda origin, content, query, context, event_id: + handler.on_event_auth( + origin, context, event_id, + ) + ) + ) + + self.server.register_path( + "PUT", + re.compile("^" + PREFIX + "/send_join/([^/]*)/([^/]*)$"), + self._with_authentication( + lambda origin, content, query, context, event_id: + self._on_send_join_request( + origin, content, query, + ) + ) + ) + + self.server.register_path( + "PUT", + re.compile("^" + PREFIX + "/invite/([^/]*)/([^/]*)$"), + self._with_authentication( + lambda origin, content, query, context, event_id: + self._on_invite_request( + origin, content, query, + ) + ) + ) + + @defer.inlineCallbacks + @log_function + def _on_send_request(self, origin, content, query, transaction_id): + """ Called on PUT /send// + + Args: + request (twisted.web.http.Request): The HTTP request. + transaction_id (str): The transaction_id associated with this + request. This is *not* None. + + Returns: + Deferred: Results in a tuple of `(code, response)`, where + `response` is a python dict to be converted into JSON that is + used as the response body. + """ + # Parse the request + try: + transaction_data = content + + logger.debug( + "Decoded %s: %s", + transaction_id, str(transaction_data) + ) + + # We should ideally be getting this from the security layer. + # origin = body["origin"] + + # Add some extra data to the transaction dict that isn't included + # in the request body. + transaction_data.update( + transaction_id=transaction_id, + destination=self.server_name + ) + + except Exception as e: + logger.exception(e) + defer.returnValue((400, {"error": "Invalid transaction"})) + return + + try: + handler = self.received_handler + code, response = yield handler.on_incoming_transaction( + transaction_data + ) + except: + logger.exception("on_incoming_transaction failed") + raise + + defer.returnValue((code, response)) + + + @log_function + def _on_backfill_request(self, origin, context, v_list, limits): + if not limits: + return defer.succeed( + (400, {"error": "Did not include limit param"}) + ) + + limit = int(limits[-1]) + + versions = v_list + + return self.request_handler.on_backfill_request( + origin, context, versions, limit + ) + + @defer.inlineCallbacks + @log_function + def _on_make_join_request(self, origin, content, query, context, user_id): + content = yield self.request_handler.on_make_join_request( + context, user_id, + ) + defer.returnValue((200, content)) + + @defer.inlineCallbacks + @log_function + def _on_send_join_request(self, origin, content, query): + content = yield self.request_handler.on_send_join_request( + origin, content, + ) + + defer.returnValue((200, content)) + + @defer.inlineCallbacks + @log_function + def _on_invite_request(self, origin, content, query): + content = yield self.request_handler.on_invite_request( + origin, content, + ) + + defer.returnValue((200, content)) -- cgit 1.5.1 From 2408c4b0a49bf21f1a84f3ac6549d30fd53bc5d4 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Fri, 16 Jan 2015 18:20:19 +0000 Subject: Fold _do_request_for_transaction into the methods that called it since it was a trivial wrapper around client.get_json --- synapse/federation/transport/client.py | 55 +++++++--------------------------- 1 file changed, 11 insertions(+), 44 deletions(-) (limited to 'synapse') diff --git a/synapse/federation/transport/client.py b/synapse/federation/transport/client.py index 604ade683b..d61ff192eb 100644 --- a/synapse/federation/transport/client.py +++ b/synapse/federation/transport/client.py @@ -29,7 +29,7 @@ class TransportLayerClient(object): """Sends federation HTTP requests to other servers""" @log_function - def get_context_state(self, destination, context, event_id=None): + def get_context_state(self, destination, context, event_id): """ Requests all state for a given context (i.e. room) from the given server. @@ -37,6 +37,7 @@ class TransportLayerClient(object): destination (str): The host name of the remote home server we want to get the state from. context (str): The name of the context we want the state of + event_id (str): The event we want the context at. Returns: Deferred: Results in a dict received from the remote homeserver. @@ -44,14 +45,9 @@ class TransportLayerClient(object): logger.debug("get_context_state dest=%s, context=%s", destination, context) - subpath = "/state/%s/" % context - - args = {} - if event_id: - args["event_id"] = event_id - - return self._do_request_for_transaction( - destination, subpath, args=args + path = PREFIX + "/state/%s/" % context + return self.client.get_json( + destination, path=path, args={"event_id": event_id}, ) @log_function @@ -69,9 +65,8 @@ class TransportLayerClient(object): logger.debug("get_pdu dest=%s, event_id=%s", destination, event_id) - subpath = "/event/%s/" % (event_id, ) - - return self._do_request_for_transaction(destination, subpath) + path = PREFIX + "/event/%s/" % (event_id, ) + return self.client.get_json(destination, path=path) @log_function def backfill(self, dest, context, event_tuples, limit): @@ -96,16 +91,16 @@ class TransportLayerClient(object): # TODO: raise? return - subpath = "/backfill/%s/" % (context,) + path = PREFIX + "/backfill/%s/" % (context,) args = { "v": event_tuples, "limit": [str(limit)], } - return self._do_request_for_transaction( - dest, - subpath, + return self.client.get_json( + destination, + path=path, args=args, ) @@ -227,31 +222,3 @@ class TransportLayerClient(object): ) defer.returnValue(response) - - @defer.inlineCallbacks - @log_function - def _do_request_for_transaction(self, destination, subpath, args={}): - """ - Args: - destination (str) - path (str) - args (dict): This is parsed directly to the HttpClient. - - Returns: - Deferred: Results in a dict. - """ - - data = yield self.client.get_json( - destination, - path=PREFIX + subpath, - args=args, - ) - - # Add certain keys to the JSON, ready for decoding as a Transaction - data.update( - origin=destination, - destination=self.server_name, - transaction_id=None - ) - - defer.returnValue(data) -- cgit 1.5.1 From 5fed04264056263e10b920a917a3a40f88e7e820 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Fri, 16 Jan 2015 18:59:04 +0000 Subject: Finish renaming "context" to "room_id" in federation codebase --- synapse/federation/replication.py | 94 +++++++++++++--------------------- synapse/federation/transport/client.py | 47 +++++++---------- synapse/federation/transport/server.py | 1 - synapse/handlers/_base.py | 4 +- synapse/handlers/federation.py | 10 ++-- synapse/http/matrixfederationclient.py | 1 - tests/handlers/test_room.py | 4 +- 7 files changed, 62 insertions(+), 99 deletions(-) (limited to 'synapse') diff --git a/synapse/federation/replication.py b/synapse/federation/replication.py index a4c29b484b..6620532a60 100644 --- a/synapse/federation/replication.py +++ b/synapse/federation/replication.py @@ -256,23 +256,21 @@ class ReplicationLayer(object): @defer.inlineCallbacks @log_function - def get_state_for_context(self, destination, context, event_id): - """Requests all of the `current` state PDUs for a given context from + def get_state_for_room(self, destination, room_id, event_id): + """Requests all of the `current` state PDUs for a given room from a remote home server. Args: destination (str): The remote homeserver to query for the state. - context (str): The context we're interested in. + room_id (str): The id of the room we're interested in. event_id (str): The id of the event we want the state at. Returns: Deferred: Results in a list of PDUs. """ - result = yield self.transport_layer.get_context_state( - destination, - context, - event_id=event_id, + result = yield self.transport_layer.get_room_state( + destination, room_id, event_id=event_id, ) pdus = [ @@ -288,9 +286,9 @@ class ReplicationLayer(object): @defer.inlineCallbacks @log_function - def get_event_auth(self, destination, context, event_id): + def get_event_auth(self, destination, room_id, event_id): res = yield self.transport_layer.get_event_auth( - destination, context, event_id, + destination, room_id, event_id, ) auth_chain = [ @@ -304,9 +302,9 @@ class ReplicationLayer(object): @defer.inlineCallbacks @log_function - def on_backfill_request(self, origin, context, versions, limit): + def on_backfill_request(self, origin, room_id, versions, limit): pdus = yield self.handler.on_backfill_request( - origin, context, versions, limit + origin, room_id, versions, limit ) defer.returnValue((200, self._transaction_from_pdus(pdus).get_dict())) @@ -380,12 +378,10 @@ class ReplicationLayer(object): @defer.inlineCallbacks @log_function - def on_context_state_request(self, origin, context, event_id): + def on_context_state_request(self, origin, room_id, event_id): if event_id: pdus = yield self.handler.get_state_for_pdu( - origin, - context, - event_id, + origin, room_id, event_id, ) auth_chain = yield self.store.get_auth_chain( [pdu.event_id for pdu in pdus] @@ -413,7 +409,7 @@ class ReplicationLayer(object): @defer.inlineCallbacks @log_function def on_pull_request(self, origin, versions): - raise NotImplementedError("Pull transacions not implemented") + raise NotImplementedError("Pull transactions not implemented") @defer.inlineCallbacks def on_query_request(self, query_type, args): @@ -422,30 +418,21 @@ class ReplicationLayer(object): defer.returnValue((200, response)) else: defer.returnValue( - (404, "No handler for Query type '%s'" % (query_type, )) + (404, "No handler for Query type '%s'" % (query_type,)) ) @defer.inlineCallbacks - def on_make_join_request(self, context, user_id): - pdu = yield self.handler.on_make_join_request(context, user_id) + def on_make_join_request(self, room_id, user_id): + pdu = yield self.handler.on_make_join_request(room_id, user_id) time_now = self._clock.time_msec() - defer.returnValue({ - "event": pdu.get_pdu_json(time_now), - }) + defer.returnValue({"event": pdu.get_pdu_json(time_now)}) @defer.inlineCallbacks def on_invite_request(self, origin, content): pdu = self.event_from_pdu_json(content) ret_pdu = yield self.handler.on_invite_request(origin, pdu) time_now = self._clock.time_msec() - defer.returnValue( - ( - 200, - { - "event": ret_pdu.get_pdu_json(time_now), - } - ) - ) + defer.returnValue((200, {"event": ret_pdu.get_pdu_json(time_now)})) @defer.inlineCallbacks def on_send_join_request(self, origin, content): @@ -462,26 +449,17 @@ class ReplicationLayer(object): })) @defer.inlineCallbacks - def on_event_auth(self, origin, context, event_id): + 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) - defer.returnValue( - ( - 200, - { - "auth_chain": [ - a.get_pdu_json(time_now) for a in auth_pdus - ], - } - ) - ) + defer.returnValue((200, { + "auth_chain": [a.get_pdu_json(time_now) for a in auth_pdus], + })) @defer.inlineCallbacks - def make_join(self, destination, context, user_id): + def make_join(self, destination, room_id, user_id): ret = yield self.transport_layer.make_join( - destination=destination, - context=context, - user_id=user_id, + destination, room_id, user_id ) pdu_dict = ret["event"] @@ -494,10 +472,10 @@ class ReplicationLayer(object): def send_join(self, destination, pdu): time_now = self._clock.time_msec() _, content = yield self.transport_layer.send_join( - destination, - pdu.room_id, - pdu.event_id, - pdu.get_pdu_json(time_now), + 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) @@ -507,9 +485,6 @@ class ReplicationLayer(object): for p in content.get("state", []) ] - # FIXME: We probably want to do something with the auth_chain given - # to us - auth_chain = [ self.event_from_pdu_json(p, outlier=True) for p in content.get("auth_chain", []) @@ -523,11 +498,11 @@ class ReplicationLayer(object): }) @defer.inlineCallbacks - def send_invite(self, destination, context, event_id, pdu): + def send_invite(self, destination, room_id, event_id, pdu): time_now = self._clock.time_msec() code, content = yield self.transport_layer.send_invite( destination=destination, - context=context, + room_id=room_id, event_id=event_id, content=pdu.get_pdu_json(time_now), ) @@ -657,7 +632,7 @@ class ReplicationLayer(object): "_handle_new_pdu getting state for %s", pdu.room_id ) - state, auth_chain = yield self.get_state_for_context( + state, auth_chain = yield self.get_state_for_room( origin, pdu.room_id, pdu.event_id, ) @@ -816,7 +791,7 @@ class _TransactionQueue(object): logger.info("TX [%s] is ready for retry", destination) logger.info("TX [%s] _attempt_new_transaction", destination) - + if destination in self.pending_transactions: # XXX: pending_transactions can get stuck on by a never-ending # request at which point pending_pdus_by_dest just keeps growing. @@ -830,14 +805,15 @@ class _TransactionQueue(object): pending_failures = self.pending_failures_by_dest.pop(destination, []) if pending_pdus: - logger.info("TX [%s] len(pending_pdus_by_dest[dest]) = %d", destination, len(pending_pdus)) + logger.info("TX [%s] len(pending_pdus_by_dest[dest]) = %d", + destination, len(pending_pdus)) if not pending_pdus and not pending_edus and not pending_failures: return logger.debug( - "TX [%s] Attempting new transaction " - "(pdus: %d, edus: %d, failures: %d)", + "TX [%s] Attempting new transaction" + " (pdus: %d, edus: %d, failures: %d)", destination, len(pending_pdus), len(pending_edus), diff --git a/synapse/federation/transport/client.py b/synapse/federation/transport/client.py index d61ff192eb..e634a3a213 100644 --- a/synapse/federation/transport/client.py +++ b/synapse/federation/transport/client.py @@ -29,9 +29,9 @@ class TransportLayerClient(object): """Sends federation HTTP requests to other servers""" @log_function - def get_context_state(self, destination, context, event_id): - """ Requests all state for a given context (i.e. room) from the - given server. + def get_room_state(self, destination, room_id, event_id): + """ Requests all state for a given room from the given server at the + given event. Args: destination (str): The host name of the remote home server we want @@ -42,10 +42,10 @@ class TransportLayerClient(object): Returns: Deferred: Results in a dict received from the remote homeserver. """ - logger.debug("get_context_state dest=%s, context=%s", - destination, context) + logger.debug("get_room_state dest=%s, room=%s", + destination, room_id) - path = PREFIX + "/state/%s/" % context + path = PREFIX + "/state/%s/" % room_id return self.client.get_json( destination, path=path, args={"event_id": event_id}, ) @@ -69,13 +69,13 @@ class TransportLayerClient(object): return self.client.get_json(destination, path=path) @log_function - def backfill(self, dest, context, event_tuples, limit): + def backfill(self, destination, room_id, event_tuples, limit): """ Requests `limit` previous PDUs in a given context before list of PDUs. Args: dest (str) - context (str) + room_id (str) event_tuples (list) limt (int) @@ -83,15 +83,15 @@ class TransportLayerClient(object): Deferred: Results in a dict received from the remote homeserver. """ logger.debug( - "backfill dest=%s, context=%s, event_tuples=%s, limit=%s", - dest, context, repr(event_tuples), str(limit) + "backfill dest=%s, room_id=%s, event_tuples=%s, limit=%s", + destination, room_id, repr(event_tuples), str(limit) ) if not event_tuples: # TODO: raise? return - path = PREFIX + "/backfill/%s/" % (context,) + path = PREFIX + "/backfill/%s/" % (room_id,) args = { "v": event_tuples, @@ -159,8 +159,8 @@ class TransportLayerClient(object): @defer.inlineCallbacks @log_function - def make_join(self, destination, context, user_id, retry_on_dns_fail=True): - path = PREFIX + "/make_join/%s/%s" % (context, user_id,) + def make_join(self, destination, room_id, user_id, retry_on_dns_fail=True): + path = PREFIX + "/make_join/%s/%s" % (room_id, user_id) response = yield self.client.get_json( destination=destination, @@ -172,11 +172,8 @@ class TransportLayerClient(object): @defer.inlineCallbacks @log_function - def send_join(self, destination, context, event_id, content): - path = PREFIX + "/send_join/%s/%s" % ( - context, - event_id, - ) + def send_join(self, destination, room_id, event_id, content): + path = PREFIX + "/send_join/%s/%s" % (room_id, event_id) code, content = yield self.client.put_json( destination=destination, @@ -191,11 +188,8 @@ class TransportLayerClient(object): @defer.inlineCallbacks @log_function - def send_invite(self, destination, context, event_id, content): - path = PREFIX + "/invite/%s/%s" % ( - context, - event_id, - ) + def send_invite(self, destination, room_id, event_id, content): + path = PREFIX + "/invite/%s/%s" % (room_id, event_id) code, content = yield self.client.put_json( destination=destination, @@ -210,11 +204,8 @@ class TransportLayerClient(object): @defer.inlineCallbacks @log_function - def get_event_auth(self, destination, context, event_id): - path = PREFIX + "/event_auth/%s/%s" % ( - context, - event_id, - ) + def get_event_auth(self, destination, room_id, event_id): + path = PREFIX + "/event_auth/%s/%s" % (room_id, event_id) response = yield self.client.get_json( destination=destination, diff --git a/synapse/federation/transport/server.py b/synapse/federation/transport/server.py index 34b50def7d..a380a6910b 100644 --- a/synapse/federation/transport/server.py +++ b/synapse/federation/transport/server.py @@ -285,7 +285,6 @@ class TransportLayerServer(object): defer.returnValue((code, response)) - @log_function def _on_backfill_request(self, origin, context, v_list, limits): if not limits: diff --git a/synapse/handlers/_base.py b/synapse/handlers/_base.py index 38af034b4d..f33d17a31e 100644 --- a/synapse/handlers/_base.py +++ b/synapse/handlers/_base.py @@ -144,7 +144,5 @@ class BaseHandler(object): yield self.notifier.on_new_room_event(event, extra_users=extra_users) yield federation_handler.handle_new_event( - event, - None, - destinations=destinations, + event, destinations=destinations, ) diff --git a/synapse/handlers/federation.py b/synapse/handlers/federation.py index 195f7c618a..81203bf1a3 100644 --- a/synapse/handlers/federation.py +++ b/synapse/handlers/federation.py @@ -75,14 +75,14 @@ class FederationHandler(BaseHandler): @log_function @defer.inlineCallbacks - def handle_new_event(self, event, snapshot, destinations): + def handle_new_event(self, event, destinations): """ Takes in an event from the client to server side, that has already been authed and handled by the state module, and sends it to any remote home servers that may be interested. Args: - event - snapshot (.storage.Snapshot): THe snapshot the event happened after + event: The event to send + destinations: A list of destinations to send it to Returns: Deferred: Resolved when it has successfully been queued for @@ -154,7 +154,7 @@ class FederationHandler(BaseHandler): replication = self.replication_layer if not state: - state, auth_chain = yield replication.get_state_for_context( + state, auth_chain = yield replication.get_state_for_room( origin, context=event.room_id, event_id=event.event_id, ) @@ -281,7 +281,7 @@ class FederationHandler(BaseHandler): """ pdu = yield self.replication_layer.send_invite( destination=target_host, - context=event.room_id, + room_id=event.room_id, event_id=event.event_id, pdu=event ) diff --git a/synapse/http/matrixfederationclient.py b/synapse/http/matrixfederationclient.py index aa14782b0f..1dda3ba2c7 100644 --- a/synapse/http/matrixfederationclient.py +++ b/synapse/http/matrixfederationclient.py @@ -72,7 +72,6 @@ class MatrixFederationHttpClient(object): requests. """ - def __init__(self, hs): self.hs = hs self.signing_key = hs.config.signing_key[0] diff --git a/tests/handlers/test_room.py b/tests/handlers/test_room.py index 0cb8aa4fbc..d3253b48b8 100644 --- a/tests/handlers/test_room.py +++ b/tests/handlers/test_room.py @@ -223,7 +223,7 @@ class RoomMemberHandlerTestCase(unittest.TestCase): yield room_handler.change_membership(event, context) self.federation.handle_new_event.assert_called_once_with( - event, None, destinations=set() + event, destinations=set() ) self.datastore.persist_event.assert_called_once_with( @@ -301,7 +301,7 @@ class RoomMemberHandlerTestCase(unittest.TestCase): yield room_handler.change_membership(event, context) self.federation.handle_new_event.assert_called_once_with( - event, None, destinations=set(['red']) + event, destinations=set(['red']) ) self.datastore.persist_event.assert_called_once_with( -- cgit 1.5.1 From 3e85e52b3f0e9330f29ec3d0f572db7b122c88b0 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Mon, 19 Jan 2015 15:26:19 +0000 Subject: Allow ':memory:' as the database path for sqlite3 --- synapse/app/homeserver.py | 8 +++++++- synapse/config/database.py | 5 ++++- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'synapse') diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py index 43b5c26144..61ad53fbb2 100755 --- a/synapse/app/homeserver.py +++ b/synapse/app/homeserver.py @@ -247,7 +247,13 @@ def setup(): logger.info("Database prepared in %s.", db_name) - hs.get_db_pool() + db_pool = hs.get_db_pool() + + if db_name == ":memory:" + # Memory databases will need to be setup each time they are opened. + reactor.callWhenRunning( + hs.get_db_pool().runWithConnection, prepare_database + ) if config.manhole: f = twisted.manhole.telnet.ShellFactory() diff --git a/synapse/config/database.py b/synapse/config/database.py index 0d33583a7d..daa161c952 100644 --- a/synapse/config/database.py +++ b/synapse/config/database.py @@ -20,7 +20,10 @@ import os class DatabaseConfig(Config): def __init__(self, args): super(DatabaseConfig, self).__init__(args) - self.database_path = self.abspath(args.database_path) + if args.database_path == ":memory:": + self.database_path = ":memory:" + else: + self.database_path = self.abspath(args.database_path) @classmethod def add_arguments(cls, parser): -- cgit 1.5.1 From 00e9c08609eb498d783c3812d9415f2706029559 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Mon, 19 Jan 2015 15:30:48 +0000 Subject: Fix syntax --- synapse/app/homeserver.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'synapse') diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py index 61ad53fbb2..f00b06aa7f 100755 --- a/synapse/app/homeserver.py +++ b/synapse/app/homeserver.py @@ -241,7 +241,8 @@ def setup(): except UpgradeDatabaseException: sys.stderr.write( "\nFailed to upgrade database.\n" - "Have you checked for version specific instructions in UPGRADES.rst?\n" + "Have you checked for version specific instructions in" + " UPGRADES.rst?\n" ) sys.exit(1) @@ -249,7 +250,7 @@ def setup(): db_pool = hs.get_db_pool() - if db_name == ":memory:" + if db_name == ":memory:": # Memory databases will need to be setup each time they are opened. reactor.callWhenRunning( hs.get_db_pool().runWithConnection, prepare_database -- cgit 1.5.1 From 42529cbcedbea7c7f7347c793f113e2cbc7c73eb Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Mon, 19 Jan 2015 15:33:04 +0000 Subject: Fix pyflakes errors --- synapse/app/homeserver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'synapse') diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py index f00b06aa7f..afe3d19760 100755 --- a/synapse/app/homeserver.py +++ b/synapse/app/homeserver.py @@ -253,7 +253,7 @@ def setup(): if db_name == ":memory:": # Memory databases will need to be setup each time they are opened. reactor.callWhenRunning( - hs.get_db_pool().runWithConnection, prepare_database + db_pool.runWithConnection, prepare_database ) if config.manhole: -- cgit 1.5.1 From dc70d1fef8c2f2f68c598c75e9808b6bed0873f6 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Mon, 19 Jan 2015 16:24:54 +0000 Subject: Only start the notifier timeout once we've had a chance to check for updates. Otherwise the timeout could fire while we are waiting for the database to return any updates it might have --- synapse/notifier.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'synapse') diff --git a/synapse/notifier.py b/synapse/notifier.py index b9d52d0c4c..3aec1d4af2 100644 --- a/synapse/notifier.py +++ b/synapse/notifier.py @@ -244,14 +244,14 @@ class Notifier(object): ) if timeout: - self.clock.call_later(timeout/1000.0, _timeout_listener) - self._register_with_keys(listener) yield self._check_for_updates(listener) if not timeout: _timeout_listener() + else: + self.clock.call_later(timeout/1000.0, _timeout_listener) return -- cgit 1.5.1