diff --git a/synapse/api/auth.py b/synapse/api/auth.py
index e31482cfaa..a342a0e0da 100644
--- a/synapse/api/auth.py
+++ b/synapse/api/auth.py
@@ -21,6 +21,7 @@ from synapse.api.constants import EventTypes, Membership, JoinRules
from synapse.api.errors import AuthError, StoreError, Codes, SynapseError
from synapse.util.logutils import log_function
from synapse.util.async import run_on_reactor
+from synapse.types import UserID
import logging
@@ -104,7 +105,7 @@ class Auth(object):
for event in curr_state:
if event.type == EventTypes.Member:
try:
- if self.hs.parse_userid(event.state_key).domain != host:
+ if UserID.from_string(event.state_key).domain != host:
continue
except:
logger.warn("state_key not user_id: %s", event.state_key)
@@ -337,7 +338,7 @@ class Auth(object):
user_info = {
"admin": bool(ret.get("admin", False)),
"device_id": ret.get("device_id"),
- "user": self.hs.parse_userid(ret.get("name")),
+ "user": UserID.from_string(ret.get("name")),
}
defer.returnValue(user_info)
@@ -461,7 +462,7 @@ class Auth(object):
"You are not allowed to set others state"
)
else:
- sender_domain = self.hs.parse_userid(
+ sender_domain = UserID.from_string(
event.user_id
).domain
@@ -496,7 +497,7 @@ class Auth(object):
# Validate users
for k, v in user_list.items():
try:
- self.hs.parse_userid(k)
+ UserID.from_string(k)
except:
raise SynapseError(400, "Not a valid user_id: %s" % (k,))
diff --git a/synapse/api/urls.py b/synapse/api/urls.py
index a299392049..693c0efda6 100644
--- a/synapse/api/urls.py
+++ b/synapse/api/urls.py
@@ -16,6 +16,7 @@
"""Contains the URL paths to prefix various aspects of the server with. """
CLIENT_PREFIX = "/_matrix/client/api/v1"
+CLIENT_V2_ALPHA_PREFIX = "/_matrix/client/v2_alpha"
FEDERATION_PREFIX = "/_matrix/federation/v1"
WEB_CLIENT_PREFIX = "/_matrix/client"
CONTENT_REPO_PREFIX = "/_matrix/content"
diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py
index 6ebf1f0de0..f20ccfb5b6 100755
--- a/synapse/app/homeserver.py
+++ b/synapse/app/homeserver.py
@@ -32,11 +32,13 @@ from synapse.http.server_key_resource import LocalKey
from synapse.http.matrixfederationclient import MatrixFederationHttpClient
from synapse.api.urls import (
CLIENT_PREFIX, FEDERATION_PREFIX, WEB_CLIENT_PREFIX, CONTENT_REPO_PREFIX,
- SERVER_KEY_PREFIX, MEDIA_PREFIX
+ SERVER_KEY_PREFIX, MEDIA_PREFIX, CLIENT_V2_ALPHA_PREFIX,
)
from synapse.config.homeserver import HomeServerConfig
from synapse.crypto import context_factory
from synapse.util.logcontext import LoggingContext
+from synapse.rest.client.v1 import ClientV1RestResource
+from synapse.rest.client.v2_alpha import ClientV2AlphaRestResource
from daemonize import Daemonize
import twisted.manhole.telnet
@@ -59,7 +61,10 @@ class SynapseHomeServer(HomeServer):
return MatrixFederationHttpClient(self)
def build_resource_for_client(self):
- return JsonResource()
+ return ClientV1RestResource(self)
+
+ def build_resource_for_client_v2_alpha(self):
+ return ClientV2AlphaRestResource(self)
def build_resource_for_federation(self):
return JsonResource()
@@ -104,6 +109,7 @@ class SynapseHomeServer(HomeServer):
# [ ("/aaa/bbb/cc", Resource1), ("/aaa/dummy", Resource2) ]
desired_tree = [
(CLIENT_PREFIX, self.get_resource_for_client()),
+ (CLIENT_V2_ALPHA_PREFIX, self.get_resource_for_client_v2_alpha()),
(FEDERATION_PREFIX, self.get_resource_for_federation()),
(CONTENT_REPO_PREFIX, self.get_resource_for_content_repo()),
(SERVER_KEY_PREFIX, self.get_resource_for_server_key()),
@@ -224,8 +230,6 @@ def setup():
content_addr=config.content_addr,
)
- hs.register_servlets()
-
hs.create_resource_tree(
web_client=config.webclient,
redirect_root_to_web_client=True,
diff --git a/synapse/events/utils.py b/synapse/events/utils.py
index bcb5457278..e391aca4cc 100644
--- a/synapse/events/utils.py
+++ b/synapse/events/utils.py
@@ -89,31 +89,31 @@ def prune_event(event):
return type(event)(allowed_fields)
-def serialize_event(hs, e, client_event=True):
+def serialize_event(e, time_now_ms, client_event=True):
# FIXME(erikj): To handle the case of presence events and the like
if not isinstance(e, EventBase):
return e
+ time_now_ms = int(time_now_ms)
+
# 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"]
+ d["unsigned"]["age"] = time_now_ms - d["unsigned"]["age_ts"]
return d
if "age_ts" in d["unsigned"]:
- now = int(hs.get_clock().time_msec())
- d["age"] = now - d["unsigned"]["age_ts"]
+ d["age"] = time_now_ms - d["unsigned"]["age_ts"]
del d["unsigned"]["age_ts"]
d["user_id"] = d.pop("sender", None)
if "redacted_because" in e.unsigned:
d["redacted_because"] = serialize_event(
- hs, e.unsigned["redacted_because"]
+ e.unsigned["redacted_because"], time_now_ms
)
del d["unsigned"]["redacted_because"]
diff --git a/synapse/handlers/_base.py b/synapse/handlers/_base.py
index f33d17a31e..1773fa20aa 100644
--- a/synapse/handlers/_base.py
+++ b/synapse/handlers/_base.py
@@ -19,6 +19,7 @@ from synapse.api.errors import LimitExceededError, SynapseError
from synapse.util.async import run_on_reactor
from synapse.crypto.event_signing import add_hashes_and_signatures
from synapse.api.constants import Membership, EventTypes
+from synapse.types import UserID
import logging
@@ -113,7 +114,7 @@ class BaseHandler(object):
if event.type == EventTypes.Member:
if event.content["membership"] == Membership.INVITE:
- invitee = self.hs.parse_userid(event.state_key)
+ invitee = UserID.from_string(event.state_key)
if not self.hs.is_mine(invitee):
# TODO: Can we add signature from remote server in a nicer
# way? If we have been invited by a remote server, we need
@@ -134,7 +135,7 @@ class BaseHandler(object):
if k[0] == EventTypes.Member:
if s.content["membership"] == Membership.JOIN:
destinations.add(
- self.hs.parse_userid(s.state_key).domain
+ UserID.from_string(s.state_key).domain
)
except SynapseError:
logger.warn(
diff --git a/synapse/handlers/directory.py b/synapse/handlers/directory.py
index 91fceda2ac..58e9a91562 100644
--- a/synapse/handlers/directory.py
+++ b/synapse/handlers/directory.py
@@ -19,6 +19,7 @@ from ._base import BaseHandler
from synapse.api.errors import SynapseError, Codes, CodeMessageException
from synapse.api.constants import EventTypes
+from synapse.types import RoomAlias
import logging
@@ -122,7 +123,7 @@ class DirectoryHandler(BaseHandler):
@defer.inlineCallbacks
def on_directory_query(self, args):
- room_alias = self.hs.parse_roomalias(args["room_alias"])
+ room_alias = RoomAlias.from_string(args["room_alias"])
if not self.hs.is_mine(room_alias):
raise SynapseError(
400, "Room Alias is not hosted on this Home Server"
diff --git a/synapse/handlers/events.py b/synapse/handlers/events.py
index 52ef07eaae..025e7e7e62 100644
--- a/synapse/handlers/events.py
+++ b/synapse/handlers/events.py
@@ -17,6 +17,8 @@ from twisted.internet import defer
from synapse.util.logcontext import PreserveLoggingContext
from synapse.util.logutils import log_function
+from synapse.types import UserID
+from synapse.events.utils import serialize_event
from ._base import BaseHandler
@@ -48,7 +50,7 @@ class EventStreamHandler(BaseHandler):
@log_function
def get_stream(self, auth_user_id, pagin_config, timeout=0,
as_client_event=True, affect_presence=True):
- auth_user = self.hs.parse_userid(auth_user_id)
+ auth_user = UserID.from_string(auth_user_id)
try:
if affect_presence:
@@ -78,8 +80,10 @@ class EventStreamHandler(BaseHandler):
auth_user, room_ids, pagin_config, timeout
)
+ time_now = self.clock.time_msec()
+
chunks = [
- self.hs.serialize_event(e, as_client_event) for e in events
+ serialize_event(e, time_now, as_client_event) for e in events
]
chunk = {
diff --git a/synapse/handlers/federation.py b/synapse/handlers/federation.py
index 81203bf1a3..bcdcc90a18 100644
--- a/synapse/handlers/federation.py
+++ b/synapse/handlers/federation.py
@@ -28,6 +28,7 @@ from synapse.crypto.event_signing import (
compute_event_signature, check_event_content_hash,
add_hashes_and_signatures,
)
+from synapse.types import UserID
from syutil.jsonutil import encode_canonical_json
from twisted.internet import defer
@@ -227,7 +228,7 @@ class FederationHandler(BaseHandler):
extra_users = []
if event.type == EventTypes.Member:
target_user_id = event.state_key
- target_user = self.hs.parse_userid(target_user_id)
+ target_user = UserID.from_string(target_user_id)
extra_users.append(target_user)
yield self.notifier.on_new_room_event(
@@ -236,7 +237,7 @@ class FederationHandler(BaseHandler):
if event.type == EventTypes.Member:
if event.membership == Membership.JOIN:
- user = self.hs.parse_userid(event.state_key)
+ user = UserID.from_string(event.state_key)
yield self.distributor.fire(
"user_joined_room", user=user, room_id=event.room_id
)
@@ -491,7 +492,7 @@ class FederationHandler(BaseHandler):
extra_users = []
if event.type == EventTypes.Member:
target_user_id = event.state_key
- target_user = self.hs.parse_userid(target_user_id)
+ target_user = UserID.from_string(target_user_id)
extra_users.append(target_user)
yield self.notifier.on_new_room_event(
@@ -500,7 +501,7 @@ class FederationHandler(BaseHandler):
if event.type == EventTypes.Member:
if event.content["membership"] == Membership.JOIN:
- user = self.hs.parse_userid(event.state_key)
+ user = UserID.from_string(event.state_key)
yield self.distributor.fire(
"user_joined_room", user=user, room_id=event.room_id
)
@@ -514,7 +515,7 @@ class FederationHandler(BaseHandler):
if k[0] == EventTypes.Member:
if s.content["membership"] == Membership.JOIN:
destinations.add(
- self.hs.parse_userid(s.state_key).domain
+ UserID.from_string(s.state_key).domain
)
except:
logger.warn(
@@ -565,7 +566,7 @@ class FederationHandler(BaseHandler):
backfilled=False,
)
- target_user = self.hs.parse_userid(event.state_key)
+ target_user = UserID.from_string(event.state_key)
yield self.notifier.on_new_room_event(
event, extra_users=[target_user],
)
diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py
index f2a2f16933..9c3271fe88 100644
--- a/synapse/handlers/message.py
+++ b/synapse/handlers/message.py
@@ -18,8 +18,10 @@ from twisted.internet import defer
from synapse.api.constants import EventTypes, Membership
from synapse.api.errors import RoomError
from synapse.streams.config import PaginationConfig
+from synapse.events.utils import serialize_event
from synapse.events.validator import EventValidator
from synapse.util.logcontext import PreserveLoggingContext
+from synapse.types import UserID
from ._base import BaseHandler
@@ -89,7 +91,7 @@ class MessageHandler(BaseHandler):
yield self.hs.get_event_sources().get_current_token()
)
- user = self.hs.parse_userid(user_id)
+ user = UserID.from_string(user_id)
events, next_key = yield data_source.get_pagination_rows(
user, pagin_config.get_source_config("room"), room_id
@@ -99,9 +101,11 @@ class MessageHandler(BaseHandler):
"room_key", next_key
)
+ time_now = self.clock.time_msec()
+
chunk = {
"chunk": [
- self.hs.serialize_event(e, as_client_event) for e in events
+ serialize_event(e, time_now, as_client_event) for e in events
],
"start": pagin_config.from_token.to_string(),
"end": next_token.to_string(),
@@ -130,13 +134,13 @@ class MessageHandler(BaseHandler):
if ratelimit:
self.ratelimit(builder.user_id)
# TODO(paul): Why does 'event' not have a 'user' object?
- user = self.hs.parse_userid(builder.user_id)
+ user = UserID.from_string(builder.user_id)
assert self.hs.is_mine(user), "User must be our own: %s" % (user,)
if builder.type == EventTypes.Member:
membership = builder.content.get("membership", None)
if membership == Membership.JOIN:
- joinee = self.hs.parse_userid(builder.state_key)
+ joinee = UserID.from_string(builder.state_key)
# If event doesn't include a display name, add one.
yield self.distributor.fire(
"collect_presencelike_data",
@@ -210,7 +214,8 @@ class MessageHandler(BaseHandler):
# TODO: This is duplicating logic from snapshot_all_rooms
current_state = yield self.state_handler.get_current_state(room_id)
- defer.returnValue([self.hs.serialize_event(c) for c in current_state])
+ now = self.clock.time_msec()
+ defer.returnValue([serialize_event(c, now) for c in current_state])
@defer.inlineCallbacks
def snapshot_all_rooms(self, user_id=None, pagin_config=None,
@@ -237,7 +242,7 @@ class MessageHandler(BaseHandler):
membership_list=[Membership.INVITE, Membership.JOIN]
)
- user = self.hs.parse_userid(user_id)
+ user = UserID.from_string(user_id)
rooms_ret = []
@@ -282,10 +287,11 @@ class MessageHandler(BaseHandler):
start_token = now_token.copy_and_replace("room_key", token[0])
end_token = now_token.copy_and_replace("room_key", token[1])
+ time_now = self.clock.time_msec()
d["messages"] = {
"chunk": [
- self.hs.serialize_event(m, as_client_event)
+ serialize_event(m, time_now, as_client_event)
for m in messages
],
"start": start_token.to_string(),
@@ -296,7 +302,8 @@ class MessageHandler(BaseHandler):
event.room_id
)
d["state"] = [
- self.hs.serialize_event(c) for c in current_state
+ serialize_event(c, time_now, as_client_event)
+ for c in current_state
]
except:
logger.exception("Failed to get snapshot")
@@ -316,11 +323,12 @@ class MessageHandler(BaseHandler):
# TODO(paul): I wish I was called with user objects not user_id
# strings...
- auth_user = self.hs.parse_userid(user_id)
+ auth_user = UserID.from_string(user_id)
# TODO: These concurrently
+ time_now = self.clock.time_msec()
state_tuples = yield self.state_handler.get_current_state(room_id)
- state = [self.hs.serialize_event(x) for x in state_tuples]
+ state = [serialize_event(x, time_now) for x in state_tuples]
member_event = (yield self.store.get_room_member(
user_id=user_id,
@@ -349,7 +357,7 @@ class MessageHandler(BaseHandler):
for m in room_members:
try:
member_presence = yield presence_handler.get_state(
- target_user=self.hs.parse_userid(m.user_id),
+ target_user=UserID.from_string(m.user_id),
auth_user=auth_user,
as_event=True,
)
@@ -359,11 +367,13 @@ class MessageHandler(BaseHandler):
"Failed to get member presence of %r", m.user_id
)
+ time_now = self.clock.time_msec()
+
defer.returnValue({
"membership": member_event.membership,
"room_id": room_id,
"messages": {
- "chunk": [self.hs.serialize_event(m) for m in messages],
+ "chunk": [serialize_event(m, time_now) for m in messages],
"start": start_token.to_string(),
"end": end_token.to_string(),
},
diff --git a/synapse/handlers/presence.py b/synapse/handlers/presence.py
index 24d901b51f..cd0798c2b0 100644
--- a/synapse/handlers/presence.py
+++ b/synapse/handlers/presence.py
@@ -20,6 +20,7 @@ from synapse.api.constants import PresenceState
from synapse.util.logutils import log_function
from synapse.util.logcontext import PreserveLoggingContext
+from synapse.types import UserID
from ._base import BaseHandler
@@ -100,22 +101,22 @@ class PresenceHandler(BaseHandler):
self.federation.register_edu_handler(
"m.presence_invite",
lambda origin, content: self.invite_presence(
- observed_user=hs.parse_userid(content["observed_user"]),
- observer_user=hs.parse_userid(content["observer_user"]),
+ observed_user=UserID.from_string(content["observed_user"]),
+ observer_user=UserID.from_string(content["observer_user"]),
)
)
self.federation.register_edu_handler(
"m.presence_accept",
lambda origin, content: self.accept_presence(
- observed_user=hs.parse_userid(content["observed_user"]),
- observer_user=hs.parse_userid(content["observer_user"]),
+ observed_user=UserID.from_string(content["observed_user"]),
+ observer_user=UserID.from_string(content["observer_user"]),
)
)
self.federation.register_edu_handler(
"m.presence_deny",
lambda origin, content: self.deny_presence(
- observed_user=hs.parse_userid(content["observed_user"]),
- observer_user=hs.parse_userid(content["observer_user"]),
+ observed_user=UserID.from_string(content["observed_user"]),
+ observer_user=UserID.from_string(content["observer_user"]),
)
)
@@ -422,7 +423,7 @@ class PresenceHandler(BaseHandler):
)
for p in presence:
- observed_user = self.hs.parse_userid(p.pop("observed_user_id"))
+ observed_user = UserID.from_string(p.pop("observed_user_id"))
p["observed_user"] = observed_user
p.update(self._get_or_offline_usercache(observed_user).get_state())
if "last_active" in p:
@@ -445,7 +446,7 @@ class PresenceHandler(BaseHandler):
user.localpart, accepted=True
)
target_users = set([
- self.hs.parse_userid(x["observed_user_id"]) for x in presence
+ UserID.from_string(x["observed_user_id"]) for x in presence
])
# Also include people in all my rooms
@@ -651,7 +652,7 @@ class PresenceHandler(BaseHandler):
deferreds = []
for push in content.get("push", []):
- user = self.hs.parse_userid(push["user_id"])
+ user = UserID.from_string(push["user_id"])
logger.debug("Incoming presence update from %s", user)
@@ -699,7 +700,7 @@ class PresenceHandler(BaseHandler):
del self._user_cachemap[user]
for poll in content.get("poll", []):
- user = self.hs.parse_userid(poll)
+ user = UserID.from_string(poll)
if not self.hs.is_mine(user):
continue
@@ -714,7 +715,7 @@ class PresenceHandler(BaseHandler):
deferreds.append(self._push_presence_remote(user, origin))
for unpoll in content.get("unpoll", []):
- user = self.hs.parse_userid(unpoll)
+ user = UserID.from_string(unpoll)
if not self.hs.is_mine(user):
continue
diff --git a/synapse/handlers/profile.py b/synapse/handlers/profile.py
index 7777d3cc94..03b2159c53 100644
--- a/synapse/handlers/profile.py
+++ b/synapse/handlers/profile.py
@@ -18,6 +18,7 @@ from twisted.internet import defer
from synapse.api.errors import SynapseError, AuthError, CodeMessageException
from synapse.api.constants import EventTypes, Membership
from synapse.util.logcontext import PreserveLoggingContext
+from synapse.types import UserID
from ._base import BaseHandler
@@ -169,7 +170,7 @@ class ProfileHandler(BaseHandler):
@defer.inlineCallbacks
def on_profile_query(self, args):
- user = self.hs.parse_userid(args["user_id"])
+ user = UserID.from_string(args["user_id"])
if not self.hs.is_mine(user):
raise SynapseError(400, "User is not hosted on this Home Server")
diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py
index 6d0db18e51..23821d321f 100644
--- a/synapse/handlers/room.py
+++ b/synapse/handlers/room.py
@@ -16,12 +16,14 @@
"""Contains functions for performing events on rooms."""
from twisted.internet import defer
+from ._base import BaseHandler
+
from synapse.types import UserID, RoomAlias, RoomID
from synapse.api.constants import EventTypes, Membership, JoinRules
from synapse.api.errors import StoreError, SynapseError
from synapse.util import stringutils
from synapse.util.async import run_on_reactor
-from ._base import BaseHandler
+from synapse.events.utils import serialize_event
import logging
@@ -64,7 +66,7 @@ class RoomCreationHandler(BaseHandler):
invite_list = config.get("invite", [])
for i in invite_list:
try:
- self.hs.parse_userid(i)
+ UserID.from_string(i)
except:
raise SynapseError(400, "Invalid user_id: %s" % (i,))
@@ -114,7 +116,7 @@ class RoomCreationHandler(BaseHandler):
servers=[self.hs.hostname],
)
- user = self.hs.parse_userid(user_id)
+ user = UserID.from_string(user_id)
creation_events = self._create_events_for_new_room(
user, room_id, is_public=is_public
)
@@ -246,11 +248,9 @@ class RoomMemberHandler(BaseHandler):
@defer.inlineCallbacks
def get_room_members(self, room_id):
- hs = self.hs
-
users = yield self.store.get_users_in_room(room_id)
- defer.returnValue([hs.parse_userid(u) for u in users])
+ defer.returnValue([UserID.from_string(u) for u in users])
@defer.inlineCallbacks
def fetch_room_distributions_into(self, room_id, localusers=None,
@@ -295,8 +295,9 @@ class RoomMemberHandler(BaseHandler):
yield self.auth.check_joined_room(room_id, user_id)
member_list = yield self.store.get_room_members(room_id=room_id)
+ time_now = self.clock.time_msec()
event_list = [
- self.hs.serialize_event(entry)
+ serialize_event(entry, time_now)
for entry in member_list
]
chunk_data = {
@@ -368,7 +369,7 @@ class RoomMemberHandler(BaseHandler):
)
if prev_state and prev_state.membership == Membership.JOIN:
- user = self.hs.parse_userid(event.user_id)
+ user = UserID.from_string(event.user_id)
self.distributor.fire(
"user_left_room", user=user, room_id=event.room_id
)
@@ -412,7 +413,7 @@ class RoomMemberHandler(BaseHandler):
@defer.inlineCallbacks
def _do_join(self, event, context, room_host=None, do_auth=True):
- joinee = self.hs.parse_userid(event.state_key)
+ joinee = UserID.from_string(event.state_key)
# room_id = RoomID.from_string(event.room_id, self.hs)
room_id = event.room_id
@@ -476,7 +477,7 @@ class RoomMemberHandler(BaseHandler):
do_auth=do_auth,
)
- user = self.hs.parse_userid(event.user_id)
+ user = UserID.from_string(event.user_id)
yield self.distributor.fire(
"user_joined_room", user=user, room_id=room_id
)
@@ -526,7 +527,7 @@ class RoomMemberHandler(BaseHandler):
do_auth):
yield run_on_reactor()
- target_user = self.hs.parse_userid(event.state_key)
+ target_user = UserID.from_string(event.state_key)
yield self.handle_new_client_event(
event,
diff --git a/synapse/handlers/typing.py b/synapse/handlers/typing.py
index cd9638dd04..c69787005f 100644
--- a/synapse/handlers/typing.py
+++ b/synapse/handlers/typing.py
@@ -18,6 +18,7 @@ from twisted.internet import defer
from ._base import BaseHandler
from synapse.api.errors import SynapseError, AuthError
+from synapse.types import UserID
import logging
@@ -185,7 +186,7 @@ class TypingNotificationHandler(BaseHandler):
@defer.inlineCallbacks
def _recv_edu(self, origin, content):
room_id = content["room_id"]
- user = self.homeserver.parse_userid(content["user_id"])
+ user = UserID.from_string(content["user_id"])
localusers = set()
diff --git a/synapse/http/servlet.py b/synapse/http/servlet.py
new file mode 100644
index 0000000000..a4eb6c817c
--- /dev/null
+++ b/synapse/http/servlet.py
@@ -0,0 +1,113 @@
+# -*- 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.
+
+""" This module contains base REST classes for constructing REST servlets. """
+
+from synapse.api.errors import SynapseError
+
+import logging
+
+
+logger = logging.getLogger(__name__)
+
+
+class RestServlet(object):
+
+ """ A Synapse REST Servlet.
+
+ An implementing class can either provide its own custom 'register' method,
+ or use the automatic pattern handling provided by the base class.
+
+ To use this latter, the implementing class instead provides a `PATTERN`
+ class attribute containing a pre-compiled regular expression. The automatic
+ register method will then use this method to register any of the following
+ instance methods associated with the corresponding HTTP method:
+
+ on_GET
+ on_PUT
+ on_POST
+ on_DELETE
+ on_OPTIONS
+
+ Automatically handles turning CodeMessageExceptions thrown by these methods
+ into the appropriate HTTP response.
+ """
+
+ def register(self, http_server):
+ """ Register this servlet with the given HTTP server. """
+ if hasattr(self, "PATTERN"):
+ pattern = self.PATTERN
+
+ for method in ("GET", "PUT", "POST", "OPTIONS", "DELETE"):
+ if hasattr(self, "on_%s" % (method)):
+ method_handler = getattr(self, "on_%s" % (method))
+ http_server.register_path(method, pattern, method_handler)
+ else:
+ raise NotImplementedError("RestServlet must register something.")
+
+ @staticmethod
+ def parse_integer(request, name, default=None, required=False):
+ if name in request.args:
+ try:
+ return int(request.args[name][0])
+ except:
+ message = "Query parameter %r must be an integer" % (name,)
+ raise SynapseError(400, message)
+ else:
+ if required:
+ message = "Missing integer query parameter %r" % (name,)
+ raise SynapseError(400, message)
+ else:
+ return default
+
+ @staticmethod
+ def parse_boolean(request, name, default=None, required=False):
+ if name in request.args:
+ try:
+ return {
+ "true": True,
+ "false": False,
+ }[request.args[name][0]]
+ except:
+ message = (
+ "Boolean query parameter %r must be one of"
+ " ['true', 'false']"
+ ) % (name,)
+ raise SynapseError(400, message)
+ else:
+ if required:
+ message = "Missing boolean query parameter %r" % (name,)
+ raise SynapseError(400, message)
+ else:
+ return default
+
+ @staticmethod
+ def parse_string(request, name, default=None, required=False,
+ allowed_values=None, param_type="string"):
+ if name in request.args:
+ value = request.args[name][0]
+ if allowed_values is not None and value not in allowed_values:
+ message = "Query parameter %r must be one of [%s]" % (
+ name, ", ".join(repr(v) for v in allowed_values)
+ )
+ raise SynapseError(message)
+ else:
+ return value
+ else:
+ if required:
+ message = "Missing %s query parameter %r" % (param_type, name)
+ raise SynapseError(400, message)
+ else:
+ return default
diff --git a/synapse/python_dependencies.py b/synapse/python_dependencies.py
index b1fae991e0..4182ad990f 100644
--- a/synapse/python_dependencies.py
+++ b/synapse/python_dependencies.py
@@ -5,7 +5,7 @@ logger = logging.getLogger(__name__)
REQUIREMENTS = {
"syutil==0.0.2": ["syutil"],
- "matrix_angular_sdk==0.6.0": ["syweb==0.6.0"],
+ "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"],
diff --git a/synapse/rest/client/v1/__init__.py b/synapse/rest/client/v1/__init__.py
index 8e5877cf3f..96a9a474f1 100644
--- a/synapse/rest/client/v1/__init__.py
+++ b/synapse/rest/client/v1/__init__.py
@@ -19,22 +19,18 @@ from . import (
voip, admin, pusher, push_rule
)
+from synapse.http.server import JsonResource
-class RestServletFactory(object):
- """ A factory for creating REST servlets.
-
- These REST servlets represent the entire client-server REST API. Generally
- speaking, they serve as wrappers around events and the handlers that
- process them.
-
- See synapse.events for information on synapse events.
- """
+class ClientV1RestResource(JsonResource):
+ """A resource for version 1 of the matrix client API."""
def __init__(self, hs):
- client_resource = hs.get_resource_for_client()
+ JsonResource.__init__(self)
+ self.register_servlets(self, hs)
- # TODO(erikj): There *must* be a better way of doing this.
+ @staticmethod
+ def register_servlets(client_resource, hs):
room.register_servlets(hs, client_resource)
events.register_servlets(hs, client_resource)
register.register_servlets(hs, client_resource)
diff --git a/synapse/rest/client/v1/admin.py b/synapse/rest/client/v1/admin.py
index 0aa83514c8..1051d96f96 100644
--- a/synapse/rest/client/v1/admin.py
+++ b/synapse/rest/client/v1/admin.py
@@ -16,19 +16,21 @@
from twisted.internet import defer
from synapse.api.errors import AuthError, SynapseError
-from base import RestServlet, client_path_pattern
+from synapse.types import UserID
+
+from base import ClientV1RestServlet, client_path_pattern
import logging
logger = logging.getLogger(__name__)
-class WhoisRestServlet(RestServlet):
+class WhoisRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/admin/whois/(?P<user_id>[^/]*)")
@defer.inlineCallbacks
def on_GET(self, request, user_id):
- target_user = self.hs.parse_userid(user_id)
+ target_user = UserID.from_string(user_id)
auth_user = yield self.auth.get_user_by_req(request)
is_admin = yield self.auth.is_server_admin(auth_user)
diff --git a/synapse/rest/client/v1/base.py b/synapse/rest/client/v1/base.py
index d005206b77..72332bdb10 100644
--- a/synapse/rest/client/v1/base.py
+++ b/synapse/rest/client/v1/base.py
@@ -13,7 +13,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-""" This module contains base REST classes for constructing REST servlets. """
+"""This module contains base REST classes for constructing client v1 servlets.
+"""
+
+from synapse.http.servlet import RestServlet
from synapse.api.urls import CLIENT_PREFIX
from .transactions import HttpTransactionStore
import re
@@ -37,44 +40,13 @@ def client_path_pattern(path_regex):
return re.compile("^" + CLIENT_PREFIX + path_regex)
-class RestServlet(object):
-
- """ A Synapse REST Servlet.
-
- An implementing class can either provide its own custom 'register' method,
- or use the automatic pattern handling provided by the base class.
-
- To use this latter, the implementing class instead provides a `PATTERN`
- class attribute containing a pre-compiled regular expression. The automatic
- register method will then use this method to register any of the following
- instance methods associated with the corresponding HTTP method:
-
- on_GET
- on_PUT
- on_POST
- on_DELETE
- on_OPTIONS
-
- Automatically handles turning CodeMessageExceptions thrown by these methods
- into the appropriate HTTP response.
+class ClientV1RestServlet(RestServlet):
+ """A base Synapse REST Servlet for the client version 1 API.
"""
def __init__(self, hs):
self.hs = hs
-
self.handlers = hs.get_handlers()
self.builder_factory = hs.get_event_builder_factory()
self.auth = hs.get_auth()
self.txns = HttpTransactionStore()
-
- def register(self, http_server):
- """ Register this servlet with the given HTTP server. """
- if hasattr(self, "PATTERN"):
- pattern = self.PATTERN
-
- for method in ("GET", "PUT", "POST", "OPTIONS", "DELETE"):
- if hasattr(self, "on_%s" % (method)):
- method_handler = getattr(self, "on_%s" % (method))
- http_server.register_path(method, pattern, method_handler)
- else:
- raise NotImplementedError("RestServlet must register something.")
diff --git a/synapse/rest/client/v1/directory.py b/synapse/rest/client/v1/directory.py
index 7ff44fdd9e..15ae8749b8 100644
--- a/synapse/rest/client/v1/directory.py
+++ b/synapse/rest/client/v1/directory.py
@@ -17,7 +17,8 @@
from twisted.internet import defer
from synapse.api.errors import AuthError, SynapseError, Codes
-from base import RestServlet, client_path_pattern
+from synapse.types import RoomAlias
+from .base import ClientV1RestServlet, client_path_pattern
import json
import logging
@@ -30,12 +31,12 @@ def register_servlets(hs, http_server):
ClientDirectoryServer(hs).register(http_server)
-class ClientDirectoryServer(RestServlet):
+class ClientDirectoryServer(ClientV1RestServlet):
PATTERN = client_path_pattern("/directory/room/(?P<room_alias>[^/]*)$")
@defer.inlineCallbacks
def on_GET(self, request, room_alias):
- room_alias = self.hs.parse_roomalias(room_alias)
+ room_alias = RoomAlias.from_string(room_alias)
dir_handler = self.handlers.directory_handler
res = yield dir_handler.get_association(room_alias)
@@ -53,7 +54,7 @@ class ClientDirectoryServer(RestServlet):
logger.debug("Got content: %s", content)
- room_alias = self.hs.parse_roomalias(room_alias)
+ room_alias = RoomAlias.from_string(room_alias)
logger.debug("Got room name: %s", room_alias.to_string())
@@ -92,7 +93,7 @@ class ClientDirectoryServer(RestServlet):
dir_handler = self.handlers.directory_handler
- room_alias = self.hs.parse_roomalias(room_alias)
+ room_alias = RoomAlias.from_string(room_alias)
yield dir_handler.delete_association(
user.to_string(), room_alias
diff --git a/synapse/rest/client/v1/events.py b/synapse/rest/client/v1/events.py
index c2515528ac..a0d051227b 100644
--- a/synapse/rest/client/v1/events.py
+++ b/synapse/rest/client/v1/events.py
@@ -18,7 +18,8 @@ from twisted.internet import defer
from synapse.api.errors import SynapseError
from synapse.streams.config import PaginationConfig
-from .base import RestServlet, client_path_pattern
+from .base import ClientV1RestServlet, client_path_pattern
+from synapse.events.utils import serialize_event
import logging
@@ -26,7 +27,7 @@ import logging
logger = logging.getLogger(__name__)
-class EventStreamRestServlet(RestServlet):
+class EventStreamRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/events$")
DEFAULT_LONGPOLL_TIME_MS = 30000
@@ -61,17 +62,22 @@ class EventStreamRestServlet(RestServlet):
# TODO: Unit test gets, with and without auth, with different kinds of events.
-class EventRestServlet(RestServlet):
+class EventRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/events/(?P<event_id>[^/]*)$")
+ def __init__(self, hs):
+ super(EventRestServlet, self).__init__(hs)
+ self.clock = hs.get_clock()
+
@defer.inlineCallbacks
def on_GET(self, request, event_id):
auth_user = yield self.auth.get_user_by_req(request)
handler = self.handlers.event_handler
event = yield handler.get_event(auth_user, event_id)
+ time_now = self.clock.time_msec()
if event:
- defer.returnValue((200, self.hs.serialize_event(event)))
+ defer.returnValue((200, serialize_event(event, time_now)))
else:
defer.returnValue((404, "Event not found."))
diff --git a/synapse/rest/client/v1/initial_sync.py b/synapse/rest/client/v1/initial_sync.py
index b13d56b286..357fa845b4 100644
--- a/synapse/rest/client/v1/initial_sync.py
+++ b/synapse/rest/client/v1/initial_sync.py
@@ -16,11 +16,11 @@
from twisted.internet import defer
from synapse.streams.config import PaginationConfig
-from base import RestServlet, client_path_pattern
+from base import ClientV1RestServlet, client_path_pattern
# TODO: Needs unit testing
-class InitialSyncRestServlet(RestServlet):
+class InitialSyncRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/initialSync$")
@defer.inlineCallbacks
diff --git a/synapse/rest/client/v1/login.py b/synapse/rest/client/v1/login.py
index 6b8deff67b..7116ac98e8 100644
--- a/synapse/rest/client/v1/login.py
+++ b/synapse/rest/client/v1/login.py
@@ -17,12 +17,12 @@ from twisted.internet import defer
from synapse.api.errors import SynapseError
from synapse.types import UserID
-from base import RestServlet, client_path_pattern
+from base import ClientV1RestServlet, client_path_pattern
import json
-class LoginRestServlet(RestServlet):
+class LoginRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/login$")
PASS_TYPE = "m.login.password"
@@ -64,7 +64,7 @@ class LoginRestServlet(RestServlet):
defer.returnValue((200, result))
-class LoginFallbackRestServlet(RestServlet):
+class LoginFallbackRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/login/fallback$")
def on_GET(self, request):
@@ -73,7 +73,7 @@ class LoginFallbackRestServlet(RestServlet):
return (200, {})
-class PasswordResetRestServlet(RestServlet):
+class PasswordResetRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/login/reset")
@defer.inlineCallbacks
diff --git a/synapse/rest/client/v1/presence.py b/synapse/rest/client/v1/presence.py
index ca4d2d21f0..b6c207e662 100644
--- a/synapse/rest/client/v1/presence.py
+++ b/synapse/rest/client/v1/presence.py
@@ -18,7 +18,8 @@
from twisted.internet import defer
from synapse.api.errors import SynapseError
-from base import RestServlet, client_path_pattern
+from synapse.types import UserID
+from .base import ClientV1RestServlet, client_path_pattern
import json
import logging
@@ -26,13 +27,13 @@ import logging
logger = logging.getLogger(__name__)
-class PresenceStatusRestServlet(RestServlet):
+class PresenceStatusRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/presence/(?P<user_id>[^/]*)/status")
@defer.inlineCallbacks
def on_GET(self, request, user_id):
auth_user = yield self.auth.get_user_by_req(request)
- user = self.hs.parse_userid(user_id)
+ user = UserID.from_string(user_id)
state = yield self.handlers.presence_handler.get_state(
target_user=user, auth_user=auth_user)
@@ -42,7 +43,7 @@ class PresenceStatusRestServlet(RestServlet):
@defer.inlineCallbacks
def on_PUT(self, request, user_id):
auth_user = yield self.auth.get_user_by_req(request)
- user = self.hs.parse_userid(user_id)
+ user = UserID.from_string(user_id)
state = {}
try:
@@ -71,13 +72,13 @@ class PresenceStatusRestServlet(RestServlet):
return (200, {})
-class PresenceListRestServlet(RestServlet):
+class PresenceListRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/presence/list/(?P<user_id>[^/]*)")
@defer.inlineCallbacks
def on_GET(self, request, user_id):
auth_user = yield self.auth.get_user_by_req(request)
- user = self.hs.parse_userid(user_id)
+ user = UserID.from_string(user_id)
if not self.hs.is_mine(user):
raise SynapseError(400, "User not hosted on this Home Server")
@@ -97,7 +98,7 @@ class PresenceListRestServlet(RestServlet):
@defer.inlineCallbacks
def on_POST(self, request, user_id):
auth_user = yield self.auth.get_user_by_req(request)
- user = self.hs.parse_userid(user_id)
+ user = UserID.from_string(user_id)
if not self.hs.is_mine(user):
raise SynapseError(400, "User not hosted on this Home Server")
@@ -118,7 +119,7 @@ class PresenceListRestServlet(RestServlet):
raise SynapseError(400, "Bad invite value.")
if len(u) == 0:
continue
- invited_user = self.hs.parse_userid(u)
+ invited_user = UserID.from_string(u)
yield self.handlers.presence_handler.send_invite(
observer_user=user, observed_user=invited_user
)
@@ -129,7 +130,7 @@ class PresenceListRestServlet(RestServlet):
raise SynapseError(400, "Bad drop value.")
if len(u) == 0:
continue
- dropped_user = self.hs.parse_userid(u)
+ dropped_user = UserID.from_string(u)
yield self.handlers.presence_handler.drop(
observer_user=user, observed_user=dropped_user
)
diff --git a/synapse/rest/client/v1/profile.py b/synapse/rest/client/v1/profile.py
index dc6eb424b0..24f8d56952 100644
--- a/synapse/rest/client/v1/profile.py
+++ b/synapse/rest/client/v1/profile.py
@@ -16,17 +16,18 @@
""" This module contains REST servlets to do with profile: /profile/<paths> """
from twisted.internet import defer
-from base import RestServlet, client_path_pattern
+from .base import ClientV1RestServlet, client_path_pattern
+from synapse.types import UserID
import json
-class ProfileDisplaynameRestServlet(RestServlet):
+class ProfileDisplaynameRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/profile/(?P<user_id>[^/]*)/displayname")
@defer.inlineCallbacks
def on_GET(self, request, user_id):
- user = self.hs.parse_userid(user_id)
+ user = UserID.from_string(user_id)
displayname = yield self.handlers.profile_handler.get_displayname(
user,
@@ -37,7 +38,7 @@ class ProfileDisplaynameRestServlet(RestServlet):
@defer.inlineCallbacks
def on_PUT(self, request, user_id):
auth_user = yield self.auth.get_user_by_req(request)
- user = self.hs.parse_userid(user_id)
+ user = UserID.from_string(user_id)
try:
content = json.loads(request.content.read())
@@ -54,12 +55,12 @@ class ProfileDisplaynameRestServlet(RestServlet):
return (200, {})
-class ProfileAvatarURLRestServlet(RestServlet):
+class ProfileAvatarURLRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/profile/(?P<user_id>[^/]*)/avatar_url")
@defer.inlineCallbacks
def on_GET(self, request, user_id):
- user = self.hs.parse_userid(user_id)
+ user = UserID.from_string(user_id)
avatar_url = yield self.handlers.profile_handler.get_avatar_url(
user,
@@ -70,7 +71,7 @@ class ProfileAvatarURLRestServlet(RestServlet):
@defer.inlineCallbacks
def on_PUT(self, request, user_id):
auth_user = yield self.auth.get_user_by_req(request)
- user = self.hs.parse_userid(user_id)
+ user = UserID.from_string(user_id)
try:
content = json.loads(request.content.read())
@@ -87,12 +88,12 @@ class ProfileAvatarURLRestServlet(RestServlet):
return (200, {})
-class ProfileRestServlet(RestServlet):
+class ProfileRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/profile/(?P<user_id>[^/]*)")
@defer.inlineCallbacks
def on_GET(self, request, user_id):
- user = self.hs.parse_userid(user_id)
+ user = UserID.from_string(user_id)
displayname = yield self.handlers.profile_handler.get_displayname(
user,
diff --git a/synapse/rest/client/v1/register.py b/synapse/rest/client/v1/register.py
index e3b26902d9..c0423c2d45 100644
--- a/synapse/rest/client/v1/register.py
+++ b/synapse/rest/client/v1/register.py
@@ -18,7 +18,7 @@ from twisted.internet import defer
from synapse.api.errors import SynapseError, Codes
from synapse.api.constants import LoginType
-from base import RestServlet, client_path_pattern
+from base import ClientV1RestServlet, client_path_pattern
import synapse.util.stringutils as stringutils
from synapse.util.async import run_on_reactor
@@ -42,7 +42,7 @@ else:
compare_digest = lambda a, b: a == b
-class RegisterRestServlet(RestServlet):
+class RegisterRestServlet(ClientV1RestServlet):
"""Handles registration with the home server.
This servlet is in control of the registration flow; the registration
diff --git a/synapse/rest/client/v1/room.py b/synapse/rest/client/v1/room.py
index 48bba2a5f3..58b09b6fc1 100644
--- a/synapse/rest/client/v1/room.py
+++ b/synapse/rest/client/v1/room.py
@@ -16,10 +16,12 @@
""" This module contains REST servlets to do with rooms: /rooms/<paths> """
from twisted.internet import defer
-from base import RestServlet, client_path_pattern
+from base import ClientV1RestServlet, client_path_pattern
from synapse.api.errors import SynapseError, Codes
from synapse.streams.config import PaginationConfig
from synapse.api.constants import EventTypes, Membership
+from synapse.types import UserID, RoomID, RoomAlias
+from synapse.events.utils import serialize_event
import json
import logging
@@ -29,7 +31,7 @@ import urllib
logger = logging.getLogger(__name__)
-class RoomCreateRestServlet(RestServlet):
+class RoomCreateRestServlet(ClientV1RestServlet):
# No PATTERN; we have custom dispatch rules here
def register(self, http_server):
@@ -93,7 +95,7 @@ class RoomCreateRestServlet(RestServlet):
# TODO: Needs unit testing for generic events
-class RoomStateEventRestServlet(RestServlet):
+class RoomStateEventRestServlet(ClientV1RestServlet):
def register(self, http_server):
# /room/$roomid/state/$eventtype
no_state_key = "/rooms/(?P<room_id>[^/]*)/state/(?P<event_type>[^/]*)$"
@@ -162,7 +164,7 @@ class RoomStateEventRestServlet(RestServlet):
# TODO: Needs unit testing for generic events + feedback
-class RoomSendEventRestServlet(RestServlet):
+class RoomSendEventRestServlet(ClientV1RestServlet):
def register(self, http_server):
# /rooms/$roomid/send/$event_type[/$txn_id]
@@ -205,7 +207,7 @@ class RoomSendEventRestServlet(RestServlet):
# TODO: Needs unit testing for room ID + alias joins
-class JoinRoomAliasServlet(RestServlet):
+class JoinRoomAliasServlet(ClientV1RestServlet):
def register(self, http_server):
# /join/$room_identifier[/$txn_id]
@@ -223,10 +225,10 @@ class JoinRoomAliasServlet(RestServlet):
identifier = None
is_room_alias = False
try:
- identifier = self.hs.parse_roomalias(room_identifier)
+ identifier = RoomAlias.from_string(room_identifier)
is_room_alias = True
except SynapseError:
- identifier = self.hs.parse_roomid(room_identifier)
+ identifier = RoomID.from_string(room_identifier)
# TODO: Support for specifying the home server to join with?
@@ -264,7 +266,7 @@ class JoinRoomAliasServlet(RestServlet):
# TODO: Needs unit testing
-class PublicRoomListRestServlet(RestServlet):
+class PublicRoomListRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/publicRooms$")
@defer.inlineCallbacks
@@ -275,7 +277,7 @@ class PublicRoomListRestServlet(RestServlet):
# TODO: Needs unit testing
-class RoomMemberListRestServlet(RestServlet):
+class RoomMemberListRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/rooms/(?P<room_id>[^/]*)/members$")
@defer.inlineCallbacks
@@ -289,7 +291,7 @@ class RoomMemberListRestServlet(RestServlet):
for event in members["chunk"]:
# FIXME: should probably be state_key here, not user_id
- target_user = self.hs.parse_userid(event["user_id"])
+ target_user = UserID.from_string(event["user_id"])
# Presence is an optional cache; don't fail if we can't fetch it
try:
presence_handler = self.handlers.presence_handler
@@ -304,7 +306,7 @@ class RoomMemberListRestServlet(RestServlet):
# TODO: Needs unit testing
-class RoomMessageListRestServlet(RestServlet):
+class RoomMessageListRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/rooms/(?P<room_id>[^/]*)/messages$")
@defer.inlineCallbacks
@@ -328,7 +330,7 @@ class RoomMessageListRestServlet(RestServlet):
# TODO: Needs unit testing
-class RoomStateRestServlet(RestServlet):
+class RoomStateRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/rooms/(?P<room_id>[^/]*)/state$")
@defer.inlineCallbacks
@@ -344,7 +346,7 @@ class RoomStateRestServlet(RestServlet):
# TODO: Needs unit testing
-class RoomInitialSyncRestServlet(RestServlet):
+class RoomInitialSyncRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/rooms/(?P<room_id>[^/]*)/initialSync$")
@defer.inlineCallbacks
@@ -359,9 +361,13 @@ class RoomInitialSyncRestServlet(RestServlet):
defer.returnValue((200, content))
-class RoomTriggerBackfill(RestServlet):
+class RoomTriggerBackfill(ClientV1RestServlet):
PATTERN = client_path_pattern("/rooms/(?P<room_id>[^/]*)/backfill$")
+ def __init__(self, hs):
+ super(RoomTriggerBackfill, self).__init__(hs)
+ self.clock = hs.get_clock()
+
@defer.inlineCallbacks
def on_GET(self, request, room_id):
remote_server = urllib.unquote(
@@ -373,12 +379,14 @@ class RoomTriggerBackfill(RestServlet):
handler = self.handlers.federation_handler
events = yield handler.backfill(remote_server, room_id, limit)
- res = [self.hs.serialize_event(event) for event in events]
+ time_now = self.clock.time_msec()
+
+ res = [serialize_event(event, time_now) for event in events]
defer.returnValue((200, res))
# TODO: Needs unit testing
-class RoomMembershipRestServlet(RestServlet):
+class RoomMembershipRestServlet(ClientV1RestServlet):
def register(self, http_server):
# /rooms/$roomid/[invite|join|leave]
@@ -430,7 +438,7 @@ class RoomMembershipRestServlet(RestServlet):
defer.returnValue(response)
-class RoomRedactEventRestServlet(RestServlet):
+class RoomRedactEventRestServlet(ClientV1RestServlet):
def register(self, http_server):
PATTERN = ("/rooms/(?P<room_id>[^/]*)/redact/(?P<event_id>[^/]*)")
register_txn_path(self, PATTERN, http_server)
@@ -468,7 +476,7 @@ class RoomRedactEventRestServlet(RestServlet):
defer.returnValue(response)
-class RoomTypingRestServlet(RestServlet):
+class RoomTypingRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern(
"/rooms/(?P<room_id>[^/]*)/typing/(?P<user_id>[^/]*)$"
)
@@ -478,7 +486,7 @@ class RoomTypingRestServlet(RestServlet):
auth_user = yield self.auth.get_user_by_req(request)
room_id = urllib.unquote(room_id)
- target_user = self.hs.parse_userid(urllib.unquote(user_id))
+ target_user = UserID.from_string(urllib.unquote(user_id))
content = _parse_json(request)
diff --git a/synapse/rest/client/v1/voip.py b/synapse/rest/client/v1/voip.py
index 011c35e69b..822d863ce6 100644
--- a/synapse/rest/client/v1/voip.py
+++ b/synapse/rest/client/v1/voip.py
@@ -15,7 +15,7 @@
from twisted.internet import defer
-from base import RestServlet, client_path_pattern
+from base import ClientV1RestServlet, client_path_pattern
import hmac
@@ -23,7 +23,7 @@ import hashlib
import base64
-class VoipRestServlet(RestServlet):
+class VoipRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/voip/turnServer$")
@defer.inlineCallbacks
diff --git a/synapse/rest/client/v2_alpha/__init__.py b/synapse/rest/client/v2_alpha/__init__.py
new file mode 100644
index 0000000000..bb740e2803
--- /dev/null
+++ b/synapse/rest/client/v2_alpha/__init__.py
@@ -0,0 +1,29 @@
+# -*- 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 synapse.http.server import JsonResource
+
+
+class ClientV2AlphaRestResource(JsonResource):
+ """A resource for version 2 alpha of the matrix client API."""
+
+ def __init__(self, hs):
+ JsonResource.__init__(self)
+ self.register_servlets(self, hs)
+
+ @staticmethod
+ def register_servlets(client_resource, hs):
+ pass
diff --git a/synapse/rest/client/v2_alpha/_base.py b/synapse/rest/client/v2_alpha/_base.py
new file mode 100644
index 0000000000..22dc5cb862
--- /dev/null
+++ b/synapse/rest/client/v2_alpha/_base.py
@@ -0,0 +1,38 @@
+# -*- 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.
+
+"""This module contains base REST classes for constructing client v1 servlets.
+"""
+
+from synapse.api.urls import CLIENT_V2_ALPHA_PREFIX
+import re
+
+import logging
+
+
+logger = logging.getLogger(__name__)
+
+
+def client_v2_pattern(path_regex):
+ """Creates a regex compiled client path with the correct client path
+ prefix.
+
+ Args:
+ path_regex (str): The regex string to match. This should NOT have a ^
+ as this will be prefixed.
+ Returns:
+ SRE_Pattern
+ """
+ return re.compile("^" + CLIENT_V2_ALPHA_PREFIX + path_regex)
diff --git a/synapse/server.py b/synapse/server.py
index 8e739716ad..f152f0321e 100644
--- a/synapse/server.py
+++ b/synapse/server.py
@@ -20,14 +20,11 @@
# Imports required for the default HomeServer() implementation
from synapse.federation import initialize_http_replication
-from synapse.events.utils import serialize_event
from synapse.notifier import Notifier
from synapse.api.auth import Auth
from synapse.handlers import Handlers
-from synapse.rest.client.v1 import RestServletFactory
from synapse.state import StateHandler
from synapse.storage import DataStore
-from synapse.types import UserID, RoomAlias, RoomID, EventID
from synapse.util import Clock
from synapse.util.distributor import Distributor
from synapse.util.lockutils import LockManager
@@ -73,6 +70,7 @@ class BaseHomeServer(object):
'notifier',
'distributor',
'resource_for_client',
+ 'resource_for_client_v2_alpha',
'resource_for_federation',
'resource_for_web_client',
'resource_for_content_repo',
@@ -127,33 +125,6 @@ class BaseHomeServer(object):
setattr(BaseHomeServer, "get_%s" % (depname), _get)
- # TODO: Why are these parse_ methods so high up along with other globals?
- # Surely these should be in a util package or in the api package?
-
- # Other utility methods
- def parse_userid(self, s):
- """Parse the string given by 's' as a User ID and return a UserID
- object."""
- return UserID.from_string(s)
-
- def parse_roomalias(self, s):
- """Parse the string given by 's' as a Room Alias and return a RoomAlias
- object."""
- return RoomAlias.from_string(s)
-
- 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)
-
- def parse_eventid(self, s):
- """Parse the string given by 's' as a Event ID and return a EventID
- object."""
- return EventID.from_string(s)
-
- 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
ip_addr = request.getClientIP()
@@ -205,9 +176,6 @@ class HomeServer(BaseHomeServer):
def build_auth(self):
return Auth(self)
- def build_rest_servlet_factory(self):
- return RestServletFactory(self)
-
def build_state_handler(self):
return StateHandler(self)
@@ -234,9 +202,3 @@ class HomeServer(BaseHomeServer):
def build_pusherpool(self):
return PusherPool(self)
-
- def register_servlets(self):
- """ Register all servlets associated with this HomeServer.
- """
- # Simply building the ServletFactory is sufficient to have it register
- self.get_rest_servlet_factory()
diff --git a/synapse/storage/roommember.py b/synapse/storage/roommember.py
index e59e65529b..c69dd995ce 100644
--- a/synapse/storage/roommember.py
+++ b/synapse/storage/roommember.py
@@ -20,6 +20,7 @@ from collections import namedtuple
from ._base import SQLBaseStore
from synapse.api.constants import Membership
+from synapse.types import UserID
import logging
@@ -39,7 +40,7 @@ class RoomMemberStore(SQLBaseStore):
"""
try:
target_user_id = event.state_key
- domain = self.hs.parse_userid(target_user_id).domain
+ domain = UserID.from_string(target_user_id).domain
except:
logger.exception(
"Failed to parse target_user_id=%s", target_user_id
@@ -84,7 +85,7 @@ class RoomMemberStore(SQLBaseStore):
for e in member_events:
try:
joined_domains.add(
- self.hs.parse_userid(e.state_key).domain
+ UserID.from_string(e.state_key).domain
)
except:
# FIXME: How do we deal with invalid user ids in the db?
|