matrix-synapse 1.139.2__cp39-abi3-manylinux_2_28_aarch64.whl → 1.140.0rc1__cp39-abi3-manylinux_2_28_aarch64.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.

Files changed (158) hide show
  1. {matrix_synapse-1.139.2.dist-info → matrix_synapse-1.140.0rc1.dist-info}/METADATA +5 -3
  2. {matrix_synapse-1.139.2.dist-info → matrix_synapse-1.140.0rc1.dist-info}/RECORD +157 -154
  3. synapse/_scripts/generate_workers_map.py +6 -1
  4. synapse/_scripts/synapse_port_db.py +0 -2
  5. synapse/_scripts/update_synapse_database.py +1 -6
  6. synapse/api/auth/base.py +1 -3
  7. synapse/api/auth/mas.py +6 -8
  8. synapse/api/auth/msc3861_delegated.py +6 -8
  9. synapse/api/errors.py +3 -0
  10. synapse/app/_base.py +101 -39
  11. synapse/app/admin_cmd.py +2 -4
  12. synapse/app/appservice.py +1 -1
  13. synapse/app/client_reader.py +1 -1
  14. synapse/app/event_creator.py +1 -1
  15. synapse/app/federation_reader.py +1 -1
  16. synapse/app/federation_sender.py +1 -1
  17. synapse/app/frontend_proxy.py +1 -1
  18. synapse/app/generic_worker.py +17 -11
  19. synapse/app/homeserver.py +85 -47
  20. synapse/app/media_repository.py +1 -1
  21. synapse/app/phone_stats_home.py +16 -14
  22. synapse/app/pusher.py +1 -1
  23. synapse/app/synchrotron.py +1 -1
  24. synapse/app/user_dir.py +1 -1
  25. synapse/appservice/__init__.py +29 -2
  26. synapse/appservice/scheduler.py +8 -8
  27. synapse/config/_base.py +32 -14
  28. synapse/config/_base.pyi +5 -3
  29. synapse/config/experimental.py +3 -0
  30. synapse/config/homeserver.py +27 -1
  31. synapse/config/logger.py +3 -4
  32. synapse/config/matrixrtc.py +67 -0
  33. synapse/crypto/keyring.py +18 -4
  34. synapse/events/auto_accept_invites.py +0 -1
  35. synapse/federation/federation_client.py +39 -0
  36. synapse/federation/federation_server.py +1 -1
  37. synapse/federation/send_queue.py +3 -0
  38. synapse/federation/sender/__init__.py +24 -8
  39. synapse/federation/sender/per_destination_queue.py +31 -8
  40. synapse/federation/sender/transaction_manager.py +12 -0
  41. synapse/federation/transport/client.py +29 -0
  42. synapse/handlers/account_validity.py +2 -4
  43. synapse/handlers/appservice.py +5 -7
  44. synapse/handlers/deactivate_account.py +2 -3
  45. synapse/handlers/delayed_events.py +10 -13
  46. synapse/handlers/device.py +14 -14
  47. synapse/handlers/e2e_keys.py +4 -3
  48. synapse/handlers/federation.py +7 -11
  49. synapse/handlers/federation_event.py +5 -6
  50. synapse/handlers/message.py +16 -10
  51. synapse/handlers/pagination.py +3 -7
  52. synapse/handlers/presence.py +21 -25
  53. synapse/handlers/profile.py +1 -1
  54. synapse/handlers/read_marker.py +3 -1
  55. synapse/handlers/register.py +8 -1
  56. synapse/handlers/room.py +13 -4
  57. synapse/handlers/room_member.py +11 -7
  58. synapse/handlers/room_policy.py +96 -2
  59. synapse/handlers/sso.py +1 -1
  60. synapse/handlers/stats.py +5 -3
  61. synapse/handlers/sync.py +20 -13
  62. synapse/handlers/typing.py +5 -10
  63. synapse/handlers/user_directory.py +12 -11
  64. synapse/handlers/worker_lock.py +19 -15
  65. synapse/http/client.py +18 -13
  66. synapse/http/federation/matrix_federation_agent.py +6 -1
  67. synapse/http/federation/well_known_resolver.py +3 -1
  68. synapse/http/matrixfederationclient.py +50 -11
  69. synapse/http/proxy.py +2 -2
  70. synapse/http/server.py +36 -2
  71. synapse/http/site.py +109 -17
  72. synapse/logging/context.py +165 -63
  73. synapse/logging/opentracing.py +30 -6
  74. synapse/logging/scopecontextmanager.py +161 -0
  75. synapse/media/_base.py +2 -1
  76. synapse/media/media_repository.py +20 -6
  77. synapse/media/url_previewer.py +5 -6
  78. synapse/metrics/_gc.py +3 -1
  79. synapse/metrics/background_process_metrics.py +128 -24
  80. synapse/metrics/common_usage_metrics.py +3 -5
  81. synapse/module_api/__init__.py +42 -5
  82. synapse/notifier.py +10 -3
  83. synapse/push/emailpusher.py +5 -4
  84. synapse/push/httppusher.py +6 -6
  85. synapse/push/pusherpool.py +3 -8
  86. synapse/replication/http/devices.py +0 -41
  87. synapse/replication/tcp/client.py +8 -5
  88. synapse/replication/tcp/handler.py +2 -3
  89. synapse/replication/tcp/protocol.py +14 -7
  90. synapse/replication/tcp/redis.py +16 -11
  91. synapse/replication/tcp/resource.py +5 -4
  92. synapse/replication/tcp/streams/__init__.py +2 -0
  93. synapse/res/providers.json +6 -5
  94. synapse/rest/__init__.py +2 -0
  95. synapse/rest/admin/__init__.py +4 -0
  96. synapse/rest/admin/events.py +69 -0
  97. synapse/rest/admin/media.py +70 -2
  98. synapse/rest/client/matrixrtc.py +52 -0
  99. synapse/rest/client/push_rule.py +1 -1
  100. synapse/rest/client/room.py +2 -3
  101. synapse/rest/client/sync.py +1 -0
  102. synapse/rest/client/transactions.py +1 -1
  103. synapse/server.py +271 -38
  104. synapse/server_notices/server_notices_manager.py +1 -0
  105. synapse/state/__init__.py +4 -1
  106. synapse/storage/_base.py +1 -1
  107. synapse/storage/background_updates.py +8 -3
  108. synapse/storage/controllers/persist_events.py +4 -3
  109. synapse/storage/controllers/purge_events.py +2 -3
  110. synapse/storage/controllers/state.py +5 -5
  111. synapse/storage/database.py +12 -7
  112. synapse/storage/databases/main/__init__.py +7 -2
  113. synapse/storage/databases/main/cache.py +4 -3
  114. synapse/storage/databases/main/censor_events.py +1 -1
  115. synapse/storage/databases/main/client_ips.py +9 -8
  116. synapse/storage/databases/main/deviceinbox.py +7 -6
  117. synapse/storage/databases/main/devices.py +4 -4
  118. synapse/storage/databases/main/end_to_end_keys.py +6 -3
  119. synapse/storage/databases/main/event_federation.py +7 -6
  120. synapse/storage/databases/main/event_push_actions.py +13 -13
  121. synapse/storage/databases/main/events_bg_updates.py +1 -1
  122. synapse/storage/databases/main/events_worker.py +6 -8
  123. synapse/storage/databases/main/lock.py +17 -13
  124. synapse/storage/databases/main/media_repository.py +2 -2
  125. synapse/storage/databases/main/metrics.py +6 -6
  126. synapse/storage/databases/main/monthly_active_users.py +3 -4
  127. synapse/storage/databases/main/receipts.py +1 -1
  128. synapse/storage/databases/main/registration.py +18 -19
  129. synapse/storage/databases/main/roommember.py +1 -1
  130. synapse/storage/databases/main/session.py +3 -3
  131. synapse/storage/databases/main/sliding_sync.py +2 -2
  132. synapse/storage/databases/main/transactions.py +3 -3
  133. synapse/storage/databases/state/store.py +2 -0
  134. synapse/synapse_rust/http_client.pyi +4 -0
  135. synapse/synapse_rust.abi3.so +0 -0
  136. synapse/util/async_helpers.py +36 -24
  137. synapse/util/batching_queue.py +16 -6
  138. synapse/util/caches/__init__.py +1 -1
  139. synapse/util/caches/deferred_cache.py +4 -0
  140. synapse/util/caches/descriptors.py +14 -2
  141. synapse/util/caches/dictionary_cache.py +6 -1
  142. synapse/util/caches/expiringcache.py +16 -5
  143. synapse/util/caches/lrucache.py +14 -26
  144. synapse/util/caches/response_cache.py +11 -1
  145. synapse/util/clock.py +215 -39
  146. synapse/util/constants.py +2 -0
  147. synapse/util/daemonize.py +5 -1
  148. synapse/util/distributor.py +9 -5
  149. synapse/util/metrics.py +35 -6
  150. synapse/util/ratelimitutils.py +4 -1
  151. synapse/util/retryutils.py +7 -4
  152. synapse/util/task_scheduler.py +11 -14
  153. synapse/logging/filter.py +0 -38
  154. {matrix_synapse-1.139.2.dist-info → matrix_synapse-1.140.0rc1.dist-info}/AUTHORS.rst +0 -0
  155. {matrix_synapse-1.139.2.dist-info → matrix_synapse-1.140.0rc1.dist-info}/LICENSE-AGPL-3.0 +0 -0
  156. {matrix_synapse-1.139.2.dist-info → matrix_synapse-1.140.0rc1.dist-info}/LICENSE-COMMERCIAL +0 -0
  157. {matrix_synapse-1.139.2.dist-info → matrix_synapse-1.140.0rc1.dist-info}/WHEEL +0 -0
  158. {matrix_synapse-1.139.2.dist-info → matrix_synapse-1.140.0rc1.dist-info}/entry_points.txt +0 -0
@@ -17,6 +17,11 @@
17
17
  import logging
18
18
  from typing import TYPE_CHECKING
19
19
 
20
+ from signedjson.key import decode_verify_key_bytes
21
+ from unpaddedbase64 import decode_base64
22
+
23
+ from synapse.api.errors import SynapseError
24
+ from synapse.crypto.keyring import VerifyJsonRequest
20
25
  from synapse.events import EventBase
21
26
  from synapse.types.handlers.policy_server import RECOMMENDATION_OK
22
27
  from synapse.util.stringutils import parse_and_validate_server_name
@@ -26,6 +31,9 @@ if TYPE_CHECKING:
26
31
 
27
32
  logger = logging.getLogger(__name__)
28
33
 
34
+ POLICY_SERVER_EVENT_TYPE = "org.matrix.msc4284.policy"
35
+ POLICY_SERVER_KEY_ID = "ed25519:policy_server"
36
+
29
37
 
30
38
  class RoomPolicyHandler:
31
39
  def __init__(self, hs: "HomeServer"):
@@ -54,11 +62,11 @@ class RoomPolicyHandler:
54
62
  Returns:
55
63
  bool: True if the event is allowed in the room, False otherwise.
56
64
  """
57
- if event.type == "org.matrix.msc4284.policy" and event.state_key is not None:
65
+ if event.type == POLICY_SERVER_EVENT_TYPE and event.state_key is not None:
58
66
  return True # always allow policy server change events
59
67
 
60
68
  policy_event = await self._storage_controllers.state.get_current_state_event(
61
- event.room_id, "org.matrix.msc4284.policy", ""
69
+ event.room_id, POLICY_SERVER_EVENT_TYPE, ""
62
70
  )
63
71
  if not policy_event:
64
72
  return True # no policy server == default allow
@@ -81,6 +89,22 @@ class RoomPolicyHandler:
81
89
  if not is_in_room:
82
90
  return True # policy server not in room == default allow
83
91
 
92
+ # Check if the event has been signed with the public key in the policy server state event.
93
+ # If it is, we can save an HTTP hit.
94
+ # We actually want to get the policy server state event BEFORE THE EVENT rather than
95
+ # the current state value, else changing the public key will cause all of these checks to fail.
96
+ # However, if we are checking outlier events (which we will due to is_event_allowed being called
97
+ # near the edges at _check_sigs_and_hash) we won't know the state before the event, so the
98
+ # only safe option is to use the current state
99
+ public_key = policy_event.content.get("public_key", None)
100
+ if public_key is not None and isinstance(public_key, str):
101
+ valid = await self._verify_policy_server_signature(
102
+ event, policy_server, public_key
103
+ )
104
+ if valid:
105
+ return True
106
+ # fallthrough to hit /check manually
107
+
84
108
  # At this point, the server appears valid and is in the room, so ask it to check
85
109
  # the event.
86
110
  recommendation = await self._federation_client.get_pdu_policy_recommendation(
@@ -90,3 +114,73 @@ class RoomPolicyHandler:
90
114
  return False
91
115
 
92
116
  return True # default allow
117
+
118
+ async def _verify_policy_server_signature(
119
+ self, event: EventBase, policy_server: str, public_key: str
120
+ ) -> bool:
121
+ # check the event is signed with this (via, public_key).
122
+ verify_json_req = VerifyJsonRequest.from_event(policy_server, event, 0)
123
+ try:
124
+ key_bytes = decode_base64(public_key)
125
+ verify_key = decode_verify_key_bytes(POLICY_SERVER_KEY_ID, key_bytes)
126
+ # We would normally use KeyRing.verify_event_for_server but we can't here as we don't
127
+ # want to fetch the server key, and instead want to use the public key in the state event.
128
+ await self._hs.get_keyring().process_json(verify_key, verify_json_req)
129
+ # if the event is correctly signed by the public key in the policy server state event = Allow
130
+ return True
131
+ except Exception as ex:
132
+ logger.warning(
133
+ "failed to verify event using public key in policy server event: %s", ex
134
+ )
135
+ return False
136
+
137
+ async def ask_policy_server_to_sign_event(
138
+ self, event: EventBase, verify: bool = False
139
+ ) -> None:
140
+ """Ask the policy server to sign this event. The signature is added to the event signatures block.
141
+
142
+ Does nothing if there is no policy server state event in the room. If the policy server
143
+ refuses to sign the event (as it's marked as spam) does nothing.
144
+
145
+ Args:
146
+ event: The event to sign
147
+ verify: If True, verify that the signature is correctly signed by the public_key in the
148
+ policy server state event.
149
+ Raises:
150
+ if verify=True and the policy server signed the event with an invalid signature. Does
151
+ not raise if the policy server refuses to sign the event.
152
+ """
153
+ policy_event = await self._storage_controllers.state.get_current_state_event(
154
+ event.room_id, POLICY_SERVER_EVENT_TYPE, ""
155
+ )
156
+ if not policy_event:
157
+ return
158
+ policy_server = policy_event.content.get("via", None)
159
+ if policy_server is None or not isinstance(policy_server, str):
160
+ return
161
+ # Only ask to sign events if the policy state event has a public_key (so they can be subsequently verified)
162
+ public_key = policy_event.content.get("public_key", None)
163
+ if public_key is None or not isinstance(public_key, str):
164
+ return
165
+
166
+ # Ask the policy server to sign this event.
167
+ # We set a smallish timeout here as we don't want to block event sending too long.
168
+ signature = await self._federation_client.ask_policy_server_to_sign_event(
169
+ policy_server,
170
+ event,
171
+ timeout=3000,
172
+ )
173
+ if (
174
+ # the policy server returns {} if it refuses to sign the event.
175
+ signature and len(signature) > 0
176
+ ):
177
+ event.signatures.update(signature)
178
+ if verify:
179
+ is_valid = await self._verify_policy_server_signature(
180
+ event, policy_server, public_key
181
+ )
182
+ if not is_valid:
183
+ raise SynapseError(
184
+ 500,
185
+ f"policy server {policy_server} failed to sign event correctly",
186
+ )
synapse/handlers/sso.py CHANGED
@@ -224,7 +224,7 @@ class SsoHandler:
224
224
  )
225
225
 
226
226
  # a lock on the mappings
227
- self._mapping_lock = Linearizer(name="sso_user_mapping", clock=hs.get_clock())
227
+ self._mapping_lock = Linearizer(clock=hs.get_clock(), name="sso_user_mapping")
228
228
 
229
229
  # a map from session id to session data
230
230
  self._username_mapping_sessions: Dict[str, UsernameMappingSession] = {}
synapse/handlers/stats.py CHANGED
@@ -33,7 +33,6 @@ from typing import (
33
33
 
34
34
  from synapse.api.constants import EventContentFields, EventTypes, Membership
35
35
  from synapse.metrics import SERVER_NAME_LABEL, event_processing_positions
36
- from synapse.metrics.background_process_metrics import run_as_background_process
37
36
  from synapse.storage.databases.main.state_deltas import StateDelta
38
37
  from synapse.types import JsonDict
39
38
  from synapse.util.events import get_plain_text_topic_from_event_content
@@ -75,7 +74,10 @@ class StatsHandler:
75
74
 
76
75
  # We kick this off so that we don't have to wait for a change before
77
76
  # we start populating stats
78
- self.clock.call_later(0, self.notify_new_event)
77
+ self.clock.call_later(
78
+ 0,
79
+ self.notify_new_event,
80
+ )
79
81
 
80
82
  def notify_new_event(self) -> None:
81
83
  """Called when there may be more deltas to process"""
@@ -90,7 +92,7 @@ class StatsHandler:
90
92
  finally:
91
93
  self._is_processing = False
92
94
 
93
- run_as_background_process("stats.notify_new_event", self.server_name, process)
95
+ self.hs.run_as_background_process("stats.notify_new_event", process)
94
96
 
95
97
  async def _unsafe_process(self) -> None:
96
98
  # If self.pos is None then means we haven't fetched it from DB
synapse/handlers/sync.py CHANGED
@@ -323,6 +323,7 @@ class SyncHandler:
323
323
  ] = ExpiringCache(
324
324
  cache_name="lazy_loaded_members_cache",
325
325
  server_name=self.server_name,
326
+ hs=hs,
326
327
  clock=self.clock,
327
328
  max_len=0,
328
329
  expiry_ms=LAZY_LOADED_MEMBERS_CACHE_MAX_AGE,
@@ -552,7 +553,7 @@ class SyncHandler:
552
553
  Returns:
553
554
  A tuple of the now StreamToken, updated to reflect the which typing
554
555
  events are included, and a dict mapping from room_id to a list of
555
- typing events for that room.
556
+ ephemeral events for that room.
556
557
  """
557
558
 
558
559
  sync_config = sync_result_builder.sync_config
@@ -577,12 +578,8 @@ class SyncHandler:
577
578
  ephemeral_by_room: JsonDict = {}
578
579
 
579
580
  for event in typing:
580
- # we want to exclude the room_id from the event, but modifying the
581
- # result returned by the event source is poor form (it might cache
582
- # the object)
583
581
  room_id = event["room_id"]
584
- event_copy = {k: v for (k, v) in event.items() if k != "room_id"}
585
- ephemeral_by_room.setdefault(room_id, []).append(event_copy)
582
+ ephemeral_by_room.setdefault(room_id, []).append(event)
586
583
 
587
584
  receipt_key = (
588
585
  since_token.receipt_key
@@ -602,9 +599,7 @@ class SyncHandler:
602
599
 
603
600
  for event in receipts:
604
601
  room_id = event["room_id"]
605
- # exclude room id, as above
606
- event_copy = {k: v for (k, v) in event.items() if k != "room_id"}
607
- ephemeral_by_room.setdefault(room_id, []).append(event_copy)
602
+ ephemeral_by_room.setdefault(room_id, []).append(event)
608
603
 
609
604
  return now_token, ephemeral_by_room
610
605
 
@@ -980,7 +975,11 @@ class SyncHandler:
980
975
  )
981
976
  if cache is None:
982
977
  logger.debug("creating LruCache for %r", cache_key)
983
- cache = LruCache(max_size=LAZY_LOADED_MEMBERS_CACHE_MAX_SIZE)
978
+ cache = LruCache(
979
+ max_size=LAZY_LOADED_MEMBERS_CACHE_MAX_SIZE,
980
+ clock=self.clock,
981
+ server_name=self.server_name,
982
+ )
984
983
  self.lazy_loaded_members_cache[cache_key] = cache
985
984
  else:
986
985
  logger.debug("found LruCache for %r", cache_key)
@@ -2729,9 +2728,17 @@ class SyncHandler:
2729
2728
  )
2730
2729
  )
2731
2730
 
2732
- ephemeral = await sync_config.filter_collection.filter_room_ephemeral(
2733
- ephemeral
2734
- )
2731
+ ephemeral = [
2732
+ # per spec, ephemeral events (typing notifications and read receipts)
2733
+ # should not have a `room_id` field when sent to clients
2734
+ # refs:
2735
+ # - https://spec.matrix.org/v1.16/client-server-api/#mtyping
2736
+ # - https://spec.matrix.org/v1.16/client-server-api/#mreceipt
2737
+ {k: v for (k, v) in event.items() if k != "room_id"}
2738
+ for event in await sync_config.filter_collection.filter_room_ephemeral(
2739
+ ephemeral
2740
+ )
2741
+ ]
2735
2742
 
2736
2743
  if not (
2737
2744
  always_include
@@ -28,7 +28,6 @@ from synapse.api.constants import EduTypes
28
28
  from synapse.api.errors import AuthError, ShadowBanError, SynapseError
29
29
  from synapse.appservice import ApplicationService
30
30
  from synapse.metrics.background_process_metrics import (
31
- run_as_background_process,
32
31
  wrap_as_background_process,
33
32
  )
34
33
  from synapse.replication.tcp.streams import TypingStream
@@ -78,11 +77,10 @@ class FollowerTypingHandler:
78
77
  """
79
78
 
80
79
  def __init__(self, hs: "HomeServer"):
80
+ self.hs = hs # nb must be called this for @wrap_as_background_process
81
81
  self.store = hs.get_datastores().main
82
82
  self._storage_controllers = hs.get_storage_controllers()
83
- self.server_name = (
84
- hs.hostname
85
- ) # nb must be called this for @wrap_as_background_process
83
+ self.server_name = hs.hostname
86
84
  self.clock = hs.get_clock()
87
85
  self.is_mine_id = hs.is_mine_id
88
86
  self.is_mine_server_name = hs.is_mine_server_name
@@ -144,9 +142,8 @@ class FollowerTypingHandler:
144
142
  if self.federation and self.is_mine_id(member.user_id):
145
143
  last_fed_poke = self._member_last_federation_poke.get(member, None)
146
144
  if not last_fed_poke or last_fed_poke + FEDERATION_PING_INTERVAL <= now:
147
- run_as_background_process(
145
+ self.hs.run_as_background_process(
148
146
  "typing._push_remote",
149
- self.server_name,
150
147
  self._push_remote,
151
148
  member=member,
152
149
  typing=True,
@@ -220,9 +217,8 @@ class FollowerTypingHandler:
220
217
  self._rooms_updated.add(row.room_id)
221
218
 
222
219
  if self.federation:
223
- run_as_background_process(
220
+ self.hs.run_as_background_process(
224
221
  "_send_changes_in_typing_to_remotes",
225
- self.server_name,
226
222
  self._send_changes_in_typing_to_remotes,
227
223
  row.room_id,
228
224
  prev_typing,
@@ -384,9 +380,8 @@ class TypingWriterHandler(FollowerTypingHandler):
384
380
  def _push_update(self, member: RoomMember, typing: bool) -> None:
385
381
  if self.hs.is_mine_id(member.user_id):
386
382
  # Only send updates for changes to our own users.
387
- run_as_background_process(
383
+ self.hs.run_as_background_process(
388
384
  "typing._push_remote",
389
- self.server_name,
390
385
  self._push_remote,
391
386
  member,
392
387
  typing,
@@ -36,7 +36,6 @@ from synapse.api.constants import (
36
36
  from synapse.api.errors import Codes, SynapseError
37
37
  from synapse.handlers.state_deltas import MatchChange, StateDeltasHandler
38
38
  from synapse.metrics import SERVER_NAME_LABEL
39
- from synapse.metrics.background_process_metrics import run_as_background_process
40
39
  from synapse.storage.databases.main.state_deltas import StateDelta
41
40
  from synapse.storage.databases.main.user_directory import SearchResult
42
41
  from synapse.storage.roommember import ProfileInfo
@@ -137,11 +136,15 @@ class UserDirectoryHandler(StateDeltasHandler):
137
136
 
138
137
  # We kick this off so that we don't have to wait for a change before
139
138
  # we start populating the user directory
140
- self.clock.call_later(0, self.notify_new_event)
139
+ self.clock.call_later(
140
+ 0,
141
+ self.notify_new_event,
142
+ )
141
143
 
142
144
  # Kick off the profile refresh process on startup
143
145
  self._refresh_remote_profiles_call_later = self.clock.call_later(
144
- 10, self.kick_off_remote_profile_refresh_process
146
+ 10,
147
+ self.kick_off_remote_profile_refresh_process,
145
148
  )
146
149
 
147
150
  async def search_users(
@@ -193,9 +196,7 @@ class UserDirectoryHandler(StateDeltasHandler):
193
196
  self._is_processing = False
194
197
 
195
198
  self._is_processing = True
196
- run_as_background_process(
197
- "user_directory.notify_new_event", self.server_name, process
198
- )
199
+ self._hs.run_as_background_process("user_directory.notify_new_event", process)
199
200
 
200
201
  async def handle_local_profile_change(
201
202
  self, user_id: str, profile: ProfileInfo
@@ -609,8 +610,8 @@ class UserDirectoryHandler(StateDeltasHandler):
609
610
  self._is_refreshing_remote_profiles = False
610
611
 
611
612
  self._is_refreshing_remote_profiles = True
612
- run_as_background_process(
613
- "user_directory.refresh_remote_profiles", self.server_name, process
613
+ self._hs.run_as_background_process(
614
+ "user_directory.refresh_remote_profiles", process
614
615
  )
615
616
 
616
617
  async def _unsafe_refresh_remote_profiles(self) -> None:
@@ -655,8 +656,9 @@ class UserDirectoryHandler(StateDeltasHandler):
655
656
  if not users:
656
657
  return
657
658
  _, _, next_try_at_ts = users[0]
659
+ delay = ((next_try_at_ts - self.clock.time_msec()) // 1000) + 2
658
660
  self._refresh_remote_profiles_call_later = self.clock.call_later(
659
- ((next_try_at_ts - self.clock.time_msec()) // 1000) + 2,
661
+ delay,
660
662
  self.kick_off_remote_profile_refresh_process,
661
663
  )
662
664
 
@@ -692,9 +694,8 @@ class UserDirectoryHandler(StateDeltasHandler):
692
694
  self._is_refreshing_remote_profiles_for_servers.remove(server_name)
693
695
 
694
696
  self._is_refreshing_remote_profiles_for_servers.add(server_name)
695
- run_as_background_process(
697
+ self._hs.run_as_background_process(
696
698
  "user_directory.refresh_remote_profiles_for_remote_server",
697
- self.server_name,
698
699
  process,
699
700
  )
700
701
 
@@ -37,13 +37,13 @@ from weakref import WeakSet
37
37
  import attr
38
38
 
39
39
  from twisted.internet import defer
40
- from twisted.internet.interfaces import IReactorTime
41
40
 
42
41
  from synapse.logging.context import PreserveLoggingContext
43
42
  from synapse.logging.opentracing import start_active_span
44
43
  from synapse.metrics.background_process_metrics import wrap_as_background_process
45
44
  from synapse.storage.databases.main.lock import Lock, LockStore
46
45
  from synapse.util.async_helpers import timeout_deferred
46
+ from synapse.util.clock import Clock
47
47
  from synapse.util.constants import ONE_MINUTE_SECONDS
48
48
 
49
49
  if TYPE_CHECKING:
@@ -66,10 +66,8 @@ class WorkerLocksHandler:
66
66
  """
67
67
 
68
68
  def __init__(self, hs: "HomeServer") -> None:
69
- self.server_name = (
70
- hs.hostname
71
- ) # nb must be called this for @wrap_as_background_process
72
- self._reactor = hs.get_reactor()
69
+ self.hs = hs # nb must be called this for @wrap_as_background_process
70
+ self._clock = hs.get_clock()
73
71
  self._store = hs.get_datastores().main
74
72
  self._clock = hs.get_clock()
75
73
  self._notifier = hs.get_notifier()
@@ -98,7 +96,7 @@ class WorkerLocksHandler:
98
96
  """
99
97
 
100
98
  lock = WaitingLock(
101
- reactor=self._reactor,
99
+ clock=self._clock,
102
100
  store=self._store,
103
101
  handler=self,
104
102
  lock_name=lock_name,
@@ -129,7 +127,7 @@ class WorkerLocksHandler:
129
127
  """
130
128
 
131
129
  lock = WaitingLock(
132
- reactor=self._reactor,
130
+ clock=self._clock,
133
131
  store=self._store,
134
132
  handler=self,
135
133
  lock_name=lock_name,
@@ -160,7 +158,7 @@ class WorkerLocksHandler:
160
158
  lock = WaitingMultiLock(
161
159
  lock_names=lock_names,
162
160
  write=write,
163
- reactor=self._reactor,
161
+ clock=self._clock,
164
162
  store=self._store,
165
163
  handler=self,
166
164
  )
@@ -197,7 +195,11 @@ class WorkerLocksHandler:
197
195
  if not deferred.called:
198
196
  deferred.callback(None)
199
197
 
200
- self._clock.call_later(0, _wake_all_locks, locks)
198
+ self._clock.call_later(
199
+ 0,
200
+ _wake_all_locks,
201
+ locks,
202
+ )
201
203
 
202
204
  @wrap_as_background_process("_cleanup_locks")
203
205
  async def _cleanup_locks(self) -> None:
@@ -207,7 +209,7 @@ class WorkerLocksHandler:
207
209
 
208
210
  @attr.s(auto_attribs=True, eq=False)
209
211
  class WaitingLock:
210
- reactor: IReactorTime
212
+ clock: Clock
211
213
  store: LockStore
212
214
  handler: WorkerLocksHandler
213
215
  lock_name: str
@@ -246,10 +248,11 @@ class WaitingLock:
246
248
  # periodically wake up in case the lock was released but we
247
249
  # weren't notified.
248
250
  with PreserveLoggingContext():
251
+ timeout = self._get_next_retry_interval()
249
252
  await timeout_deferred(
250
253
  deferred=self.deferred,
251
- timeout=self._get_next_retry_interval(),
252
- reactor=self.reactor,
254
+ timeout=timeout,
255
+ clock=self.clock,
253
256
  )
254
257
  except Exception:
255
258
  pass
@@ -290,7 +293,7 @@ class WaitingMultiLock:
290
293
 
291
294
  write: bool
292
295
 
293
- reactor: IReactorTime
296
+ clock: Clock
294
297
  store: LockStore
295
298
  handler: WorkerLocksHandler
296
299
 
@@ -323,10 +326,11 @@ class WaitingMultiLock:
323
326
  # periodically wake up in case the lock was released but we
324
327
  # weren't notified.
325
328
  with PreserveLoggingContext():
329
+ timeout = self._get_next_retry_interval()
326
330
  await timeout_deferred(
327
331
  deferred=self.deferred,
328
- timeout=self._get_next_retry_interval(),
329
- reactor=self.reactor,
332
+ timeout=timeout,
333
+ clock=self.clock,
330
334
  )
331
335
  except Exception:
332
336
  pass
synapse/http/client.py CHANGED
@@ -54,7 +54,6 @@ from twisted.internet.interfaces import (
54
54
  IOpenSSLContextFactory,
55
55
  IReactorCore,
56
56
  IReactorPluggableNameResolver,
57
- IReactorTime,
58
57
  IResolutionReceiver,
59
58
  ITCPTransport,
60
59
  )
@@ -88,6 +87,7 @@ from synapse.logging.opentracing import set_tag, start_active_span, tags
88
87
  from synapse.metrics import SERVER_NAME_LABEL
89
88
  from synapse.types import ISynapseReactor, StrSequence
90
89
  from synapse.util.async_helpers import timeout_deferred
90
+ from synapse.util.clock import Clock
91
91
  from synapse.util.json import json_decoder
92
92
 
93
93
  if TYPE_CHECKING:
@@ -165,16 +165,17 @@ def _is_ip_blocked(
165
165
  _EPSILON = 0.00000001
166
166
 
167
167
 
168
- def _make_scheduler(
169
- reactor: IReactorTime,
170
- ) -> Callable[[Callable[[], object]], IDelayedCall]:
168
+ def _make_scheduler(clock: Clock) -> Callable[[Callable[[], object]], IDelayedCall]:
171
169
  """Makes a schedular suitable for a Cooperator using the given reactor.
172
170
 
173
171
  (This is effectively just a copy from `twisted.internet.task`)
174
172
  """
175
173
 
176
174
  def _scheduler(x: Callable[[], object]) -> IDelayedCall:
177
- return reactor.callLater(_EPSILON, x)
175
+ return clock.call_later(
176
+ _EPSILON,
177
+ x,
178
+ )
178
179
 
179
180
  return _scheduler
180
181
 
@@ -367,7 +368,7 @@ class BaseHttpClient:
367
368
 
368
369
  # We use this for our body producers to ensure that they use the correct
369
370
  # reactor.
370
- self._cooperator = Cooperator(scheduler=_make_scheduler(hs.get_reactor()))
371
+ self._cooperator = Cooperator(scheduler=_make_scheduler(hs.get_clock()))
371
372
 
372
373
  async def request(
373
374
  self,
@@ -436,9 +437,9 @@ class BaseHttpClient:
436
437
  # we use our own timeout mechanism rather than treq's as a workaround
437
438
  # for https://twistedmatrix.com/trac/ticket/9534.
438
439
  request_deferred = timeout_deferred(
439
- request_deferred,
440
- 60,
441
- self.hs.get_reactor(),
440
+ deferred=request_deferred,
441
+ timeout=60,
442
+ clock=self.hs.get_clock(),
442
443
  )
443
444
 
444
445
  # turn timeouts into RequestTimedOutErrors
@@ -763,7 +764,11 @@ class BaseHttpClient:
763
764
  d = read_body_with_max_size(response, output_stream, max_size)
764
765
 
765
766
  # Ensure that the body is not read forever.
766
- d = timeout_deferred(d, 30, self.hs.get_reactor())
767
+ d = timeout_deferred(
768
+ deferred=d,
769
+ timeout=30,
770
+ clock=self.hs.get_clock(),
771
+ )
767
772
 
768
773
  length = await make_deferred_yieldable(d)
769
774
  except BodyExceededMaxSize:
@@ -957,9 +962,9 @@ class ReplicationClient(BaseHttpClient):
957
962
  # for https://twistedmatrix.com/trac/ticket/9534.
958
963
  # (Updated url https://github.com/twisted/twisted/issues/9534)
959
964
  request_deferred = timeout_deferred(
960
- request_deferred,
961
- 60,
962
- self.hs.get_reactor(),
965
+ deferred=request_deferred,
966
+ timeout=60,
967
+ clock=self.hs.get_clock(),
963
968
  )
964
969
 
965
970
  # turn timeouts into RequestTimedOutErrors
@@ -67,6 +67,9 @@ class MatrixFederationAgent:
67
67
  Args:
68
68
  reactor: twisted reactor to use for underlying requests
69
69
 
70
+ clock: Internal `HomeServer` clock used to track delayed and looping calls.
71
+ Should be obtained from `hs.get_clock()`.
72
+
70
73
  tls_client_options_factory:
71
74
  factory to use for fetching client tls options, or none to disable TLS.
72
75
 
@@ -97,6 +100,7 @@ class MatrixFederationAgent:
97
100
  *,
98
101
  server_name: str,
99
102
  reactor: ISynapseReactor,
103
+ clock: Clock,
100
104
  tls_client_options_factory: Optional[FederationPolicyForHTTPS],
101
105
  user_agent: bytes,
102
106
  ip_allowlist: Optional[IPSet],
@@ -109,6 +113,7 @@ class MatrixFederationAgent:
109
113
  Args:
110
114
  server_name: Our homeserver name (used to label metrics) (`hs.hostname`).
111
115
  reactor
116
+ clock: Should be the `hs` clock from `hs.get_clock()`
112
117
  tls_client_options_factory
113
118
  user_agent
114
119
  ip_allowlist
@@ -124,7 +129,6 @@ class MatrixFederationAgent:
124
129
  # addresses, to prevent DNS rebinding.
125
130
  reactor = BlocklistingReactorWrapper(reactor, ip_allowlist, ip_blocklist)
126
131
 
127
- self._clock = Clock(reactor)
128
132
  self._pool = HTTPConnectionPool(reactor)
129
133
  self._pool.retryAutomatically = False
130
134
  self._pool.maxPersistentPerHost = 5
@@ -147,6 +151,7 @@ class MatrixFederationAgent:
147
151
  _well_known_resolver = WellKnownResolver(
148
152
  server_name=server_name,
149
153
  reactor=reactor,
154
+ clock=clock,
150
155
  agent=BlocklistingAgentWrapper(
151
156
  ProxyAgent(
152
157
  reactor=reactor,
@@ -90,6 +90,7 @@ class WellKnownResolver:
90
90
  self,
91
91
  server_name: str,
92
92
  reactor: ISynapseThreadlessReactor,
93
+ clock: Clock,
93
94
  agent: IAgent,
94
95
  user_agent: bytes,
95
96
  well_known_cache: Optional[TTLCache[bytes, Optional[bytes]]] = None,
@@ -99,6 +100,7 @@ class WellKnownResolver:
99
100
  Args:
100
101
  server_name: Our homeserver name (used to label metrics) (`hs.hostname`).
101
102
  reactor
103
+ clock: Should be the `hs` clock from `hs.get_clock()`
102
104
  agent
103
105
  user_agent
104
106
  well_known_cache
@@ -107,7 +109,7 @@ class WellKnownResolver:
107
109
 
108
110
  self.server_name = server_name
109
111
  self._reactor = reactor
110
- self._clock = Clock(reactor)
112
+ self._clock = clock
111
113
 
112
114
  if well_known_cache is None:
113
115
  well_known_cache = TTLCache(