matrix-synapse 1.139.2__cp39-abi3-macosx_11_0_arm64.whl → 1.140.0rc1__cp39-abi3-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of matrix-synapse might be problematic. Click here for more details.
- {matrix_synapse-1.139.2.dist-info → matrix_synapse-1.140.0rc1.dist-info}/METADATA +5 -3
- {matrix_synapse-1.139.2.dist-info → matrix_synapse-1.140.0rc1.dist-info}/RECORD +157 -154
- synapse/_scripts/generate_workers_map.py +6 -1
- synapse/_scripts/synapse_port_db.py +0 -2
- synapse/_scripts/update_synapse_database.py +1 -6
- synapse/api/auth/base.py +1 -3
- synapse/api/auth/mas.py +6 -8
- synapse/api/auth/msc3861_delegated.py +6 -8
- synapse/api/errors.py +3 -0
- synapse/app/_base.py +101 -39
- synapse/app/admin_cmd.py +2 -4
- synapse/app/appservice.py +1 -1
- synapse/app/client_reader.py +1 -1
- synapse/app/event_creator.py +1 -1
- synapse/app/federation_reader.py +1 -1
- synapse/app/federation_sender.py +1 -1
- synapse/app/frontend_proxy.py +1 -1
- synapse/app/generic_worker.py +17 -11
- synapse/app/homeserver.py +85 -47
- synapse/app/media_repository.py +1 -1
- synapse/app/phone_stats_home.py +16 -14
- synapse/app/pusher.py +1 -1
- synapse/app/synchrotron.py +1 -1
- synapse/app/user_dir.py +1 -1
- synapse/appservice/__init__.py +29 -2
- synapse/appservice/scheduler.py +8 -8
- synapse/config/_base.py +32 -14
- synapse/config/_base.pyi +5 -3
- synapse/config/experimental.py +3 -0
- synapse/config/homeserver.py +27 -1
- synapse/config/logger.py +3 -4
- synapse/config/matrixrtc.py +67 -0
- synapse/crypto/keyring.py +18 -4
- synapse/events/auto_accept_invites.py +0 -1
- synapse/federation/federation_client.py +39 -0
- synapse/federation/federation_server.py +1 -1
- synapse/federation/send_queue.py +3 -0
- synapse/federation/sender/__init__.py +24 -8
- synapse/federation/sender/per_destination_queue.py +31 -8
- synapse/federation/sender/transaction_manager.py +12 -0
- synapse/federation/transport/client.py +29 -0
- synapse/handlers/account_validity.py +2 -4
- synapse/handlers/appservice.py +5 -7
- synapse/handlers/deactivate_account.py +2 -3
- synapse/handlers/delayed_events.py +10 -13
- synapse/handlers/device.py +14 -14
- synapse/handlers/e2e_keys.py +4 -3
- synapse/handlers/federation.py +7 -11
- synapse/handlers/federation_event.py +5 -6
- synapse/handlers/message.py +16 -10
- synapse/handlers/pagination.py +3 -7
- synapse/handlers/presence.py +21 -25
- synapse/handlers/profile.py +1 -1
- synapse/handlers/read_marker.py +3 -1
- synapse/handlers/register.py +8 -1
- synapse/handlers/room.py +13 -4
- synapse/handlers/room_member.py +11 -7
- synapse/handlers/room_policy.py +96 -2
- synapse/handlers/sso.py +1 -1
- synapse/handlers/stats.py +5 -3
- synapse/handlers/sync.py +20 -13
- synapse/handlers/typing.py +5 -10
- synapse/handlers/user_directory.py +12 -11
- synapse/handlers/worker_lock.py +19 -15
- synapse/http/client.py +18 -13
- synapse/http/federation/matrix_federation_agent.py +6 -1
- synapse/http/federation/well_known_resolver.py +3 -1
- synapse/http/matrixfederationclient.py +50 -11
- synapse/http/proxy.py +2 -2
- synapse/http/server.py +36 -2
- synapse/http/site.py +109 -17
- synapse/logging/context.py +165 -63
- synapse/logging/opentracing.py +30 -6
- synapse/logging/scopecontextmanager.py +161 -0
- synapse/media/_base.py +2 -1
- synapse/media/media_repository.py +20 -6
- synapse/media/url_previewer.py +5 -6
- synapse/metrics/_gc.py +3 -1
- synapse/metrics/background_process_metrics.py +128 -24
- synapse/metrics/common_usage_metrics.py +3 -5
- synapse/module_api/__init__.py +42 -5
- synapse/notifier.py +10 -3
- synapse/push/emailpusher.py +5 -4
- synapse/push/httppusher.py +6 -6
- synapse/push/pusherpool.py +3 -8
- synapse/replication/http/devices.py +0 -41
- synapse/replication/tcp/client.py +8 -5
- synapse/replication/tcp/handler.py +2 -3
- synapse/replication/tcp/protocol.py +14 -7
- synapse/replication/tcp/redis.py +16 -11
- synapse/replication/tcp/resource.py +5 -4
- synapse/replication/tcp/streams/__init__.py +2 -0
- synapse/res/providers.json +6 -5
- synapse/rest/__init__.py +2 -0
- synapse/rest/admin/__init__.py +4 -0
- synapse/rest/admin/events.py +69 -0
- synapse/rest/admin/media.py +70 -2
- synapse/rest/client/matrixrtc.py +52 -0
- synapse/rest/client/push_rule.py +1 -1
- synapse/rest/client/room.py +2 -3
- synapse/rest/client/sync.py +1 -0
- synapse/rest/client/transactions.py +1 -1
- synapse/server.py +271 -38
- synapse/server_notices/server_notices_manager.py +1 -0
- synapse/state/__init__.py +4 -1
- synapse/storage/_base.py +1 -1
- synapse/storage/background_updates.py +8 -3
- synapse/storage/controllers/persist_events.py +4 -3
- synapse/storage/controllers/purge_events.py +2 -3
- synapse/storage/controllers/state.py +5 -5
- synapse/storage/database.py +12 -7
- synapse/storage/databases/main/__init__.py +7 -2
- synapse/storage/databases/main/cache.py +4 -3
- synapse/storage/databases/main/censor_events.py +1 -1
- synapse/storage/databases/main/client_ips.py +9 -8
- synapse/storage/databases/main/deviceinbox.py +7 -6
- synapse/storage/databases/main/devices.py +4 -4
- synapse/storage/databases/main/end_to_end_keys.py +6 -3
- synapse/storage/databases/main/event_federation.py +7 -6
- synapse/storage/databases/main/event_push_actions.py +13 -13
- synapse/storage/databases/main/events_bg_updates.py +1 -1
- synapse/storage/databases/main/events_worker.py +6 -8
- synapse/storage/databases/main/lock.py +17 -13
- synapse/storage/databases/main/media_repository.py +2 -2
- synapse/storage/databases/main/metrics.py +6 -6
- synapse/storage/databases/main/monthly_active_users.py +3 -4
- synapse/storage/databases/main/receipts.py +1 -1
- synapse/storage/databases/main/registration.py +18 -19
- synapse/storage/databases/main/roommember.py +1 -1
- synapse/storage/databases/main/session.py +3 -3
- synapse/storage/databases/main/sliding_sync.py +2 -2
- synapse/storage/databases/main/transactions.py +3 -3
- synapse/storage/databases/state/store.py +2 -0
- synapse/synapse_rust/http_client.pyi +4 -0
- synapse/synapse_rust.abi3.so +0 -0
- synapse/util/async_helpers.py +36 -24
- synapse/util/batching_queue.py +16 -6
- synapse/util/caches/__init__.py +1 -1
- synapse/util/caches/deferred_cache.py +4 -0
- synapse/util/caches/descriptors.py +14 -2
- synapse/util/caches/dictionary_cache.py +6 -1
- synapse/util/caches/expiringcache.py +16 -5
- synapse/util/caches/lrucache.py +14 -26
- synapse/util/caches/response_cache.py +11 -1
- synapse/util/clock.py +215 -39
- synapse/util/constants.py +2 -0
- synapse/util/daemonize.py +5 -1
- synapse/util/distributor.py +9 -5
- synapse/util/metrics.py +35 -6
- synapse/util/ratelimitutils.py +4 -1
- synapse/util/retryutils.py +7 -4
- synapse/util/task_scheduler.py +11 -14
- synapse/logging/filter.py +0 -38
- {matrix_synapse-1.139.2.dist-info → matrix_synapse-1.140.0rc1.dist-info}/AUTHORS.rst +0 -0
- {matrix_synapse-1.139.2.dist-info → matrix_synapse-1.140.0rc1.dist-info}/LICENSE-AGPL-3.0 +0 -0
- {matrix_synapse-1.139.2.dist-info → matrix_synapse-1.140.0rc1.dist-info}/LICENSE-COMMERCIAL +0 -0
- {matrix_synapse-1.139.2.dist-info → matrix_synapse-1.140.0rc1.dist-info}/WHEEL +0 -0
- {matrix_synapse-1.139.2.dist-info → matrix_synapse-1.140.0rc1.dist-info}/entry_points.txt +0 -0
synapse/config/homeserver.py
CHANGED
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
# [This file includes modifications made by New Vector Limited]
|
|
19
19
|
#
|
|
20
20
|
#
|
|
21
|
-
|
|
21
|
+
|
|
22
|
+
from ._base import ConfigError, RootConfig
|
|
22
23
|
from .account_validity import AccountValidityConfig
|
|
23
24
|
from .api import ApiConfig
|
|
24
25
|
from .appservice import AppServiceConfig
|
|
@@ -37,6 +38,7 @@ from .jwt import JWTConfig
|
|
|
37
38
|
from .key import KeyConfig
|
|
38
39
|
from .logger import LoggingConfig
|
|
39
40
|
from .mas import MasConfig
|
|
41
|
+
from .matrixrtc import MatrixRtcConfig
|
|
40
42
|
from .metrics import MetricsConfig
|
|
41
43
|
from .modules import ModulesConfig
|
|
42
44
|
from .oembed import OembedConfig
|
|
@@ -66,6 +68,10 @@ from .workers import WorkerConfig
|
|
|
66
68
|
|
|
67
69
|
|
|
68
70
|
class HomeServerConfig(RootConfig):
|
|
71
|
+
"""
|
|
72
|
+
Top-level config object for Synapse homeserver (main process and workers).
|
|
73
|
+
"""
|
|
74
|
+
|
|
69
75
|
config_classes = [
|
|
70
76
|
ModulesConfig,
|
|
71
77
|
ServerConfig,
|
|
@@ -80,6 +86,7 @@ class HomeServerConfig(RootConfig):
|
|
|
80
86
|
OembedConfig,
|
|
81
87
|
CaptchaConfig,
|
|
82
88
|
VoipConfig,
|
|
89
|
+
MatrixRtcConfig,
|
|
83
90
|
RegistrationConfig,
|
|
84
91
|
AccountValidityConfig,
|
|
85
92
|
MetricsConfig,
|
|
@@ -113,3 +120,22 @@ class HomeServerConfig(RootConfig):
|
|
|
113
120
|
# This must be last, as it checks for conflicts with other config options.
|
|
114
121
|
MasConfig,
|
|
115
122
|
]
|
|
123
|
+
|
|
124
|
+
def validate_config(
|
|
125
|
+
self,
|
|
126
|
+
) -> None:
|
|
127
|
+
if (
|
|
128
|
+
self.registration.enable_registration
|
|
129
|
+
and not self.registration.enable_registration_without_verification
|
|
130
|
+
):
|
|
131
|
+
if (
|
|
132
|
+
not self.captcha.enable_registration_captcha
|
|
133
|
+
and not self.registration.registrations_require_3pid
|
|
134
|
+
and not self.registration.registration_requires_token
|
|
135
|
+
):
|
|
136
|
+
raise ConfigError(
|
|
137
|
+
"You have enabled open registration without any verification. This is a known vector for "
|
|
138
|
+
"spam and abuse. If you would like to allow public registration, please consider adding email, "
|
|
139
|
+
"captcha, or token-based verification. Otherwise this check can be removed by setting the "
|
|
140
|
+
"`enable_registration_without_verification` config option to `true`."
|
|
141
|
+
)
|
synapse/config/logger.py
CHANGED
|
@@ -40,7 +40,6 @@ from twisted.logger import (
|
|
|
40
40
|
)
|
|
41
41
|
|
|
42
42
|
from synapse.logging.context import LoggingContextFilter
|
|
43
|
-
from synapse.logging.filter import MetadataFilter
|
|
44
43
|
from synapse.synapse_rust import reset_logging_config
|
|
45
44
|
from synapse.types import JsonDict
|
|
46
45
|
|
|
@@ -213,13 +212,11 @@ def _setup_stdlib_logging(
|
|
|
213
212
|
# writes.
|
|
214
213
|
|
|
215
214
|
log_context_filter = LoggingContextFilter()
|
|
216
|
-
log_metadata_filter = MetadataFilter({"server_name": config.server.server_name})
|
|
217
215
|
old_factory = logging.getLogRecordFactory()
|
|
218
216
|
|
|
219
217
|
def factory(*args: Any, **kwargs: Any) -> logging.LogRecord:
|
|
220
218
|
record = old_factory(*args, **kwargs)
|
|
221
219
|
log_context_filter.filter(record)
|
|
222
|
-
log_metadata_filter.filter(record)
|
|
223
220
|
return record
|
|
224
221
|
|
|
225
222
|
logging.setLogRecordFactory(factory)
|
|
@@ -348,7 +345,9 @@ def setup_logging(
|
|
|
348
345
|
# Add a SIGHUP handler to reload the logging configuration, if one is available.
|
|
349
346
|
from synapse.app import _base as appbase
|
|
350
347
|
|
|
351
|
-
appbase.register_sighup(
|
|
348
|
+
appbase.register_sighup(
|
|
349
|
+
hs.get_instance_id(), _reload_logging_config, log_config_path
|
|
350
|
+
)
|
|
352
351
|
|
|
353
352
|
# Log immediately so we can grep backwards.
|
|
354
353
|
logger.warning("***** STARTING SERVER *****")
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This file is licensed under the Affero General Public License (AGPL) version 3.
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2025 New Vector, Ltd
|
|
5
|
+
#
|
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the GNU Affero General Public License as
|
|
8
|
+
# published by the Free Software Foundation, either version 3 of the
|
|
9
|
+
# License, or (at your option) any later version.
|
|
10
|
+
#
|
|
11
|
+
# See the GNU Affero General Public License for more details:
|
|
12
|
+
# <https://www.gnu.org/licenses/agpl-3.0.html>.
|
|
13
|
+
#
|
|
14
|
+
# [This file includes modifications made by New Vector Limited]
|
|
15
|
+
#
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
from typing import Any, Optional
|
|
19
|
+
|
|
20
|
+
from pydantic import ValidationError
|
|
21
|
+
|
|
22
|
+
from synapse._pydantic_compat import Field, StrictStr, validator
|
|
23
|
+
from synapse.types import JsonDict
|
|
24
|
+
from synapse.util.pydantic_models import ParseModel
|
|
25
|
+
|
|
26
|
+
from ._base import Config, ConfigError
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class TransportConfigModel(ParseModel):
|
|
30
|
+
type: StrictStr
|
|
31
|
+
|
|
32
|
+
livekit_service_url: Optional[StrictStr] = Field(default=None)
|
|
33
|
+
"""An optional livekit service URL. Only required if type is "livekit"."""
|
|
34
|
+
|
|
35
|
+
@validator("livekit_service_url", always=True)
|
|
36
|
+
def validate_livekit_service_url(cls, v: Any, values: dict) -> Any:
|
|
37
|
+
if values.get("type") == "livekit" and not v:
|
|
38
|
+
raise ValueError(
|
|
39
|
+
"You must set a `livekit_service_url` when using the 'livekit' transport."
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
return v
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class MatrixRtcConfigModel(ParseModel):
|
|
46
|
+
transports: list = []
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class MatrixRtcConfig(Config):
|
|
50
|
+
section = "matrix_rtc"
|
|
51
|
+
|
|
52
|
+
def read_config(
|
|
53
|
+
self, config: JsonDict, allow_secrets_in_config: bool, **kwargs: Any
|
|
54
|
+
) -> None:
|
|
55
|
+
matrix_rtc = config.get("matrix_rtc", {})
|
|
56
|
+
if matrix_rtc is None:
|
|
57
|
+
matrix_rtc = {}
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
parsed = MatrixRtcConfigModel(**matrix_rtc)
|
|
61
|
+
except ValidationError as e:
|
|
62
|
+
raise ConfigError(
|
|
63
|
+
"Could not validate matrix_rtc config",
|
|
64
|
+
("matrix_rtc",),
|
|
65
|
+
) from e
|
|
66
|
+
|
|
67
|
+
self.transports = parsed.transports
|
synapse/crypto/keyring.py
CHANGED
|
@@ -172,7 +172,7 @@ class Keyring:
|
|
|
172
172
|
_FetchKeyRequest, Dict[str, Dict[str, FetchKeyResult]]
|
|
173
173
|
] = BatchingQueue(
|
|
174
174
|
name="keyring_server",
|
|
175
|
-
|
|
175
|
+
hs=hs,
|
|
176
176
|
clock=hs.get_clock(),
|
|
177
177
|
# The method called to fetch each key
|
|
178
178
|
process_batch_callback=self._inner_fetch_key_requests,
|
|
@@ -194,6 +194,14 @@ class Keyring:
|
|
|
194
194
|
valid_until_ts=2**63, # fake future timestamp
|
|
195
195
|
)
|
|
196
196
|
|
|
197
|
+
def shutdown(self) -> None:
|
|
198
|
+
"""
|
|
199
|
+
Prepares the KeyRing for garbage collection by shutting down it's queues.
|
|
200
|
+
"""
|
|
201
|
+
self._fetch_keys_queue.shutdown()
|
|
202
|
+
for key_fetcher in self._key_fetchers:
|
|
203
|
+
key_fetcher.shutdown()
|
|
204
|
+
|
|
197
205
|
async def verify_json_for_server(
|
|
198
206
|
self,
|
|
199
207
|
server_name: str,
|
|
@@ -316,7 +324,7 @@ class Keyring:
|
|
|
316
324
|
if key_result.valid_until_ts < verify_request.minimum_valid_until_ts:
|
|
317
325
|
continue
|
|
318
326
|
|
|
319
|
-
await self.
|
|
327
|
+
await self.process_json(key_result.verify_key, verify_request)
|
|
320
328
|
verified = True
|
|
321
329
|
|
|
322
330
|
if not verified:
|
|
@@ -326,7 +334,7 @@ class Keyring:
|
|
|
326
334
|
Codes.UNAUTHORIZED,
|
|
327
335
|
)
|
|
328
336
|
|
|
329
|
-
async def
|
|
337
|
+
async def process_json(
|
|
330
338
|
self, verify_key: VerifyKey, verify_request: VerifyJsonRequest
|
|
331
339
|
) -> None:
|
|
332
340
|
"""Processes the `VerifyJsonRequest`. Raises if the signature can't be
|
|
@@ -479,11 +487,17 @@ class KeyFetcher(metaclass=abc.ABCMeta):
|
|
|
479
487
|
self.server_name = hs.hostname
|
|
480
488
|
self._queue = BatchingQueue(
|
|
481
489
|
name=self.__class__.__name__,
|
|
482
|
-
|
|
490
|
+
hs=hs,
|
|
483
491
|
clock=hs.get_clock(),
|
|
484
492
|
process_batch_callback=self._fetch_keys,
|
|
485
493
|
)
|
|
486
494
|
|
|
495
|
+
def shutdown(self) -> None:
|
|
496
|
+
"""
|
|
497
|
+
Prepares the KeyFetcher for garbage collection by shutting down it's queue.
|
|
498
|
+
"""
|
|
499
|
+
self._queue.shutdown()
|
|
500
|
+
|
|
487
501
|
async def get_keys(
|
|
488
502
|
self, server_name: str, key_ids: List[str], minimum_valid_until_ts: int
|
|
489
503
|
) -> Dict[str, FetchKeyResult]:
|
|
@@ -148,6 +148,7 @@ class FederationClient(FederationBase):
|
|
|
148
148
|
self._get_pdu_cache: ExpiringCache[str, Tuple[EventBase, str]] = ExpiringCache(
|
|
149
149
|
cache_name="get_pdu_cache",
|
|
150
150
|
server_name=self.server_name,
|
|
151
|
+
hs=self.hs,
|
|
151
152
|
clock=self._clock,
|
|
152
153
|
max_len=1000,
|
|
153
154
|
expiry_ms=120 * 1000,
|
|
@@ -167,6 +168,7 @@ class FederationClient(FederationBase):
|
|
|
167
168
|
] = ExpiringCache(
|
|
168
169
|
cache_name="get_room_hierarchy_cache",
|
|
169
170
|
server_name=self.server_name,
|
|
171
|
+
hs=self.hs,
|
|
170
172
|
clock=self._clock,
|
|
171
173
|
max_len=1000,
|
|
172
174
|
expiry_ms=5 * 60 * 1000,
|
|
@@ -495,6 +497,43 @@ class FederationClient(FederationBase):
|
|
|
495
497
|
)
|
|
496
498
|
return RECOMMENDATION_OK
|
|
497
499
|
|
|
500
|
+
@trace
|
|
501
|
+
@tag_args
|
|
502
|
+
async def ask_policy_server_to_sign_event(
|
|
503
|
+
self, destination: str, pdu: EventBase, timeout: Optional[int] = None
|
|
504
|
+
) -> Optional[JsonDict]:
|
|
505
|
+
"""Requests that the destination server (typically a policy server)
|
|
506
|
+
sign the event as not spam.
|
|
507
|
+
|
|
508
|
+
If the policy server could not be contacted or the policy server
|
|
509
|
+
returned an error, this returns no signature.
|
|
510
|
+
|
|
511
|
+
Args:
|
|
512
|
+
destination: The remote homeserver to ask (a policy server)
|
|
513
|
+
pdu: The event to sign
|
|
514
|
+
timeout: How long to try (in ms) the destination for before
|
|
515
|
+
giving up. None indicates no timeout.
|
|
516
|
+
Returns:
|
|
517
|
+
The signature from the policy server, structured in the same was as the 'signatures'
|
|
518
|
+
JSON in the event e.g { "$policy_server_via_domain" : { "ed25519:policy_server": "signature_base64" }}
|
|
519
|
+
"""
|
|
520
|
+
logger.debug(
|
|
521
|
+
"ask_policy_server_to_sign_event for event_id=%s from %s",
|
|
522
|
+
pdu.event_id,
|
|
523
|
+
destination,
|
|
524
|
+
)
|
|
525
|
+
try:
|
|
526
|
+
return await self.transport_layer.ask_policy_server_to_sign_event(
|
|
527
|
+
destination, pdu, timeout=timeout
|
|
528
|
+
)
|
|
529
|
+
except Exception as e:
|
|
530
|
+
logger.warning(
|
|
531
|
+
"ask_policy_server_to_sign_event: server %s responded with error: %s",
|
|
532
|
+
destination,
|
|
533
|
+
e,
|
|
534
|
+
)
|
|
535
|
+
return None
|
|
536
|
+
|
|
498
537
|
@trace
|
|
499
538
|
@tag_args
|
|
500
539
|
async def get_pdu(
|
|
@@ -159,7 +159,7 @@ class FederationServer(FederationBase):
|
|
|
159
159
|
# with FederationHandlerRegistry.
|
|
160
160
|
hs.get_directory_handler()
|
|
161
161
|
|
|
162
|
-
self._server_linearizer = Linearizer("fed_server")
|
|
162
|
+
self._server_linearizer = Linearizer(name="fed_server", clock=hs.get_clock())
|
|
163
163
|
|
|
164
164
|
# origins that we are currently processing a transaction from.
|
|
165
165
|
# a dict from origin to txn id.
|
synapse/federation/send_queue.py
CHANGED
|
@@ -144,6 +144,9 @@ class FederationRemoteSendQueue(AbstractFederationSender):
|
|
|
144
144
|
|
|
145
145
|
self.clock.looping_call(self._clear_queue, 30 * 1000)
|
|
146
146
|
|
|
147
|
+
def shutdown(self) -> None:
|
|
148
|
+
"""Stops this federation sender instance from sending further transactions."""
|
|
149
|
+
|
|
147
150
|
def _next_pos(self) -> int:
|
|
148
151
|
pos = self.pos
|
|
149
152
|
self.pos += 1
|
|
@@ -168,7 +168,6 @@ from synapse.metrics import (
|
|
|
168
168
|
events_processed_counter,
|
|
169
169
|
)
|
|
170
170
|
from synapse.metrics.background_process_metrics import (
|
|
171
|
-
run_as_background_process,
|
|
172
171
|
wrap_as_background_process,
|
|
173
172
|
)
|
|
174
173
|
from synapse.types import (
|
|
@@ -232,6 +231,11 @@ WAKEUP_INTERVAL_BETWEEN_DESTINATIONS_SEC = 5
|
|
|
232
231
|
|
|
233
232
|
|
|
234
233
|
class AbstractFederationSender(metaclass=abc.ABCMeta):
|
|
234
|
+
@abc.abstractmethod
|
|
235
|
+
def shutdown(self) -> None:
|
|
236
|
+
"""Stops this federation sender instance from sending further transactions."""
|
|
237
|
+
raise NotImplementedError()
|
|
238
|
+
|
|
235
239
|
@abc.abstractmethod
|
|
236
240
|
def notify_new_events(self, max_token: RoomStreamToken) -> None:
|
|
237
241
|
"""This gets called when we have some new events we might want to
|
|
@@ -326,6 +330,7 @@ class _DestinationWakeupQueue:
|
|
|
326
330
|
_MAX_TIME_IN_QUEUE = 30.0
|
|
327
331
|
|
|
328
332
|
sender: "FederationSender" = attr.ib()
|
|
333
|
+
hs: "HomeServer" = attr.ib()
|
|
329
334
|
server_name: str = attr.ib()
|
|
330
335
|
"""
|
|
331
336
|
Our homeserver name (used to label metrics) (`hs.hostname`).
|
|
@@ -453,18 +458,30 @@ class FederationSender(AbstractFederationSender):
|
|
|
453
458
|
1.0 / hs.config.ratelimiting.federation_rr_transactions_per_room_per_second
|
|
454
459
|
)
|
|
455
460
|
self._destination_wakeup_queue = _DestinationWakeupQueue(
|
|
456
|
-
self,
|
|
461
|
+
self,
|
|
462
|
+
hs,
|
|
463
|
+
self.server_name,
|
|
464
|
+
self.clock,
|
|
465
|
+
max_delay_s=rr_txn_interval_per_room_s,
|
|
457
466
|
)
|
|
458
467
|
|
|
468
|
+
# It is important for `_is_shutdown` to be instantiated before the looping call
|
|
469
|
+
# for `wake_destinations_needing_catchup`.
|
|
470
|
+
self._is_shutdown = False
|
|
471
|
+
|
|
459
472
|
# Regularly wake up destinations that have outstanding PDUs to be caught up
|
|
460
473
|
self.clock.looping_call_now(
|
|
461
|
-
run_as_background_process,
|
|
474
|
+
self.hs.run_as_background_process,
|
|
462
475
|
WAKEUP_RETRY_PERIOD_SEC * 1000.0,
|
|
463
476
|
"wake_destinations_needing_catchup",
|
|
464
|
-
self.server_name,
|
|
465
477
|
self._wake_destinations_needing_catchup,
|
|
466
478
|
)
|
|
467
479
|
|
|
480
|
+
def shutdown(self) -> None:
|
|
481
|
+
self._is_shutdown = True
|
|
482
|
+
for queue in self._per_destination_queues.values():
|
|
483
|
+
queue.shutdown()
|
|
484
|
+
|
|
468
485
|
def _get_per_destination_queue(
|
|
469
486
|
self, destination: str
|
|
470
487
|
) -> Optional[PerDestinationQueue]:
|
|
@@ -503,16 +520,15 @@ class FederationSender(AbstractFederationSender):
|
|
|
503
520
|
return
|
|
504
521
|
|
|
505
522
|
# fire off a processing loop in the background
|
|
506
|
-
run_as_background_process(
|
|
523
|
+
self.hs.run_as_background_process(
|
|
507
524
|
"process_event_queue_for_federation",
|
|
508
|
-
self.server_name,
|
|
509
525
|
self._process_event_queue_loop,
|
|
510
526
|
)
|
|
511
527
|
|
|
512
528
|
async def _process_event_queue_loop(self) -> None:
|
|
513
529
|
try:
|
|
514
530
|
self._is_processing = True
|
|
515
|
-
while
|
|
531
|
+
while not self._is_shutdown:
|
|
516
532
|
last_token = await self.store.get_federation_out_pos("events")
|
|
517
533
|
(
|
|
518
534
|
next_token,
|
|
@@ -1123,7 +1139,7 @@ class FederationSender(AbstractFederationSender):
|
|
|
1123
1139
|
|
|
1124
1140
|
last_processed: Optional[str] = None
|
|
1125
1141
|
|
|
1126
|
-
while
|
|
1142
|
+
while not self._is_shutdown:
|
|
1127
1143
|
destinations_to_wake = (
|
|
1128
1144
|
await self.store.get_catch_up_outstanding_destinations(last_processed)
|
|
1129
1145
|
)
|
|
@@ -28,6 +28,8 @@ from typing import TYPE_CHECKING, Dict, Hashable, Iterable, List, Optional, Tupl
|
|
|
28
28
|
import attr
|
|
29
29
|
from prometheus_client import Counter
|
|
30
30
|
|
|
31
|
+
from twisted.internet import defer
|
|
32
|
+
|
|
31
33
|
from synapse.api.constants import EduTypes
|
|
32
34
|
from synapse.api.errors import (
|
|
33
35
|
FederationDeniedError,
|
|
@@ -41,7 +43,6 @@ from synapse.handlers.presence import format_user_presence_state
|
|
|
41
43
|
from synapse.logging import issue9533_logger
|
|
42
44
|
from synapse.logging.opentracing import SynapseTags, set_tag
|
|
43
45
|
from synapse.metrics import SERVER_NAME_LABEL, sent_transactions_counter
|
|
44
|
-
from synapse.metrics.background_process_metrics import run_as_background_process
|
|
45
46
|
from synapse.types import JsonDict, ReadReceipt
|
|
46
47
|
from synapse.util.retryutils import NotRetryingDestination, get_retry_limiter
|
|
47
48
|
from synapse.visibility import filter_events_for_server
|
|
@@ -79,6 +80,7 @@ MAX_PRESENCE_STATES_PER_EDU = 50
|
|
|
79
80
|
class PerDestinationQueue:
|
|
80
81
|
"""
|
|
81
82
|
Manages the per-destination transmission queues.
|
|
83
|
+
Runs until `shutdown()` is called on the queue.
|
|
82
84
|
|
|
83
85
|
Args:
|
|
84
86
|
hs
|
|
@@ -94,6 +96,7 @@ class PerDestinationQueue:
|
|
|
94
96
|
destination: str,
|
|
95
97
|
):
|
|
96
98
|
self.server_name = hs.hostname
|
|
99
|
+
self._hs = hs
|
|
97
100
|
self._clock = hs.get_clock()
|
|
98
101
|
self._storage_controllers = hs.get_storage_controllers()
|
|
99
102
|
self._store = hs.get_datastores().main
|
|
@@ -117,6 +120,8 @@ class PerDestinationQueue:
|
|
|
117
120
|
|
|
118
121
|
self._destination = destination
|
|
119
122
|
self.transmission_loop_running = False
|
|
123
|
+
self._transmission_loop_enabled = True
|
|
124
|
+
self.active_transmission_loop: Optional[defer.Deferred] = None
|
|
120
125
|
|
|
121
126
|
# Flag to signal to any running transmission loop that there is new data
|
|
122
127
|
# queued up to be sent.
|
|
@@ -171,6 +176,20 @@ class PerDestinationQueue:
|
|
|
171
176
|
def __str__(self) -> str:
|
|
172
177
|
return "PerDestinationQueue[%s]" % self._destination
|
|
173
178
|
|
|
179
|
+
def shutdown(self) -> None:
|
|
180
|
+
"""Instruct the queue to stop processing any further requests"""
|
|
181
|
+
self._transmission_loop_enabled = False
|
|
182
|
+
# The transaction manager must be shutdown before cancelling the active
|
|
183
|
+
# transmission loop. Otherwise the transmission loop can enter a new cycle of
|
|
184
|
+
# sleeping before retrying since the shutdown flag of the _transaction_manager
|
|
185
|
+
# hasn't been set yet.
|
|
186
|
+
self._transaction_manager.shutdown()
|
|
187
|
+
try:
|
|
188
|
+
if self.active_transmission_loop is not None:
|
|
189
|
+
self.active_transmission_loop.cancel()
|
|
190
|
+
except Exception:
|
|
191
|
+
pass
|
|
192
|
+
|
|
174
193
|
def pending_pdu_count(self) -> int:
|
|
175
194
|
return len(self._pending_pdus)
|
|
176
195
|
|
|
@@ -309,11 +328,14 @@ class PerDestinationQueue:
|
|
|
309
328
|
)
|
|
310
329
|
return
|
|
311
330
|
|
|
331
|
+
if not self._transmission_loop_enabled:
|
|
332
|
+
logger.warning("Shutdown has been requested. Not sending transaction")
|
|
333
|
+
return
|
|
334
|
+
|
|
312
335
|
logger.debug("TX [%s] Starting transaction loop", self._destination)
|
|
313
336
|
|
|
314
|
-
run_as_background_process(
|
|
337
|
+
self.active_transmission_loop = self._hs.run_as_background_process(
|
|
315
338
|
"federation_transaction_transmission_loop",
|
|
316
|
-
self.server_name,
|
|
317
339
|
self._transaction_transmission_loop,
|
|
318
340
|
)
|
|
319
341
|
|
|
@@ -321,13 +343,13 @@ class PerDestinationQueue:
|
|
|
321
343
|
pending_pdus: List[EventBase] = []
|
|
322
344
|
try:
|
|
323
345
|
self.transmission_loop_running = True
|
|
324
|
-
|
|
325
346
|
# This will throw if we wouldn't retry. We do this here so we fail
|
|
326
347
|
# quickly, but we will later check this again in the http client,
|
|
327
348
|
# hence why we throw the result away.
|
|
328
349
|
await get_retry_limiter(
|
|
329
350
|
destination=self._destination,
|
|
330
351
|
our_server_name=self.server_name,
|
|
352
|
+
hs=self._hs,
|
|
331
353
|
clock=self._clock,
|
|
332
354
|
store=self._store,
|
|
333
355
|
)
|
|
@@ -339,7 +361,7 @@ class PerDestinationQueue:
|
|
|
339
361
|
# not caught up yet
|
|
340
362
|
return
|
|
341
363
|
|
|
342
|
-
while
|
|
364
|
+
while self._transmission_loop_enabled:
|
|
343
365
|
self._new_data_to_send = False
|
|
344
366
|
|
|
345
367
|
async with _TransactionQueueManager(self) as (
|
|
@@ -352,8 +374,8 @@ class PerDestinationQueue:
|
|
|
352
374
|
# If we've gotten told about new things to send during
|
|
353
375
|
# checking for things to send, we try looking again.
|
|
354
376
|
# Otherwise new PDUs or EDUs might arrive in the meantime,
|
|
355
|
-
# but not get sent because we
|
|
356
|
-
# `
|
|
377
|
+
# but not get sent because we currently have an
|
|
378
|
+
# `_active_transmission_loop` running.
|
|
357
379
|
if self._new_data_to_send:
|
|
358
380
|
continue
|
|
359
381
|
else:
|
|
@@ -442,6 +464,7 @@ class PerDestinationQueue:
|
|
|
442
464
|
)
|
|
443
465
|
finally:
|
|
444
466
|
# We want to be *very* sure we clear this after we stop processing
|
|
467
|
+
self.active_transmission_loop = None
|
|
445
468
|
self.transmission_loop_running = False
|
|
446
469
|
|
|
447
470
|
async def _catch_up_transmission_loop(self) -> None:
|
|
@@ -469,7 +492,7 @@ class PerDestinationQueue:
|
|
|
469
492
|
last_successful_stream_ordering: int = _tmp_last_successful_stream_ordering
|
|
470
493
|
|
|
471
494
|
# get at most 50 catchup room/PDUs
|
|
472
|
-
while
|
|
495
|
+
while self._transmission_loop_enabled:
|
|
473
496
|
event_ids = await self._store.get_catch_up_room_event_ids(
|
|
474
497
|
self._destination, last_successful_stream_ordering
|
|
475
498
|
)
|
|
@@ -72,6 +72,12 @@ class TransactionManager:
|
|
|
72
72
|
# HACK to get unique tx id
|
|
73
73
|
self._next_txn_id = int(self.clock.time_msec())
|
|
74
74
|
|
|
75
|
+
self._is_shutdown = False
|
|
76
|
+
|
|
77
|
+
def shutdown(self) -> None:
|
|
78
|
+
self._is_shutdown = True
|
|
79
|
+
self._transport_layer.shutdown()
|
|
80
|
+
|
|
75
81
|
@measure_func("_send_new_transaction")
|
|
76
82
|
async def send_new_transaction(
|
|
77
83
|
self,
|
|
@@ -86,6 +92,12 @@ class TransactionManager:
|
|
|
86
92
|
edus: List of EDUs to send
|
|
87
93
|
"""
|
|
88
94
|
|
|
95
|
+
if self._is_shutdown:
|
|
96
|
+
logger.warning(
|
|
97
|
+
"TransactionManager has been shutdown, not sending transaction"
|
|
98
|
+
)
|
|
99
|
+
return
|
|
100
|
+
|
|
89
101
|
# Make a transaction-sending opentracing span. This span follows on from
|
|
90
102
|
# all the edus in that transaction. This needs to be done since there is
|
|
91
103
|
# no active span here, so if the edus were not received by the remote the
|
|
@@ -70,6 +70,9 @@ class TransportLayerClient:
|
|
|
70
70
|
self.client = hs.get_federation_http_client()
|
|
71
71
|
self._is_mine_server_name = hs.is_mine_server_name
|
|
72
72
|
|
|
73
|
+
def shutdown(self) -> None:
|
|
74
|
+
self.client.shutdown()
|
|
75
|
+
|
|
73
76
|
async def get_room_state_ids(
|
|
74
77
|
self, destination: str, room_id: str, event_id: str
|
|
75
78
|
) -> JsonDict:
|
|
@@ -170,6 +173,32 @@ class TransportLayerClient:
|
|
|
170
173
|
timeout=timeout,
|
|
171
174
|
)
|
|
172
175
|
|
|
176
|
+
async def ask_policy_server_to_sign_event(
|
|
177
|
+
self, destination: str, event: EventBase, timeout: Optional[int] = None
|
|
178
|
+
) -> JsonDict:
|
|
179
|
+
"""Requests that the destination server (typically a policy server)
|
|
180
|
+
sign the event as not spam.
|
|
181
|
+
|
|
182
|
+
If the policy server could not be contacted or the policy server
|
|
183
|
+
returned an error, this raises that error.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
destination: The host name of the policy server / homeserver.
|
|
187
|
+
event: The event to sign.
|
|
188
|
+
timeout: How long to try (in ms) the destination for before giving up.
|
|
189
|
+
None indicates no timeout.
|
|
190
|
+
Returns:
|
|
191
|
+
The signature from the policy server, structured in the same was as the 'signatures'
|
|
192
|
+
JSON in the event e.g { "$policy_server_via_domain" : { "ed25519:policy_server": "signature_base64" }}
|
|
193
|
+
"""
|
|
194
|
+
return await self.client.post_json(
|
|
195
|
+
destination=destination,
|
|
196
|
+
path="/_matrix/policy/unstable/org.matrix.msc4284/sign",
|
|
197
|
+
data=event.get_pdu_json(),
|
|
198
|
+
ignore_backoff=True,
|
|
199
|
+
timeout=timeout,
|
|
200
|
+
)
|
|
201
|
+
|
|
173
202
|
async def backfill(
|
|
174
203
|
self, destination: str, room_id: str, event_tuples: Collection[str], limit: int
|
|
175
204
|
) -> Optional[Union[JsonDict, list]]:
|
|
@@ -37,10 +37,8 @@ logger = logging.getLogger(__name__)
|
|
|
37
37
|
|
|
38
38
|
class AccountValidityHandler:
|
|
39
39
|
def __init__(self, hs: "HomeServer"):
|
|
40
|
-
self.hs = hs
|
|
41
|
-
self.server_name =
|
|
42
|
-
hs.hostname
|
|
43
|
-
) # nb must be called this for @wrap_as_background_process
|
|
40
|
+
self.hs = hs # nb must be called this for @wrap_as_background_process
|
|
41
|
+
self.server_name = hs.hostname
|
|
44
42
|
self.config = hs.config
|
|
45
43
|
self.store = hs.get_datastores().main
|
|
46
44
|
self.send_email_handler = hs.get_send_email_handler()
|
synapse/handlers/appservice.py
CHANGED
|
@@ -47,7 +47,6 @@ from synapse.metrics import (
|
|
|
47
47
|
event_processing_loop_room_count,
|
|
48
48
|
)
|
|
49
49
|
from synapse.metrics.background_process_metrics import (
|
|
50
|
-
run_as_background_process,
|
|
51
50
|
wrap_as_background_process,
|
|
52
51
|
)
|
|
53
52
|
from synapse.storage.databases.main.directory import RoomAliasMapping
|
|
@@ -76,9 +75,8 @@ events_processed_counter = Counter(
|
|
|
76
75
|
|
|
77
76
|
class ApplicationServicesHandler:
|
|
78
77
|
def __init__(self, hs: "HomeServer"):
|
|
79
|
-
self.server_name =
|
|
80
|
-
|
|
81
|
-
) # nb must be called this for @wrap_as_background_process
|
|
78
|
+
self.server_name = hs.hostname
|
|
79
|
+
self.hs = hs # nb must be called this for @wrap_as_background_process
|
|
82
80
|
self.store = hs.get_datastores().main
|
|
83
81
|
self.is_mine_id = hs.is_mine_id
|
|
84
82
|
self.appservice_api = hs.get_application_service_api()
|
|
@@ -98,7 +96,7 @@ class ApplicationServicesHandler:
|
|
|
98
96
|
self.is_processing = False
|
|
99
97
|
|
|
100
98
|
self._ephemeral_events_linearizer = Linearizer(
|
|
101
|
-
name="appservice_ephemeral_events"
|
|
99
|
+
name="appservice_ephemeral_events", clock=hs.get_clock()
|
|
102
100
|
)
|
|
103
101
|
|
|
104
102
|
def notify_interested_services(self, max_token: RoomStreamToken) -> None:
|
|
@@ -171,8 +169,8 @@ class ApplicationServicesHandler:
|
|
|
171
169
|
except Exception:
|
|
172
170
|
logger.error("Application Services Failure")
|
|
173
171
|
|
|
174
|
-
run_as_background_process(
|
|
175
|
-
"as_scheduler",
|
|
172
|
+
self.hs.run_as_background_process(
|
|
173
|
+
"as_scheduler", start_scheduler
|
|
176
174
|
)
|
|
177
175
|
self.started_scheduler = True
|
|
178
176
|
|
|
@@ -24,7 +24,6 @@ from typing import TYPE_CHECKING, Optional
|
|
|
24
24
|
|
|
25
25
|
from synapse.api.constants import Membership
|
|
26
26
|
from synapse.api.errors import SynapseError
|
|
27
|
-
from synapse.metrics.background_process_metrics import run_as_background_process
|
|
28
27
|
from synapse.replication.http.deactivate_account import (
|
|
29
28
|
ReplicationNotifyAccountDeactivatedServlet,
|
|
30
29
|
)
|
|
@@ -272,8 +271,8 @@ class DeactivateAccountHandler:
|
|
|
272
271
|
pending deactivation, if it isn't already running.
|
|
273
272
|
"""
|
|
274
273
|
if not self._user_parter_running:
|
|
275
|
-
run_as_background_process(
|
|
276
|
-
"user_parter_loop", self.
|
|
274
|
+
self.hs.run_as_background_process(
|
|
275
|
+
"user_parter_loop", self._user_parter_loop
|
|
277
276
|
)
|
|
278
277
|
|
|
279
278
|
async def _user_parter_loop(self) -> None:
|