mirror of
https://github.com/element-hq/synapse.git
synced 2024-12-14 11:57:44 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
d05ff3e098
16 changed files with 123 additions and 93 deletions
|
@ -21,8 +21,13 @@ from synapse.server import HomeServer
|
|||
from twisted.internet import reactor
|
||||
from twisted.enterprise import adbapi
|
||||
from twisted.python.log import PythonLoggingObserver
|
||||
from synapse.http.server import TwistedHttpServer
|
||||
from twisted.web.resource import Resource
|
||||
from twisted.web.static import File
|
||||
from twisted.web.server import Site
|
||||
from synapse.http.server import JsonResource
|
||||
from synapse.http.client import TwistedHttpClient
|
||||
from synapse.rest.base import CLIENT_PREFIX
|
||||
from synapse.federation.transport import PREFIX
|
||||
|
||||
from daemonize import Daemonize
|
||||
|
||||
|
@ -35,12 +40,19 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
|
||||
class SynapseHomeServer(HomeServer):
|
||||
def build_http_server(self):
|
||||
return TwistedHttpServer()
|
||||
|
||||
def build_http_client(self):
|
||||
return TwistedHttpClient()
|
||||
|
||||
def build_resource_for_client(self):
|
||||
return JsonResource()
|
||||
|
||||
def build_resource_for_federation(self):
|
||||
return JsonResource()
|
||||
|
||||
def build_resource_for_web_client(self):
|
||||
return File("webclient")
|
||||
|
||||
def build_db_pool(self):
|
||||
""" Set up all the dbs. Since all the *.sql have IF NOT EXISTS, so we
|
||||
don't have to worry about overwriting existing content.
|
||||
|
@ -73,6 +85,69 @@ class SynapseHomeServer(HomeServer):
|
|||
|
||||
return pool
|
||||
|
||||
def create_resource_tree(self, web_client):
|
||||
"""Create the resource tree for this Home Server.
|
||||
|
||||
This in unduly complicated because Twisted does not support putting
|
||||
child resources more than 1 level deep at a time.
|
||||
"""
|
||||
desired_tree = [ # list containing (path_str, Resource)
|
||||
(CLIENT_PREFIX, self.get_resource_for_client()),
|
||||
(PREFIX, self.get_resource_for_federation())
|
||||
]
|
||||
if web_client:
|
||||
logger.info("Adding the web client.")
|
||||
desired_tree.append(("/matrix/client", # TODO constant please
|
||||
self.get_resource_for_web_client()))
|
||||
|
||||
self.root_resource = Resource()
|
||||
# ideally we'd just use getChild and putChild but getChild doesn't work
|
||||
# unless you give it a Request object IN ADDITION to the name :/ So
|
||||
# instead, we'll store a copy of this mapping so we can actually add
|
||||
# extra resources to existing nodes. See self._resource_id for the key.
|
||||
resource_mappings = {}
|
||||
for (full_path, resource) in desired_tree:
|
||||
logging.info("Attaching %s to path %s", resource, full_path)
|
||||
last_resource = self.root_resource
|
||||
for path_seg in full_path.split('/')[1:-1]:
|
||||
if not path_seg in last_resource.listNames():
|
||||
# resource doesn't exist
|
||||
child_resource = Resource()
|
||||
last_resource.putChild(path_seg, child_resource)
|
||||
res_id = self._resource_id(last_resource, path_seg)
|
||||
resource_mappings[res_id] = child_resource
|
||||
last_resource = child_resource
|
||||
else:
|
||||
# we have an existing Resource, pull it out.
|
||||
res_id = self._resource_id(last_resource, path_seg)
|
||||
last_resource = resource_mappings[res_id]
|
||||
|
||||
# now attach the actual resource
|
||||
last_path_seg = full_path.split('/')[-1]
|
||||
last_resource.putChild(last_path_seg, resource)
|
||||
res_id = self._resource_id(last_resource, last_path_seg)
|
||||
resource_mappings[res_id] = resource
|
||||
|
||||
return self.root_resource
|
||||
|
||||
def _resource_id(self, resource, path_seg):
|
||||
"""Construct an arbitrary resource ID so you can retrieve the mapping
|
||||
later.
|
||||
|
||||
If you want to represent resource A putChild resource B with path C,
|
||||
the mapping should looks like _resource_id(A,C) = B.
|
||||
|
||||
Args:
|
||||
resource (Resource): The *parent* Resource
|
||||
path_seg (str): The name of the child Resource to be attached.
|
||||
Returns:
|
||||
str: A unique string which can be a key to the child Resource.
|
||||
"""
|
||||
return "%s-%s" % (resource, path_seg)
|
||||
|
||||
def start_listening(self, port):
|
||||
reactor.listenTCP(port, Site(self.root_resource))
|
||||
|
||||
|
||||
def setup_logging(verbosity=0, filename=None, config_path=None):
|
||||
""" Sets up logging with verbosity levels.
|
||||
|
@ -150,7 +225,8 @@ def setup():
|
|||
|
||||
hs.register_servlets()
|
||||
|
||||
hs.get_http_server().start_listening(args.port)
|
||||
hs.create_resource_tree(web_client=args.webclient)
|
||||
hs.start_listening(args.port)
|
||||
|
||||
hs.build_db_pool()
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ from .transport import TransportLayer
|
|||
def initialize_http_replication(homeserver):
|
||||
transport = TransportLayer(
|
||||
homeserver.hostname,
|
||||
server=homeserver.get_http_server(),
|
||||
server=homeserver.get_resource_for_federation(),
|
||||
client=homeserver.get_http_client()
|
||||
)
|
||||
|
||||
|
|
|
@ -52,10 +52,9 @@ class HttpServer(object):
|
|||
pass
|
||||
|
||||
|
||||
# The actual HTTP server impl, using twisted http server
|
||||
class TwistedHttpServer(HttpServer, resource.Resource):
|
||||
""" This wraps the twisted HTTP server, and triggers the correct callbacks
|
||||
on the transport_layer.
|
||||
class JsonResource(HttpServer, resource.Resource):
|
||||
""" This implements the HttpServer interface and provides JSON support for
|
||||
Resources.
|
||||
|
||||
Register callbacks via register_path()
|
||||
"""
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
|
||||
|
||||
from . import (
|
||||
room, events, register, login, profile, public, presence, im, directory,
|
||||
webclient
|
||||
room, events, register, login, profile, public, presence, im, directory
|
||||
)
|
||||
|
||||
|
||||
|
@ -32,19 +31,15 @@ class RestServletFactory(object):
|
|||
"""
|
||||
|
||||
def __init__(self, hs):
|
||||
http_server = hs.get_http_server()
|
||||
client_resource = hs.get_resource_for_client()
|
||||
|
||||
# TODO(erikj): There *must* be a better way of doing this.
|
||||
room.register_servlets(hs, http_server)
|
||||
events.register_servlets(hs, http_server)
|
||||
register.register_servlets(hs, http_server)
|
||||
login.register_servlets(hs, http_server)
|
||||
profile.register_servlets(hs, http_server)
|
||||
public.register_servlets(hs, http_server)
|
||||
presence.register_servlets(hs, http_server)
|
||||
im.register_servlets(hs, http_server)
|
||||
directory.register_servlets(hs, http_server)
|
||||
|
||||
def register_web_client(self, hs):
|
||||
http_server = hs.get_http_server()
|
||||
webclient.register_servlets(hs, http_server)
|
||||
room.register_servlets(hs, client_resource)
|
||||
events.register_servlets(hs, client_resource)
|
||||
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)
|
||||
im.register_servlets(hs, client_resource)
|
||||
directory.register_servlets(hs, client_resource)
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
""" This module contains base REST classes for constructing REST servlets. """
|
||||
import re
|
||||
|
||||
CLIENT_PREFIX = "/matrix/client/api/v1"
|
||||
|
||||
|
||||
def client_path_pattern(path_regex):
|
||||
"""Creates a regex compiled client path with the correct client path
|
||||
|
@ -27,7 +29,7 @@ def client_path_pattern(path_regex):
|
|||
Returns:
|
||||
SRE_Pattern
|
||||
"""
|
||||
return re.compile("^/matrix/client/api/v1" + path_regex)
|
||||
return re.compile("^" + CLIENT_PREFIX + path_regex)
|
||||
|
||||
|
||||
class RestServlet(object):
|
||||
|
|
|
@ -1,45 +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.
|
||||
|
||||
from synapse.rest.base import RestServlet
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WebClientRestServlet(RestServlet):
|
||||
# No PATTERN; we have custom dispatch rules here
|
||||
|
||||
def register(self, http_server):
|
||||
http_server.register_path("GET",
|
||||
re.compile("^/$"),
|
||||
self.on_GET_redirect)
|
||||
http_server.register_path("GET",
|
||||
re.compile("^/matrix/client$"),
|
||||
self.on_GET)
|
||||
|
||||
def on_GET(self, request):
|
||||
return (200, "not implemented")
|
||||
|
||||
def on_GET_redirect(self, request):
|
||||
request.setHeader("Location", request.uri + "matrix/client")
|
||||
return (302, None)
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
logger.info("Registering web client.")
|
||||
WebClientRestServlet(hs).register(http_server)
|
|
@ -55,7 +55,6 @@ class BaseHomeServer(object):
|
|||
|
||||
DEPENDENCIES = [
|
||||
'clock',
|
||||
'http_server',
|
||||
'http_client',
|
||||
'db_pool',
|
||||
'persistence_service',
|
||||
|
@ -70,6 +69,9 @@ class BaseHomeServer(object):
|
|||
'room_lock_manager',
|
||||
'notifier',
|
||||
'distributor',
|
||||
'resource_for_client',
|
||||
'resource_for_federation',
|
||||
'resource_for_web_client',
|
||||
]
|
||||
|
||||
def __init__(self, hostname, **kwargs):
|
||||
|
@ -135,7 +137,9 @@ class HomeServer(BaseHomeServer):
|
|||
required.
|
||||
|
||||
It still requires the following to be specified by the caller:
|
||||
http_server
|
||||
resource_for_client
|
||||
resource_for_web_client
|
||||
resource_for_federation
|
||||
http_client
|
||||
db_pool
|
||||
"""
|
||||
|
@ -178,9 +182,6 @@ class HomeServer(BaseHomeServer):
|
|||
|
||||
def register_servlets(self):
|
||||
""" Register all servlets associated with this HomeServer.
|
||||
|
||||
Args:
|
||||
host_web_client (bool): True to host the web client as well.
|
||||
"""
|
||||
# Simply building the ServletFactory is sufficient to have it register
|
||||
factory = self.get_rest_servlet_factory()
|
||||
self.get_rest_servlet_factory()
|
||||
|
|
|
@ -70,7 +70,7 @@ class FederationTestCase(unittest.TestCase):
|
|||
)
|
||||
self.clock = MockClock()
|
||||
hs = HomeServer("test",
|
||||
http_server=self.mock_http_server,
|
||||
resource_for_federation=self.mock_http_server,
|
||||
http_client=self.mock_http_client,
|
||||
db_pool=None,
|
||||
datastore=self.mock_persistence,
|
||||
|
|
|
@ -51,7 +51,7 @@ class DirectoryTestCase(unittest.TestCase):
|
|||
"get_association_from_room_alias",
|
||||
]),
|
||||
http_client=None,
|
||||
http_server=Mock(),
|
||||
resource_for_federation=Mock(),
|
||||
replication_layer=self.mock_federation,
|
||||
)
|
||||
hs.handlers = DirectoryHandlers(hs)
|
||||
|
|
|
@ -42,7 +42,7 @@ class FederationTestCase(unittest.TestCase):
|
|||
"persist_event",
|
||||
"store_room",
|
||||
]),
|
||||
http_server=NonCallableMock(),
|
||||
resource_for_federation=NonCallableMock(),
|
||||
http_client=NonCallableMock(spec_set=[]),
|
||||
notifier=NonCallableMock(spec_set=["on_new_room_event"]),
|
||||
handlers=NonCallableMock(spec_set=[
|
||||
|
|
|
@ -66,7 +66,7 @@ class PresenceStateTestCase(unittest.TestCase):
|
|||
"set_presence_list_accepted",
|
||||
]),
|
||||
handlers=None,
|
||||
http_server=Mock(),
|
||||
resource_for_federation=Mock(),
|
||||
http_client=None,
|
||||
)
|
||||
hs.handlers = JustPresenceHandlers(hs)
|
||||
|
@ -188,7 +188,7 @@ class PresenceInvitesTestCase(unittest.TestCase):
|
|||
"del_presence_list",
|
||||
]),
|
||||
handlers=None,
|
||||
http_server=Mock(),
|
||||
resource_for_client=Mock(),
|
||||
http_client=None,
|
||||
replication_layer=self.replication
|
||||
)
|
||||
|
@ -402,7 +402,7 @@ class PresencePushTestCase(unittest.TestCase):
|
|||
"set_presence_state",
|
||||
]),
|
||||
handlers=None,
|
||||
http_server=Mock(),
|
||||
resource_for_client=Mock(),
|
||||
http_client=None,
|
||||
replication_layer=self.replication,
|
||||
)
|
||||
|
@ -727,7 +727,7 @@ class PresencePollingTestCase(unittest.TestCase):
|
|||
db_pool=None,
|
||||
datastore=Mock(spec=[]),
|
||||
handlers=None,
|
||||
http_server=Mock(),
|
||||
resource_for_client=Mock(),
|
||||
http_client=None,
|
||||
replication_layer=self.replication,
|
||||
)
|
||||
|
|
|
@ -71,7 +71,7 @@ class PresenceProfilelikeDataTestCase(unittest.TestCase):
|
|||
"set_profile_displayname",
|
||||
]),
|
||||
handlers=None,
|
||||
http_server=Mock(),
|
||||
resource_for_federation=Mock(),
|
||||
http_client=None,
|
||||
replication_layer=MockReplication(),
|
||||
)
|
||||
|
|
|
@ -56,7 +56,7 @@ class ProfileTestCase(unittest.TestCase):
|
|||
"set_profile_avatar_url",
|
||||
]),
|
||||
handlers=None,
|
||||
http_server=Mock(),
|
||||
resource_for_federation=Mock(),
|
||||
replication_layer=self.mock_federation,
|
||||
)
|
||||
hs.handlers = ProfileHandlers(hs)
|
||||
|
@ -139,7 +139,7 @@ class ProfileTestCase(unittest.TestCase):
|
|||
mocked_set = self.datastore.set_profile_avatar_url
|
||||
mocked_set.return_value = defer.succeed(())
|
||||
|
||||
yield self.handler.set_avatar_url(self.frank, self.frank,
|
||||
yield self.handler.set_avatar_url(self.frank, self.frank,
|
||||
"http://my.server/pic.gif")
|
||||
|
||||
mocked_set.assert_called_with("1234ABCD", "http://my.server/pic.gif")
|
||||
|
|
|
@ -46,7 +46,7 @@ class RoomMemberHandlerTestCase(unittest.TestCase):
|
|||
"get_room",
|
||||
"store_room",
|
||||
]),
|
||||
http_server=NonCallableMock(),
|
||||
resource_for_federation=NonCallableMock(),
|
||||
http_client=NonCallableMock(spec_set=[]),
|
||||
notifier=NonCallableMock(spec_set=["on_new_room_event"]),
|
||||
handlers=NonCallableMock(spec_set=[
|
||||
|
@ -317,7 +317,6 @@ class RoomCreationTest(unittest.TestCase):
|
|||
datastore=NonCallableMock(spec_set=[
|
||||
"store_room",
|
||||
]),
|
||||
http_server=NonCallableMock(),
|
||||
http_client=NonCallableMock(spec_set=[]),
|
||||
notifier=NonCallableMock(spec_set=["on_new_room_event"]),
|
||||
handlers=NonCallableMock(spec_set=[
|
||||
|
|
|
@ -51,7 +51,8 @@ class PresenceStateTestCase(unittest.TestCase):
|
|||
hs = HomeServer("test",
|
||||
db_pool=None,
|
||||
http_client=None,
|
||||
http_server=self.mock_server,
|
||||
resource_for_client=self.mock_server,
|
||||
resource_for_federation=self.mock_server,
|
||||
)
|
||||
|
||||
def _get_user_by_token(token=None):
|
||||
|
@ -108,7 +109,8 @@ class PresenceListTestCase(unittest.TestCase):
|
|||
hs = HomeServer("test",
|
||||
db_pool=None,
|
||||
http_client=None,
|
||||
http_server=self.mock_server,
|
||||
resource_for_client=self.mock_server,
|
||||
resource_for_federation=self.mock_server
|
||||
)
|
||||
|
||||
def _get_user_by_token(token=None):
|
||||
|
@ -183,7 +185,8 @@ class PresenceEventStreamTestCase(unittest.TestCase):
|
|||
hs = HomeServer("test",
|
||||
db_pool=None,
|
||||
http_client=None,
|
||||
http_server=self.mock_server,
|
||||
resource_for_client=self.mock_server,
|
||||
resource_for_federation=self.mock_server,
|
||||
datastore=Mock(spec=[
|
||||
"set_presence_state",
|
||||
"get_presence_list",
|
||||
|
|
|
@ -43,7 +43,7 @@ class ProfileTestCase(unittest.TestCase):
|
|||
hs = HomeServer("test",
|
||||
db_pool=None,
|
||||
http_client=None,
|
||||
http_server=self.mock_server,
|
||||
resource_for_client=self.mock_server,
|
||||
federation=Mock(),
|
||||
replication_layer=Mock(),
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue