mirror of
https://github.com/element-hq/synapse.git
synced 2024-11-22 09:35:45 +03:00
Start phasing out HttpServer: we should be using Resources instead. Added resource_for_client/federation/web_client to the HomeServer and hooked the C-S servlets to operate on resource_for_client. Dynamically construct the Resource tree.
This commit is contained in:
parent
e7736668ba
commit
9f863d3466
7 changed files with 101 additions and 21 deletions
|
@ -21,8 +21,12 @@ from synapse.server import HomeServer
|
||||||
from twisted.internet import reactor
|
from twisted.internet import reactor
|
||||||
from twisted.enterprise import adbapi
|
from twisted.enterprise import adbapi
|
||||||
from twisted.python.log import PythonLoggingObserver
|
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 TwistedHttpServer, JsonResource
|
||||||
from synapse.http.client import TwistedHttpClient
|
from synapse.http.client import TwistedHttpClient
|
||||||
|
from synapse.rest.base import CLIENT_PREFIX
|
||||||
|
|
||||||
from daemonize import Daemonize
|
from daemonize import Daemonize
|
||||||
|
|
||||||
|
@ -41,6 +45,15 @@ class SynapseHomeServer(HomeServer):
|
||||||
def build_http_client(self):
|
def build_http_client(self):
|
||||||
return TwistedHttpClient()
|
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):
|
def build_db_pool(self):
|
||||||
""" Set up all the dbs. Since all the *.sql have IF NOT EXISTS, so we
|
""" Set up all the dbs. Since all the *.sql have IF NOT EXISTS, so we
|
||||||
don't have to worry about overwriting existing content.
|
don't have to worry about overwriting existing content.
|
||||||
|
@ -73,6 +86,65 @@ class SynapseHomeServer(HomeServer):
|
||||||
|
|
||||||
return pool
|
return pool
|
||||||
|
|
||||||
|
def create_resource_tree(self):
|
||||||
|
"""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 of tuples containing (path_str, Resource)
|
||||||
|
("/matrix/client", self.get_resource_for_web_client()),
|
||||||
|
(CLIENT_PREFIX, self.get_resource_for_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):
|
def setup_logging(verbosity=0, filename=None, config_path=None):
|
||||||
""" Sets up logging with verbosity levels.
|
""" Sets up logging with verbosity levels.
|
||||||
|
@ -150,7 +222,8 @@ def setup():
|
||||||
|
|
||||||
hs.register_servlets()
|
hs.register_servlets()
|
||||||
|
|
||||||
hs.get_http_server().start_listening(args.port)
|
hs.create_resource_tree()
|
||||||
|
hs.start_listening(args.port)
|
||||||
|
|
||||||
hs.build_db_pool()
|
hs.build_db_pool()
|
||||||
|
|
||||||
|
|
|
@ -185,3 +185,8 @@ def respond_with_json_bytes(request, code, json_bytes, send_cors=False):
|
||||||
request.write(json_bytes)
|
request.write(json_bytes)
|
||||||
request.finish()
|
request.finish()
|
||||||
return NOT_DONE_YET
|
return NOT_DONE_YET
|
||||||
|
|
||||||
|
|
||||||
|
# FIXME: Temp, just so the new name can be used without breaking the world.
|
||||||
|
class JsonResource(TwistedHttpServer):
|
||||||
|
pass
|
|
@ -32,19 +32,15 @@ class RestServletFactory(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, hs):
|
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.
|
# TODO(erikj): There *must* be a better way of doing this.
|
||||||
room.register_servlets(hs, http_server)
|
room.register_servlets(hs, client_resource)
|
||||||
events.register_servlets(hs, http_server)
|
events.register_servlets(hs, client_resource)
|
||||||
register.register_servlets(hs, http_server)
|
register.register_servlets(hs, client_resource)
|
||||||
login.register_servlets(hs, http_server)
|
login.register_servlets(hs, client_resource)
|
||||||
profile.register_servlets(hs, http_server)
|
profile.register_servlets(hs, client_resource)
|
||||||
public.register_servlets(hs, http_server)
|
public.register_servlets(hs, client_resource)
|
||||||
presence.register_servlets(hs, http_server)
|
presence.register_servlets(hs, client_resource)
|
||||||
im.register_servlets(hs, http_server)
|
im.register_servlets(hs, client_resource)
|
||||||
directory.register_servlets(hs, http_server)
|
directory.register_servlets(hs, client_resource)
|
||||||
|
|
||||||
def register_web_client(self, hs):
|
|
||||||
http_server = hs.get_http_server()
|
|
||||||
webclient.register_servlets(hs, http_server)
|
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
""" This module contains base REST classes for constructing REST servlets. """
|
""" This module contains base REST classes for constructing REST servlets. """
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
CLIENT_PREFIX = "/matrix/client/api/v1"
|
||||||
|
|
||||||
|
|
||||||
def client_path_pattern(path_regex):
|
def client_path_pattern(path_regex):
|
||||||
"""Creates a regex compiled client path with the correct client path
|
"""Creates a regex compiled client path with the correct client path
|
||||||
|
@ -27,7 +29,7 @@ def client_path_pattern(path_regex):
|
||||||
Returns:
|
Returns:
|
||||||
SRE_Pattern
|
SRE_Pattern
|
||||||
"""
|
"""
|
||||||
return re.compile("^/matrix/client/api/v1" + path_regex)
|
return re.compile("^" + CLIENT_PREFIX + path_regex)
|
||||||
|
|
||||||
|
|
||||||
class RestServlet(object):
|
class RestServlet(object):
|
||||||
|
|
|
@ -70,6 +70,9 @@ class BaseHomeServer(object):
|
||||||
'room_lock_manager',
|
'room_lock_manager',
|
||||||
'notifier',
|
'notifier',
|
||||||
'distributor',
|
'distributor',
|
||||||
|
'resource_for_client',
|
||||||
|
'resource_for_federation',
|
||||||
|
'resource_for_web_client',
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, hostname, **kwargs):
|
def __init__(self, hostname, **kwargs):
|
||||||
|
@ -178,9 +181,6 @@ class HomeServer(BaseHomeServer):
|
||||||
|
|
||||||
def register_servlets(self):
|
def register_servlets(self):
|
||||||
""" Register all servlets associated with this HomeServer.
|
""" 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
|
# Simply building the ServletFactory is sufficient to have it register
|
||||||
factory = self.get_rest_servlet_factory()
|
self.get_rest_servlet_factory()
|
||||||
|
|
|
@ -51,6 +51,7 @@ class PresenceStateTestCase(unittest.TestCase):
|
||||||
hs = HomeServer("test",
|
hs = HomeServer("test",
|
||||||
db_pool=None,
|
db_pool=None,
|
||||||
http_client=None,
|
http_client=None,
|
||||||
|
resource_for_client=self.mock_server,
|
||||||
http_server=self.mock_server,
|
http_server=self.mock_server,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -108,6 +109,7 @@ class PresenceListTestCase(unittest.TestCase):
|
||||||
hs = HomeServer("test",
|
hs = HomeServer("test",
|
||||||
db_pool=None,
|
db_pool=None,
|
||||||
http_client=None,
|
http_client=None,
|
||||||
|
resource_for_client=self.mock_server,
|
||||||
http_server=self.mock_server,
|
http_server=self.mock_server,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -184,6 +186,7 @@ class PresenceEventStreamTestCase(unittest.TestCase):
|
||||||
db_pool=None,
|
db_pool=None,
|
||||||
http_client=None,
|
http_client=None,
|
||||||
http_server=self.mock_server,
|
http_server=self.mock_server,
|
||||||
|
resource_for_client=self.mock_server,
|
||||||
datastore=Mock(spec=[
|
datastore=Mock(spec=[
|
||||||
"set_presence_state",
|
"set_presence_state",
|
||||||
"get_presence_list",
|
"get_presence_list",
|
||||||
|
|
|
@ -44,6 +44,7 @@ class ProfileTestCase(unittest.TestCase):
|
||||||
db_pool=None,
|
db_pool=None,
|
||||||
http_client=None,
|
http_client=None,
|
||||||
http_server=self.mock_server,
|
http_server=self.mock_server,
|
||||||
|
resource_for_client=self.mock_server,
|
||||||
federation=Mock(),
|
federation=Mock(),
|
||||||
replication_layer=Mock(),
|
replication_layer=Mock(),
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue