From dd661769e1846b627d26203f6ca7936e0820d93c Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 27 Aug 2014 11:33:56 +0100 Subject: Renamed /rooms to /createRoom. Removed ability to PUT raw room IDs, and removed tests which tested that. Updated cmdclient and webclient. --- synapse/rest/room.py | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'synapse') diff --git a/synapse/rest/room.py b/synapse/rest/room.py index b8d5cb87fd..1cbb31e301 100644 --- a/synapse/rest/room.py +++ b/synapse/rest/room.py @@ -34,31 +34,28 @@ class RoomCreateRestServlet(RestServlet): # No PATTERN; we have custom dispatch rules here def register(self, http_server): - # /rooms OR /rooms/ - http_server.register_path("POST", - client_path_pattern("/rooms$"), - self.on_POST) - http_server.register_path("PUT", - client_path_pattern( - "/rooms/(?P[^/]*)$"), - self.on_PUT) + PATTERN = "/createRoom" + register_txn_path(self, PATTERN, http_server) # define CORS for all of /rooms in RoomCreateRestServlet for simplicity http_server.register_path("OPTIONS", client_path_pattern("/rooms(?:/.*)?$"), self.on_OPTIONS) + # define CORS for /createRoom[/txnid] + http_server.register_path("OPTIONS", + client_path_pattern("/createRoom(?:/.*)?$"), + self.on_OPTIONS) @defer.inlineCallbacks - def on_PUT(self, request, room_id): - room_id = urllib.unquote(room_id) - auth_user = yield self.auth.get_user_by_req(request) + def on_PUT(self, request, txn_id): + try: + defer.returnValue(self.txns.get_client_transaction(request, txn_id)) + except KeyError: + pass - if not room_id: - raise SynapseError(400, "PUT must specify a room ID") + response = yield self.on_POST(request) - room_config = self.get_room_config(request) - info = yield self.make_room(room_config, auth_user, room_id) - room_config.update(info) - defer.returnValue((200, info)) + self.txns.store_client_transaction(request, txn_id, response) + defer.returnValue(response) @defer.inlineCallbacks def on_POST(self, request): -- cgit 1.5.1 From 135a1aa229f09badb7aeb79e803ab5d7654230ac Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 27 Aug 2014 11:37:53 +0100 Subject: Final url modifications: renamed /presence_list to /presence/list to keep the top-level namespace clean. Updated tests. --- synapse/rest/presence.py | 2 +- tests/rest/test_presence.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'synapse') diff --git a/synapse/rest/presence.py b/synapse/rest/presence.py index 6043848595..e013b20853 100644 --- a/synapse/rest/presence.py +++ b/synapse/rest/presence.py @@ -68,7 +68,7 @@ class PresenceStatusRestServlet(RestServlet): class PresenceListRestServlet(RestServlet): - PATTERN = client_path_pattern("/presence_list/(?P[^/]*)") + PATTERN = client_path_pattern("/presence/list/(?P[^/]*)") @defer.inlineCallbacks def on_GET(self, request, user_id): diff --git a/tests/rest/test_presence.py b/tests/rest/test_presence.py index 970405d271..e249a0d48a 100644 --- a/tests/rest/test_presence.py +++ b/tests/rest/test_presence.py @@ -171,7 +171,7 @@ class PresenceListTestCase(unittest.TestCase): ) (code, response) = yield self.mock_resource.trigger("GET", - "/presence_list/%s" % (myid), None) + "/presence/list/%s" % (myid), None) self.assertEquals(200, code) self.assertEquals( @@ -192,7 +192,7 @@ class PresenceListTestCase(unittest.TestCase): ) (code, response) = yield self.mock_resource.trigger("POST", - "/presence_list/%s" % (myid), + "/presence/list/%s" % (myid), """{"invite": ["@banana:test"]}""" ) @@ -212,7 +212,7 @@ class PresenceListTestCase(unittest.TestCase): ) (code, response) = yield self.mock_resource.trigger("POST", - "/presence_list/%s" % (myid), + "/presence/list/%s" % (myid), """{"drop": ["@banana:test"]}""" ) -- cgit 1.5.1 From 648796ef1de4335f26b464ef24f14fd8dd550e31 Mon Sep 17 00:00:00 2001 From: "Paul \"LeoNerd\" Evans" Date: Wed, 20 Aug 2014 16:40:51 +0100 Subject: Neater database setup at application startup time; only .connect() it once, not once per schema file; don't build the db_pool twice --- synapse/app/homeserver.py | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) (limited to 'synapse') diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py index f210d26629..d63afd1b4a 100755 --- a/synapse/app/homeserver.py +++ b/synapse/app/homeserver.py @@ -43,6 +43,17 @@ import re logger = logging.getLogger(__name__) +SCHEMAS = [ + "transactions", + "pdu", + "users", + "profiles", + "presence", + "im", + "room_aliases", +] + + class SynapseHomeServer(HomeServer): def build_http_client(self): @@ -65,24 +76,11 @@ class SynapseHomeServer(HomeServer): don't have to worry about overwriting existing content. """ logging.info("Preparing database: %s...", self.db_name) - pool = adbapi.ConnectionPool( - 'sqlite3', self.db_name, check_same_thread=False, - cp_min=1, cp_max=1) - schemas = [ - "transactions", - "pdu", - "users", - "profiles", - "presence", - "im", - "room_aliases", - ] + with sqlite3.connect(self.db_name) as db_conn: + for sql_loc in SCHEMAS: + sql_script = read_schema(sql_loc) - for sql_loc in schemas: - sql_script = read_schema(sql_loc) - - with sqlite3.connect(self.db_name) as db_conn: c = db_conn.cursor() c.executescript(sql_script) c.close() @@ -90,6 +88,10 @@ class SynapseHomeServer(HomeServer): logging.info("Database prepared in %s.", self.db_name) + pool = adbapi.ConnectionPool( + 'sqlite3', self.db_name, check_same_thread=False, + cp_min=1, cp_max=1) + return pool def create_resource_tree(self, web_client, redirect_root_to_web_client): @@ -282,7 +284,7 @@ def setup(): redirect_root_to_web_client=True) hs.start_listening(args.port) - hs.build_db_pool() + hs.get_db_pool() if args.manhole: f = twisted.manhole.telnet.ShellFactory() -- cgit 1.5.1 From e677a3114e0395a328b4d5f775f60532bad4e7eb Mon Sep 17 00:00:00 2001 From: "Paul \"LeoNerd\" Evans" Date: Wed, 20 Aug 2014 16:49:54 +0100 Subject: Use SQLite's PRAGMA user_version to check if the database file really matches the schema we have in mind --- synapse/app/homeserver.py | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) (limited to 'synapse') diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py index d63afd1b4a..d0a4880da3 100755 --- a/synapse/app/homeserver.py +++ b/synapse/app/homeserver.py @@ -54,6 +54,11 @@ SCHEMAS = [ ] +# Remember to update this number every time an incompatible change is made to +# database schema files, so the users will be informed on server restarts. +SCHEMA_VERSION = 1 + + class SynapseHomeServer(HomeServer): def build_http_client(self): @@ -78,13 +83,30 @@ class SynapseHomeServer(HomeServer): logging.info("Preparing database: %s...", self.db_name) with sqlite3.connect(self.db_name) as db_conn: - for sql_loc in SCHEMAS: - sql_script = read_schema(sql_loc) + c = db_conn.cursor() + c.execute("PRAGMA user_version") + row = c.fetchone() + + if row and row[0]: + user_version = row[0] + + if user_version < SCHEMA_VERSION: + # TODO(paul): add some kind of intelligent fixup here + raise ValueError("Cannot use this database as the " + + "schema version (%d) does not match (%d)" % + (user_version, SCHEMA_VERSION) + ) + + else: + for sql_loc in SCHEMAS: + sql_script = read_schema(sql_loc) + + c.executescript(sql_script) + db_conn.commit() + + c.execute("PRAGMA user_version = %d" % SCHEMA_VERSION) - c = db_conn.cursor() - c.executescript(sql_script) - c.close() - db_conn.commit() + c.close() logging.info("Database prepared in %s.", self.db_name) -- cgit 1.5.1 From d63f775e06f873236d560825e97c4b91163e8584 Mon Sep 17 00:00:00 2001 From: "Paul \"LeoNerd\" Evans" Date: Wed, 20 Aug 2014 17:40:20 +0100 Subject: Added parse_roomid() helper --- synapse/server.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'synapse') diff --git a/synapse/server.py b/synapse/server.py index 439b9d628e..24f3a88103 100644 --- a/synapse/server.py +++ b/synapse/server.py @@ -126,6 +126,11 @@ class BaseHomeServer(object): object.""" return UserID.from_string(s, hs=self) + def parse_roomid(self, s): + """Parse the string given by 's' as a Room ID and return a RoomID + object.""" + return RoomID.from_string(s, hs=self) + def parse_roomalias(self, s): """Parse the string given by 's' as a Room Alias and return a RoomAlias object.""" -- cgit 1.5.1 From 5eff05a4ce83c7ab8f489d38707a0c895ccad6b7 Mon Sep 17 00:00:00 2001 From: "Paul \"LeoNerd\" Evans" Date: Wed, 20 Aug 2014 19:15:47 +0100 Subject: Initial typing notification support - EDU federation, but no timers, and no actual push to clients --- synapse/handlers/__init__.py | 2 + synapse/handlers/typing.py | 146 ++++++++++++++++++++++++ tests/handlers/test_typing.py | 250 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 398 insertions(+) create mode 100644 synapse/handlers/typing.py create mode 100644 tests/handlers/test_typing.py (limited to 'synapse') diff --git a/synapse/handlers/__init__.py b/synapse/handlers/__init__.py index 7417a02cea..b645977767 100644 --- a/synapse/handlers/__init__.py +++ b/synapse/handlers/__init__.py @@ -23,6 +23,7 @@ from .login import LoginHandler from .profile import ProfileHandler from .presence import PresenceHandler from .directory import DirectoryHandler +from .typing import TypingNotificationHandler class Handlers(object): @@ -46,3 +47,4 @@ class Handlers(object): self.room_list_handler = RoomListHandler(hs) self.login_handler = LoginHandler(hs) self.directory_handler = DirectoryHandler(hs) + self.typing_notification_handler = TypingNotificationHandler(hs) diff --git a/synapse/handlers/typing.py b/synapse/handlers/typing.py new file mode 100644 index 0000000000..9d38a7336e --- /dev/null +++ b/synapse/handlers/typing.py @@ -0,0 +1,146 @@ +# -*- coding: utf-8 -*- +# Copyright 2014 matrix.org +# +# 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 ._base import BaseHandler + +import logging + +from collections import namedtuple + + +logger = logging.getLogger(__name__) + + +# A tiny object useful for storing a user's membership in a room, as a mapping +# key +RoomMember = namedtuple("RoomMember", ("room_id", "user")) + + +class TypingNotificationHandler(BaseHandler): + def __init__(self, hs): + super(TypingNotificationHandler, self).__init__(hs) + + self.homeserver = hs + + self.clock = hs.get_clock() + + self.federation = hs.get_replication_layer() + + self.federation.register_edu_handler("m.typing", self._recv_edu) + + self._member_typing_until = {} + + @defer.inlineCallbacks + def started_typing(self, target_user, auth_user, room_id, timeout): + if not target_user.is_mine: + raise SynapseError(400, "User is not hosted on this Home Server") + + if target_user != auth_user: + raise AuthError(400, "Cannot set another user's typing state") + + until = self.clock.time_msec() + timeout + member = RoomMember(room_id=room_id, user=target_user) + + was_present = member in self._member_typing_until + + self._member_typing_until[member] = until + + if was_present: + # No point sending another notification + defer.returnValue(None) + + yield self._push_update( + room_id=room_id, + user=target_user, + typing=True, + ) + + @defer.inlineCallbacks + def stopped_typing(self, target_user, auth_user, room_id): + if not target_user.is_mine: + raise SynapseError(400, "User is not hosted on this Home Server") + + if target_user != auth_user: + raise AuthError(400, "Cannot set another user's typing state") + + member = RoomMember(room_id=room_id, user=target_user) + + if member not in self._member_typing_until: + # No point + defer.returnValue(None) + + yield self._push_update( + room_id=room_id, + user=target_user, + typing=False, + ) + + @defer.inlineCallbacks + def _push_update(self, room_id, user, typing): + localusers = set() + remotedomains = set() + + rm_handler = self.homeserver.get_handlers().room_member_handler + yield rm_handler.fetch_room_distributions_into(room_id, + localusers=localusers, remotedomains=remotedomains, + ignore_user=user) + + for u in localusers: + self.push_update_to_clients( + room_id=room_id, + observer_user=u, + observed_user=user, + typing=typing, + ) + + deferreds = [] + for domain in remotedomains: + deferreds.append(self.federation.send_edu( + destination=domain, + edu_type="m.typing", + content={ + "room_id": room_id, + "user_id": user.to_string(), + "typing": typing, + }, + )) + + yield defer.DeferredList(deferreds, consumeErrors=False) + + @defer.inlineCallbacks + def _recv_edu(self, origin, content): + room_id = content["room_id"] + user = self.homeserver.parse_userid(content["user_id"]) + + localusers = set() + + rm_handler = self.homeserver.get_handlers().room_member_handler + yield rm_handler.fetch_room_distributions_into(room_id, + localusers=localusers) + + for u in localusers: + self.push_update_to_clients( + room_id=room_id, + observer_user=u, + observed_user=user, + typing=content["typing"] + ) + + def push_update_to_clients(self, room_id, observer_user, observed_user, + typing): + # TODO(paul) steal this from presence.py + pass diff --git a/tests/handlers/test_typing.py b/tests/handlers/test_typing.py new file mode 100644 index 0000000000..300a6e340a --- /dev/null +++ b/tests/handlers/test_typing.py @@ -0,0 +1,250 @@ +# -*- coding: utf-8 -*- +# Copyright 2014 matrix.org +# +# 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.trial import unittest +from twisted.internet import defer + +from mock import Mock, call, ANY +import json +import logging + +from ..utils import MockHttpResource, MockClock, DeferredMockCallable + +from synapse.server import HomeServer +from synapse.handlers.typing import TypingNotificationHandler + + +logging.getLogger().addHandler(logging.NullHandler()) + + +def _expect_edu(destination, edu_type, content, origin="test"): + return { + "origin": origin, + "ts": 1000000, + "pdus": [], + "edus": [ + { + "origin": origin, + "destination": destination, + "edu_type": edu_type, + "content": content, + } + ], + } + + +def _make_edu_json(origin, edu_type, content): + return json.dumps(_expect_edu("test", edu_type, content, origin=origin)) + + +class JustTypingNotificationHandlers(object): + def __init__(self, hs): + self.typing_notification_handler = TypingNotificationHandler(hs) + + +class TypingNotificationsTestCase(unittest.TestCase): + """Tests typing notifications to rooms.""" + def setUp(self): + self.clock = MockClock() + + self.mock_http_client = Mock(spec=[]) + self.mock_http_client.put_json = DeferredMockCallable() + + self.mock_federation_resource = MockHttpResource() + + hs = HomeServer("test", + clock=self.clock, + db_pool=None, + datastore=Mock(spec=[ + # Bits that Federation needs + "prep_send_transaction", + "delivered_txn", + "get_received_txn_response", + "set_received_txn_response", + ]), + handlers=None, + resource_for_client=Mock(), + resource_for_federation=self.mock_federation_resource, + http_client=self.mock_http_client, + ) + hs.handlers = JustTypingNotificationHandlers(hs) + + self.mock_update_client = Mock() + self.mock_update_client.return_value = defer.succeed(None) + + self.handler = hs.get_handlers().typing_notification_handler + self.handler.push_update_to_clients = self.mock_update_client + + self.datastore = hs.get_datastore() + + def get_received_txn_response(*args): + return defer.succeed(None) + self.datastore.get_received_txn_response = get_received_txn_response + + self.room_id = "a-room" + + # Mock the RoomMemberHandler + hs.handlers.room_member_handler = Mock(spec=[]) + self.room_member_handler = hs.handlers.room_member_handler + + self.room_members = [] + + def get_rooms_for_user(user): + if user in self.room_members: + return defer.succeed([self.room_id]) + else: + return defer.succeed([]) + self.room_member_handler.get_rooms_for_user = get_rooms_for_user + + def get_room_members(room_id): + if room_id == self.room_id: + return defer.succeed(self.room_members) + else: + return defer.succeed([]) + self.room_member_handler.get_room_members = get_room_members + + @defer.inlineCallbacks + def fetch_room_distributions_into(room_id, localusers=None, + remotedomains=None, ignore_user=None): + + members = yield get_room_members(room_id) + for member in members: + if ignore_user is not None and member == ignore_user: + continue + + if member.is_mine: + if localusers is not None: + localusers.add(member) + else: + if remotedomains is not None: + remotedomains.add(member.domain) + self.room_member_handler.fetch_room_distributions_into = ( + fetch_room_distributions_into) + + # Some local users to test with + self.u_apple = hs.parse_userid("@apple:test") + self.u_banana = hs.parse_userid("@banana:test") + + # Remote user + self.u_onion = hs.parse_userid("@onion:farm") + + @defer.inlineCallbacks + def test_started_typing_local(self): + self.room_members = [self.u_apple, self.u_banana] + + yield self.handler.started_typing( + target_user=self.u_apple, + auth_user=self.u_apple, + room_id=self.room_id, + timeout=20000, + ) + + self.mock_update_client.assert_has_calls([ + call(observer_user=self.u_banana, + observed_user=self.u_apple, + room_id=self.room_id, + typing=True), + ]) + + @defer.inlineCallbacks + def test_started_typing_remote_send(self): + self.room_members = [self.u_apple, self.u_onion] + + put_json = self.mock_http_client.put_json + put_json.expect_call_and_return( + call("farm", + path="/matrix/federation/v1/send/1000000/", + data=_expect_edu("farm", "m.typing", + content={ + "room_id": self.room_id, + "user_id": self.u_apple.to_string(), + "typing": True, + } + ) + ), + defer.succeed((200, "OK")) + ) + + yield self.handler.started_typing( + target_user=self.u_apple, + auth_user=self.u_apple, + room_id=self.room_id, + timeout=20000, + ) + + yield put_json.await_calls() + + @defer.inlineCallbacks + def test_started_typing_remote_recv(self): + self.room_members = [self.u_apple, self.u_onion] + + yield self.mock_federation_resource.trigger("PUT", + "/matrix/federation/v1/send/1000000/", + _make_edu_json("farm", "m.typing", + content={ + "room_id": self.room_id, + "user_id": self.u_onion.to_string(), + "typing": True, + } + ) + ) + + self.mock_update_client.assert_has_calls([ + call(observer_user=self.u_apple, + observed_user=self.u_onion, + room_id=self.room_id, + typing=True), + ]) + + @defer.inlineCallbacks + def test_stopped_typing(self): + self.room_members = [self.u_apple, self.u_banana, self.u_onion] + + put_json = self.mock_http_client.put_json + put_json.expect_call_and_return( + call("farm", + path="/matrix/federation/v1/send/1000000/", + data=_expect_edu("farm", "m.typing", + content={ + "room_id": self.room_id, + "user_id": self.u_apple.to_string(), + "typing": False, + } + ) + ), + defer.succeed((200, "OK")) + ) + + # Gut-wrenching + from synapse.handlers.typing import RoomMember + self.handler._member_typing_until[ + RoomMember(self.room_id, self.u_apple) + ] = 1002000 + + yield self.handler.stopped_typing( + target_user=self.u_apple, + auth_user=self.u_apple, + room_id=self.room_id, + ) + + self.mock_update_client.assert_has_calls([ + call(observer_user=self.u_banana, + observed_user=self.u_apple, + room_id=self.room_id, + typing=False), + ]) + + yield put_json.await_calls() -- cgit 1.5.1 From 05fa81fee43c02aa370b576c5cdfb7940f8c2e99 Mon Sep 17 00:00:00 2001 From: "Paul \"LeoNerd\" Evans" Date: Wed, 27 Aug 2014 13:07:25 +0100 Subject: A reliable logger.info() message /after/ the TCP port has been opened and is listening; this is essential for avoiding races in wrapper scripts e.g. integration testing --- synapse/app/homeserver.py | 1 + 1 file changed, 1 insertion(+) (limited to 'synapse') diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py index d0a4880da3..a89770ed7b 100755 --- a/synapse/app/homeserver.py +++ b/synapse/app/homeserver.py @@ -208,6 +208,7 @@ class SynapseHomeServer(HomeServer): def start_listening(self, port): reactor.listenTCP(port, Site(self.root_resource)) + logger.info("Synapse now listening on port %d", port) def setup_logging(verbosity=0, filename=None, config_path=None): -- cgit 1.5.1 From 1d9d287c7c9e1149561e2e4b9623a74823f441db Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 27 Aug 2014 14:51:59 +0100 Subject: Renamed /public/rooms to /publicRooms --- synapse/rest/__init__.py | 4 +--- synapse/rest/public.py | 33 --------------------------- synapse/rest/room.py | 12 ++++++++++ webclient/components/matrix/matrix-service.js | 2 +- 4 files changed, 14 insertions(+), 37 deletions(-) delete mode 100644 synapse/rest/public.py (limited to 'synapse') diff --git a/synapse/rest/__init__.py b/synapse/rest/__init__.py index 47896612ce..f33024e72a 100644 --- a/synapse/rest/__init__.py +++ b/synapse/rest/__init__.py @@ -15,8 +15,7 @@ from . import ( - room, events, register, login, profile, public, presence, initial_sync, - directory + room, events, register, login, profile, presence, initial_sync, directory ) @@ -40,7 +39,6 @@ class RestServletFactory(object): register.register_servlets(hs, client_resource) login.register_servlets(hs, client_resource) profile.register_servlets(hs, client_resource) - public.register_servlets(hs, client_resource) presence.register_servlets(hs, client_resource) initial_sync.register_servlets(hs, client_resource) directory.register_servlets(hs, client_resource) diff --git a/synapse/rest/public.py b/synapse/rest/public.py deleted file mode 100644 index 3430c8049f..0000000000 --- a/synapse/rest/public.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright 2014 matrix.org -# -# 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. - -"""This module contains REST servlets to do with public paths: /public""" -from twisted.internet import defer - -from base import RestServlet, client_path_pattern - - -class PublicRoomListRestServlet(RestServlet): - PATTERN = client_path_pattern("/public/rooms$") - - @defer.inlineCallbacks - def on_GET(self, request): - handler = self.handlers.room_list_handler - data = yield handler.get_public_room_list() - defer.returnValue((200, data)) - - -def register_servlets(hs, http_server): - PublicRoomListRestServlet(hs).register(http_server) diff --git a/synapse/rest/room.py b/synapse/rest/room.py index 1cbb31e301..3f2530b141 100644 --- a/synapse/rest/room.py +++ b/synapse/rest/room.py @@ -264,6 +264,17 @@ class JoinRoomAliasServlet(RestServlet): defer.returnValue(response) +# TODO: Needs unit testing +class PublicRoomListRestServlet(RestServlet): + PATTERN = client_path_pattern("/publicRooms$") + + @defer.inlineCallbacks + def on_GET(self, request): + handler = self.handlers.room_list_handler + data = yield handler.get_public_room_list() + defer.returnValue((200, data)) + + # TODO: Needs unit testing class RoomMemberListRestServlet(RestServlet): PATTERN = client_path_pattern("/rooms/(?P[^/]*)/members$") @@ -424,3 +435,4 @@ def register_servlets(hs, http_server): RoomTriggerBackfill(hs).register(http_server) RoomMembershipRestServlet(hs).register(http_server) RoomSendEventRestServlet(hs).register(http_server) + PublicRoomListRestServlet(hs).register(http_server) diff --git a/webclient/components/matrix/matrix-service.js b/webclient/components/matrix/matrix-service.js index e467ca40da..aad0960db9 100644 --- a/webclient/components/matrix/matrix-service.js +++ b/webclient/components/matrix/matrix-service.js @@ -235,7 +235,7 @@ angular.module('matrixService', []) // get a list of public rooms on your home server publicRooms: function() { - var path = "/public/rooms" + var path = "/publicRooms" return doRequest("GET", path); }, -- cgit 1.5.1 From c585c87c4b13691c68926b8abffa3a9deb6b0937 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 27 Aug 2014 14:54:29 +0100 Subject: Renamed /ds to /directory --- synapse/rest/directory.py | 2 +- webclient/components/matrix/matrix-service.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'synapse') diff --git a/synapse/rest/directory.py b/synapse/rest/directory.py index be9a3f5f9f..dc347652a0 100644 --- a/synapse/rest/directory.py +++ b/synapse/rest/directory.py @@ -31,7 +31,7 @@ def register_servlets(hs, http_server): class ClientDirectoryServer(RestServlet): - PATTERN = client_path_pattern("/ds/room/(?P[^/]*)$") + PATTERN = client_path_pattern("/directory/room/(?P[^/]*)$") @defer.inlineCallbacks def on_GET(self, request, room_alias): diff --git a/webclient/components/matrix/matrix-service.js b/webclient/components/matrix/matrix-service.js index aad0960db9..93e23de68c 100644 --- a/webclient/components/matrix/matrix-service.js +++ b/webclient/components/matrix/matrix-service.js @@ -155,7 +155,7 @@ angular.module('matrixService', []) // Retrieves the room ID corresponding to a room alias resolveRoomAlias:function(room_alias) { - var path = "/matrix/client/api/v1/ds/room/$room_alias"; + var path = "/matrix/client/api/v1/directory/room/$room_alias"; room_alias = encodeURIComponent(room_alias); path = path.replace("$room_alias", room_alias); -- cgit 1.5.1 From 4e8d19ee2ba760ac366f89743b873df15d8e1def Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 27 Aug 2014 16:42:33 +0100 Subject: Added RestServlet for /rooms/$roomid/state --- synapse/rest/room.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'synapse') diff --git a/synapse/rest/room.py b/synapse/rest/room.py index 3f2530b141..2d30eeaf38 100644 --- a/synapse/rest/room.py +++ b/synapse/rest/room.py @@ -322,6 +322,21 @@ class RoomMessageListRestServlet(RestServlet): defer.returnValue((200, msgs)) +# TODO: Needs unit testing +class RoomStateRestServlet(RestServlet): + PATTERN = client_path_pattern("/rooms/(?P[^/]*)/state$") + + @defer.inlineCallbacks + def on_GET(self, request, room_id): + user = yield self.auth.get_user_by_req(request) + # TODO: Get all the current state for this room and return in the same + # format as initial sync, that is: + # [ + # { state event }, { state event } + # ] + defer.returnValue((200, [])) + + class RoomTriggerBackfill(RestServlet): PATTERN = client_path_pattern("/rooms/(?P[^/]*)/backfill$") @@ -436,3 +451,4 @@ def register_servlets(hs, http_server): RoomMembershipRestServlet(hs).register(http_server) RoomSendEventRestServlet(hs).register(http_server) PublicRoomListRestServlet(hs).register(http_server) + RoomStateRestServlet(hs).register(http_server) -- cgit 1.5.1 From f64887e15c3b554d375e3ae3585aa592ace550dc Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 27 Aug 2014 16:49:01 +0100 Subject: Added RestServlet for /rooms/$roomid/initialSync --- synapse/rest/room.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'synapse') diff --git a/synapse/rest/room.py b/synapse/rest/room.py index 2d30eeaf38..ebe4e24432 100644 --- a/synapse/rest/room.py +++ b/synapse/rest/room.py @@ -337,6 +337,35 @@ class RoomStateRestServlet(RestServlet): defer.returnValue((200, [])) +# TODO: Needs unit testing +class RoomInitialSyncRestServlet(RestServlet): + PATTERN = client_path_pattern("/rooms/(?P[^/]*)/initialSync$") + + @defer.inlineCallbacks + def on_GET(self, request, room_id): + user = yield self.auth.get_user_by_req(request) + # TODO: Get all the initial sync data for this room and return in the + # same format as initial sync, that is: + # { + # membership: join, + # messages: [ + # chunk: [ msg events ], + # start: s_tok, + # end: e_tok + # ], + # room_id: foo, + # state: [ + # { state event } , { state event } + # ] + # } + # Probably worth keeping the keys room_id and membership for parity with + # /initialSync even though they must be joined to sync this and know the + # room ID, so clients can reuse the same code (room_id and membership + # are MANDATORY for /initialSync, so the code will expect it to be + # there) + defer.returnValue((200, {})) + + class RoomTriggerBackfill(RestServlet): PATTERN = client_path_pattern("/rooms/(?P[^/]*)/backfill$") @@ -452,3 +481,4 @@ def register_servlets(hs, http_server): RoomSendEventRestServlet(hs).register(http_server) PublicRoomListRestServlet(hs).register(http_server) RoomStateRestServlet(hs).register(http_server) + RoomInitialSyncRestServlet(hs).register(http_server) -- cgit 1.5.1