2014-08-12 16:10:52 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
2016-01-07 05:26:29 +01:00
|
|
|
# Copyright 2014-2016 OpenMarket Ltd
|
2014-08-12 16:10:52 +02:00
|
|
|
#
|
|
|
|
# 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.
|
|
|
|
|
2014-08-13 04:14:34 +02:00
|
|
|
|
2014-08-12 16:10:52 +02:00
|
|
|
# This file provides some classes for setting up (partially-populated)
|
|
|
|
# homeservers; either as a full homeserver as a real application, or a small
|
|
|
|
# partial one for unit test mocking.
|
|
|
|
|
|
|
|
# Imports required for the default HomeServer() implementation
|
2015-09-09 13:02:07 +02:00
|
|
|
from twisted.web.client import BrowserLikePolicyForHTTPS
|
2016-01-26 14:52:29 +01:00
|
|
|
from twisted.enterprise import adbapi
|
|
|
|
|
2016-05-31 14:53:48 +02:00
|
|
|
from synapse.appservice.scheduler import ApplicationServiceScheduler
|
|
|
|
from synapse.appservice.api import ApplicationServiceApi
|
2014-08-12 16:10:52 +02:00
|
|
|
from synapse.federation import initialize_http_replication
|
2016-02-02 18:18:50 +01:00
|
|
|
from synapse.http.client import SimpleHttpClient, InsecureInterceptableContextFactory
|
2014-08-26 19:57:46 +02:00
|
|
|
from synapse.notifier import Notifier
|
2014-08-12 16:10:52 +02:00
|
|
|
from synapse.api.auth import Auth
|
|
|
|
from synapse.handlers import Handlers
|
2016-05-16 19:56:37 +02:00
|
|
|
from synapse.handlers.presence import PresenceHandler
|
2016-05-16 21:19:26 +02:00
|
|
|
from synapse.handlers.sync import SyncHandler
|
2016-05-17 16:58:46 +02:00
|
|
|
from synapse.handlers.typing import TypingHandler
|
2016-05-31 12:05:16 +02:00
|
|
|
from synapse.handlers.room import RoomListHandler
|
2016-06-02 14:31:45 +02:00
|
|
|
from synapse.handlers.auth import AuthHandler
|
2016-05-31 14:53:48 +02:00
|
|
|
from synapse.handlers.appservice import ApplicationServicesHandler
|
2014-08-12 16:10:52 +02:00
|
|
|
from synapse.state import StateHandler
|
2016-01-28 15:32:05 +01:00
|
|
|
from synapse.storage import DataStore
|
2014-08-12 16:10:52 +02:00
|
|
|
from synapse.util import Clock
|
|
|
|
from synapse.util.distributor import Distributor
|
2014-08-26 19:57:46 +02:00
|
|
|
from synapse.streams.events import EventSources
|
2014-09-02 18:57:04 +02:00
|
|
|
from synapse.api.ratelimiting import Ratelimiter
|
2014-09-30 16:15:10 +02:00
|
|
|
from synapse.crypto.keyring import Keyring
|
2014-11-19 19:20:59 +01:00
|
|
|
from synapse.push.pusherpool import PusherPool
|
2014-12-04 16:50:01 +01:00
|
|
|
from synapse.events.builder import EventBuilderFactory
|
2015-01-27 15:28:56 +01:00
|
|
|
from synapse.api.filtering import Filtering
|
2014-08-12 16:10:52 +02:00
|
|
|
|
2016-01-26 14:52:29 +01:00
|
|
|
from synapse.http.matrixfederationclient import MatrixFederationHttpClient
|
|
|
|
|
2016-01-26 16:51:06 +01:00
|
|
|
import logging
|
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2014-08-12 16:10:52 +02:00
|
|
|
|
2016-01-26 14:52:29 +01:00
|
|
|
class HomeServer(object):
|
2014-08-12 16:10:52 +02:00
|
|
|
"""A basic homeserver object without lazy component builders.
|
|
|
|
|
|
|
|
This will need all of the components it requires to either be passed as
|
|
|
|
constructor arguments, or the relevant methods overriding to create them.
|
|
|
|
Typically this would only be used for unit tests.
|
|
|
|
|
|
|
|
For every dependency in the DEPENDENCIES list below, this class creates one
|
|
|
|
method,
|
|
|
|
def get_DEPENDENCY(self)
|
|
|
|
which returns the value of that dependency. If no value has yet been set
|
|
|
|
nor was provided to the constructor, it will attempt to call a lazy builder
|
|
|
|
method called
|
|
|
|
def build_DEPENDENCY(self)
|
|
|
|
which must be implemented by the subclass. This code may call any of the
|
|
|
|
required "get" methods on the instance to obtain the sub-dependencies that
|
|
|
|
one requires.
|
|
|
|
"""
|
|
|
|
|
|
|
|
DEPENDENCIES = [
|
2015-02-24 15:23:26 +01:00
|
|
|
'config',
|
2014-08-12 16:10:52 +02:00
|
|
|
'clock',
|
|
|
|
'http_client',
|
|
|
|
'db_pool',
|
|
|
|
'persistence_service',
|
|
|
|
'replication_layer',
|
|
|
|
'datastore',
|
|
|
|
'handlers',
|
2015-03-24 18:24:15 +01:00
|
|
|
'v1auth',
|
2014-08-12 16:10:52 +02:00
|
|
|
'auth',
|
|
|
|
'rest_servlet_factory',
|
|
|
|
'state_handler',
|
2016-05-16 19:56:37 +02:00
|
|
|
'presence_handler',
|
2016-05-16 21:19:26 +02:00
|
|
|
'sync_handler',
|
2016-05-17 16:58:46 +02:00
|
|
|
'typing_handler',
|
2016-05-31 12:05:16 +02:00
|
|
|
'room_list_handler',
|
2016-06-02 14:31:45 +02:00
|
|
|
'auth_handler',
|
2016-05-31 14:53:48 +02:00
|
|
|
'application_service_api',
|
|
|
|
'application_service_scheduler',
|
|
|
|
'application_service_handler',
|
2014-08-12 16:10:52 +02:00
|
|
|
'notifier',
|
|
|
|
'distributor',
|
2015-12-08 16:26:52 +01:00
|
|
|
'client_resource',
|
2014-08-14 10:52:20 +02:00
|
|
|
'resource_for_federation',
|
2015-02-23 16:35:09 +01:00
|
|
|
'resource_for_static_content',
|
2014-08-14 10:52:20 +02:00
|
|
|
'resource_for_web_client',
|
2014-08-18 16:01:08 +02:00
|
|
|
'resource_for_content_repo',
|
2014-09-23 19:40:59 +02:00
|
|
|
'resource_for_server_key',
|
2015-04-14 17:04:52 +02:00
|
|
|
'resource_for_server_key_v2',
|
2014-12-02 20:51:47 +01:00
|
|
|
'resource_for_media_repository',
|
2015-03-12 16:33:53 +01:00
|
|
|
'resource_for_metrics',
|
2014-08-26 19:57:46 +02:00
|
|
|
'event_sources',
|
2014-09-02 18:57:04 +02:00
|
|
|
'ratelimiter',
|
2014-09-30 16:15:10 +02:00
|
|
|
'keyring',
|
2014-12-18 16:15:22 +01:00
|
|
|
'pusherpool',
|
2014-12-04 16:50:01 +01:00
|
|
|
'event_builder_factory',
|
2015-01-27 15:28:56 +01:00
|
|
|
'filtering',
|
2015-09-09 13:02:07 +02:00
|
|
|
'http_client_context_factory',
|
|
|
|
'simple_http_client',
|
2014-08-12 16:10:52 +02:00
|
|
|
]
|
|
|
|
|
|
|
|
def __init__(self, hostname, **kwargs):
|
|
|
|
"""
|
|
|
|
Args:
|
|
|
|
hostname : The hostname for the server.
|
|
|
|
"""
|
|
|
|
self.hostname = hostname
|
|
|
|
self._building = {}
|
|
|
|
|
2016-01-26 16:51:06 +01:00
|
|
|
self.clock = Clock()
|
|
|
|
self.distributor = Distributor()
|
|
|
|
self.ratelimiter = Ratelimiter()
|
|
|
|
|
2014-08-12 16:10:52 +02:00
|
|
|
# Other kwargs are explicit dependencies
|
|
|
|
for depname in kwargs:
|
|
|
|
setattr(self, depname, kwargs[depname])
|
|
|
|
|
2016-01-26 16:51:06 +01:00
|
|
|
def setup(self):
|
|
|
|
logger.info("Setting up.")
|
2016-01-28 15:32:05 +01:00
|
|
|
self.datastore = DataStore(self.get_db_conn(), self)
|
2016-01-26 16:51:06 +01:00
|
|
|
logger.info("Finished setting up.")
|
|
|
|
|
2014-09-26 17:36:24 +02:00
|
|
|
def get_ip_from_request(self, request):
|
2015-06-12 18:13:23 +02:00
|
|
|
# X-Forwarded-For is handled by our custom request type.
|
|
|
|
return request.getClientIP()
|
2014-09-26 17:36:24 +02:00
|
|
|
|
2014-12-02 11:42:28 +01:00
|
|
|
def is_mine(self, domain_specific_string):
|
|
|
|
return domain_specific_string.domain == self.hostname
|
|
|
|
|
2016-01-19 17:01:05 +01:00
|
|
|
def is_mine_id(self, string):
|
2016-01-19 17:11:39 +01:00
|
|
|
return string.split(":", 1)[1] == self.hostname
|
2016-01-19 17:01:05 +01:00
|
|
|
|
2014-08-12 16:10:52 +02:00
|
|
|
def build_replication_layer(self):
|
|
|
|
return initialize_http_replication(self)
|
|
|
|
|
|
|
|
def build_handlers(self):
|
|
|
|
return Handlers(self)
|
|
|
|
|
|
|
|
def build_notifier(self):
|
|
|
|
return Notifier(self)
|
|
|
|
|
|
|
|
def build_auth(self):
|
|
|
|
return Auth(self)
|
|
|
|
|
2015-09-09 13:02:07 +02:00
|
|
|
def build_http_client_context_factory(self):
|
|
|
|
return (
|
2015-09-15 16:50:13 +02:00
|
|
|
InsecureInterceptableContextFactory()
|
2016-01-26 16:51:06 +01:00
|
|
|
if self.config.use_insecure_ssl_client_just_for_testing_do_not_use
|
2015-09-09 13:02:07 +02:00
|
|
|
else BrowserLikePolicyForHTTPS()
|
|
|
|
)
|
|
|
|
|
|
|
|
def build_simple_http_client(self):
|
|
|
|
return SimpleHttpClient(self)
|
|
|
|
|
2015-03-24 18:24:15 +01:00
|
|
|
def build_v1auth(self):
|
|
|
|
orf = Auth(self)
|
|
|
|
# Matrix spec makes no reference to what HTTP status code is returned,
|
|
|
|
# but the V1 API uses 403 where it means 401, and the webclient
|
|
|
|
# relies on this behaviour, so V1 gets its own copy of the auth
|
|
|
|
# with backwards compat behaviour.
|
|
|
|
orf.TOKEN_NOT_FOUND_HTTP_STATUS = 403
|
|
|
|
return orf
|
|
|
|
|
2014-08-12 16:10:52 +02:00
|
|
|
def build_state_handler(self):
|
|
|
|
return StateHandler(self)
|
|
|
|
|
2016-05-16 19:56:37 +02:00
|
|
|
def build_presence_handler(self):
|
|
|
|
return PresenceHandler(self)
|
|
|
|
|
2016-05-17 16:58:46 +02:00
|
|
|
def build_typing_handler(self):
|
|
|
|
return TypingHandler(self)
|
|
|
|
|
2016-05-16 21:19:26 +02:00
|
|
|
def build_sync_handler(self):
|
|
|
|
return SyncHandler(self)
|
|
|
|
|
2016-05-31 12:05:16 +02:00
|
|
|
def build_room_list_handler(self):
|
|
|
|
return RoomListHandler(self)
|
|
|
|
|
2016-06-02 14:31:45 +02:00
|
|
|
def build_auth_handler(self):
|
|
|
|
return AuthHandler(self)
|
|
|
|
|
2016-05-31 14:53:48 +02:00
|
|
|
def build_application_service_api(self):
|
|
|
|
return ApplicationServiceApi(self)
|
|
|
|
|
|
|
|
def build_application_service_scheduler(self):
|
|
|
|
return ApplicationServiceScheduler(self)
|
|
|
|
|
|
|
|
def build_application_service_handler(self):
|
|
|
|
return ApplicationServicesHandler(self)
|
|
|
|
|
2014-08-26 19:57:46 +02:00
|
|
|
def build_event_sources(self):
|
|
|
|
return EventSources(self)
|
|
|
|
|
2014-09-30 16:15:10 +02:00
|
|
|
def build_keyring(self):
|
|
|
|
return Keyring(self)
|
|
|
|
|
2014-12-04 16:50:01 +01:00
|
|
|
def build_event_builder_factory(self):
|
|
|
|
return EventBuilderFactory(
|
|
|
|
clock=self.get_clock(),
|
|
|
|
hostname=self.hostname,
|
|
|
|
)
|
2015-01-27 15:28:56 +01:00
|
|
|
|
|
|
|
def build_filtering(self):
|
|
|
|
return Filtering(self)
|
2015-01-29 15:55:27 +01:00
|
|
|
|
2014-11-19 19:20:59 +01:00
|
|
|
def build_pusherpool(self):
|
|
|
|
return PusherPool(self)
|
2016-01-26 14:52:29 +01:00
|
|
|
|
|
|
|
def build_http_client(self):
|
|
|
|
return MatrixFederationHttpClient(self)
|
|
|
|
|
|
|
|
def build_db_pool(self):
|
|
|
|
name = self.db_config["name"]
|
|
|
|
|
|
|
|
return adbapi.ConnectionPool(
|
|
|
|
name,
|
|
|
|
**self.db_config.get("args", {})
|
|
|
|
)
|
|
|
|
|
2016-04-21 18:21:02 +02:00
|
|
|
def remove_pusher(self, app_id, push_key, user_id):
|
|
|
|
return self.get_pusherpool().remove_pusher(app_id, push_key, user_id)
|
|
|
|
|
2016-06-16 13:53:15 +02:00
|
|
|
def get_event_cache_size(self):
|
|
|
|
return self.config.event_cache_size
|
|
|
|
|
2016-01-26 14:52:29 +01:00
|
|
|
|
|
|
|
def _make_dependency_method(depname):
|
|
|
|
def _get(hs):
|
|
|
|
try:
|
|
|
|
return getattr(hs, depname)
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
try:
|
|
|
|
builder = getattr(hs, "build_%s" % (depname))
|
|
|
|
except AttributeError:
|
|
|
|
builder = None
|
|
|
|
|
|
|
|
if builder:
|
|
|
|
# Prevent cyclic dependencies from deadlocking
|
|
|
|
if depname in hs._building:
|
|
|
|
raise ValueError("Cyclic dependency while building %s" % (
|
|
|
|
depname,
|
|
|
|
))
|
|
|
|
hs._building[depname] = 1
|
|
|
|
|
|
|
|
dep = builder()
|
|
|
|
setattr(hs, depname, dep)
|
|
|
|
|
|
|
|
del hs._building[depname]
|
|
|
|
|
|
|
|
return dep
|
|
|
|
|
|
|
|
raise NotImplementedError(
|
|
|
|
"%s has no %s nor a builder for it" % (
|
|
|
|
type(hs).__name__, depname,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
setattr(HomeServer, "get_%s" % (depname), _get)
|
|
|
|
|
|
|
|
|
|
|
|
# Build magic accessors for every dependency
|
|
|
|
for depname in HomeServer.DEPENDENCIES:
|
|
|
|
_make_dependency_method(depname)
|