Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit a026695

Browse files
Clarifications and small fixes to to-device related code (#11247)
Co-authored-by: Patrick Cloke <clokep@users.noreply.github.com>
1 parent b6f4d12 commit a026695

File tree

6 files changed

+78
-17
lines changed

6 files changed

+78
-17
lines changed

changelog.d/11247.misc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Clean up code relating to to-device messages and sending ephemeral events to application services.

synapse/handlers/appservice.py

+20-4
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ def notify_interested_services_ephemeral(
188188
self,
189189
stream_key: str,
190190
new_token: Union[int, RoomStreamToken],
191-
users: Optional[Collection[Union[str, UserID]]] = None,
191+
users: Collection[Union[str, UserID]],
192192
) -> None:
193193
"""
194194
This is called by the notifier in the background when an ephemeral event is handled
@@ -203,7 +203,9 @@ def notify_interested_services_ephemeral(
203203
value for `stream_key` will cause this function to return early.
204204
205205
Ephemeral events will only be pushed to appservices that have opted into
206-
them.
206+
receiving them by setting `push_ephemeral` to true in their registration
207+
file. Note that while MSC2409 is experimental, this option is called
208+
`de.sorunome.msc2409.push_ephemeral`.
207209
208210
Appservices will only receive ephemeral events that fall within their
209211
registered user and room namespaces.
@@ -214,6 +216,7 @@ def notify_interested_services_ephemeral(
214216
if not self.notify_appservices:
215217
return
216218

219+
# Ignore any unsupported streams
217220
if stream_key not in ("typing_key", "receipt_key", "presence_key"):
218221
return
219222

@@ -230,18 +233,25 @@ def notify_interested_services_ephemeral(
230233
# Additional context: https://github.com/matrix-org/synapse/pull/11137
231234
assert isinstance(new_token, int)
232235

236+
# Check whether there are any appservices which have registered to receive
237+
# ephemeral events.
238+
#
239+
# Note that whether these events are actually relevant to these appservices
240+
# is decided later on.
233241
services = [
234242
service
235243
for service in self.store.get_app_services()
236244
if service.supports_ephemeral
237245
]
238246
if not services:
247+
# Bail out early if none of the target appservices have explicitly registered
248+
# to receive these ephemeral events.
239249
return
240250

241251
# We only start a new background process if necessary rather than
242252
# optimistically (to cut down on overhead).
243253
self._notify_interested_services_ephemeral(
244-
services, stream_key, new_token, users or []
254+
services, stream_key, new_token, users
245255
)
246256

247257
@wrap_as_background_process("notify_interested_services_ephemeral")
@@ -252,7 +262,7 @@ async def _notify_interested_services_ephemeral(
252262
new_token: int,
253263
users: Collection[Union[str, UserID]],
254264
) -> None:
255-
logger.debug("Checking interested services for %s" % (stream_key))
265+
logger.debug("Checking interested services for %s", stream_key)
256266
with Measure(self.clock, "notify_interested_services_ephemeral"):
257267
for service in services:
258268
if stream_key == "typing_key":
@@ -345,6 +355,9 @@ async def _handle_receipts(
345355
346356
Args:
347357
service: The application service to check for which events it should receive.
358+
new_token: A receipts event stream token. Purely used to double-check that the
359+
from_token we pull from the database isn't greater than or equal to this
360+
token. Prevents accidentally duplicating work.
348361
349362
Returns:
350363
A list of JSON dictionaries containing data derived from the read receipts that
@@ -382,6 +395,9 @@ async def _handle_presence(
382395
Args:
383396
service: The application service that ephemeral events are being sent to.
384397
users: The users that should receive the presence update.
398+
new_token: A presence update stream token. Purely used to double-check that the
399+
from_token we pull from the database isn't greater than or equal to this
400+
token. Prevents accidentally duplicating work.
385401
386402
Returns:
387403
A list of json dictionaries containing data derived from the presence events

synapse/handlers/devicemessage.py

+27-4
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,13 @@ def __init__(self, hs: "HomeServer"):
8989
)
9090

9191
async def on_direct_to_device_edu(self, origin: str, content: JsonDict) -> None:
92+
"""
93+
Handle receiving to-device messages from remote homeservers.
94+
95+
Args:
96+
origin: The remote homeserver.
97+
content: The JSON dictionary containing the to-device messages.
98+
"""
9299
local_messages = {}
93100
sender_user_id = content["sender"]
94101
if origin != get_domain_from_id(sender_user_id):
@@ -135,12 +142,16 @@ async def on_direct_to_device_edu(self, origin: str, content: JsonDict) -> None:
135142
message_type, sender_user_id, by_device
136143
)
137144

138-
stream_id = await self.store.add_messages_from_remote_to_device_inbox(
145+
# Add messages to the database.
146+
# Retrieve the stream id of the last-processed to-device message.
147+
last_stream_id = await self.store.add_messages_from_remote_to_device_inbox(
139148
origin, message_id, local_messages
140149
)
141150

151+
# Notify listeners that there are new to-device messages to process,
152+
# handing them the latest stream id.
142153
self.notifier.on_new_event(
143-
"to_device_key", stream_id, users=local_messages.keys()
154+
"to_device_key", last_stream_id, users=local_messages.keys()
144155
)
145156

146157
async def _check_for_unknown_devices(
@@ -195,6 +206,14 @@ async def send_device_message(
195206
message_type: str,
196207
messages: Dict[str, Dict[str, JsonDict]],
197208
) -> None:
209+
"""
210+
Handle a request from a user to send to-device message(s).
211+
212+
Args:
213+
requester: The user that is sending the to-device messages.
214+
message_type: The type of to-device messages that are being sent.
215+
messages: A dictionary containing recipients mapped to messages intended for them.
216+
"""
198217
sender_user_id = requester.user.to_string()
199218

200219
message_id = random_string(16)
@@ -257,12 +276,16 @@ async def send_device_message(
257276
"org.matrix.opentracing_context": json_encoder.encode(context),
258277
}
259278

260-
stream_id = await self.store.add_messages_to_device_inbox(
279+
# Add messages to the database.
280+
# Retrieve the stream id of the last-processed to-device message.
281+
last_stream_id = await self.store.add_messages_to_device_inbox(
261282
local_messages, remote_edu_contents
262283
)
263284

285+
# Notify listeners that there are new to-device messages to process,
286+
# handing them the latest stream id.
264287
self.notifier.on_new_event(
265-
"to_device_key", stream_id, users=local_messages.keys()
288+
"to_device_key", last_stream_id, users=local_messages.keys()
266289
)
267290

268291
if self.federation_sender:

synapse/storage/databases/main/appservice.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -412,16 +412,16 @@ def get_type_stream_id_for_appservice_txn(txn):
412412
)
413413

414414
async def set_type_stream_id_for_appservice(
415-
self, service: ApplicationService, type: str, pos: Optional[int]
415+
self, service: ApplicationService, stream_type: str, pos: Optional[int]
416416
) -> None:
417-
if type not in ("read_receipt", "presence"):
417+
if stream_type not in ("read_receipt", "presence"):
418418
raise ValueError(
419419
"Expected type to be a valid application stream id type, got %s"
420-
% (type,)
420+
% (stream_type,)
421421
)
422422

423423
def set_type_stream_id_for_appservice_txn(txn):
424-
stream_id_type = "%s_stream_id" % type
424+
stream_id_type = "%s_stream_id" % stream_type
425425
txn.execute(
426426
"UPDATE application_services_state SET %s = ? WHERE as_id=?"
427427
% stream_id_type,

synapse/storage/databases/main/deviceinbox.py

+20-3
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,10 @@ async def get_new_messages_for_device(
134134
limit: The maximum number of messages to retrieve.
135135
136136
Returns:
137-
A list of messages for the device and where in the stream the messages got to.
137+
A tuple containing:
138+
* A list of messages for the device.
139+
* The max stream token of these messages. There may be more to retrieve
140+
if the given limit was reached.
138141
"""
139142
has_changed = self._device_inbox_stream_cache.has_entity_changed(
140143
user_id, last_stream_id
@@ -153,12 +156,19 @@ def get_new_messages_for_device_txn(txn):
153156
txn.execute(
154157
sql, (user_id, device_id, last_stream_id, current_stream_id, limit)
155158
)
159+
156160
messages = []
161+
stream_pos = current_stream_id
162+
157163
for row in txn:
158164
stream_pos = row[0]
159165
messages.append(db_to_json(row[1]))
166+
167+
# If the limit was not reached we know that there's no more data for this
168+
# user/device pair up to current_stream_id.
160169
if len(messages) < limit:
161170
stream_pos = current_stream_id
171+
162172
return messages, stream_pos
163173

164174
return await self.db_pool.runInteraction(
@@ -260,13 +270,20 @@ def get_new_messages_for_remote_destination_txn(txn):
260270
" LIMIT ?"
261271
)
262272
txn.execute(sql, (destination, last_stream_id, current_stream_id, limit))
273+
263274
messages = []
275+
stream_pos = current_stream_id
276+
264277
for row in txn:
265278
stream_pos = row[0]
266279
messages.append(db_to_json(row[1]))
280+
281+
# If the limit was not reached we know that there's no more data for this
282+
# user/device pair up to current_stream_id.
267283
if len(messages) < limit:
268284
log_kv({"message": "Set stream position to current position"})
269285
stream_pos = current_stream_id
286+
270287
return messages, stream_pos
271288

272289
return await self.db_pool.runInteraction(
@@ -372,8 +389,8 @@ async def add_messages_to_device_inbox(
372389
"""Used to send messages from this server.
373390
374391
Args:
375-
local_messages_by_user_and_device:
376-
Dictionary of user_id to device_id to message.
392+
local_messages_by_user_then_device:
393+
Dictionary of recipient user_id to recipient device_id to message.
377394
remote_messages_by_destination:
378395
Dictionary of destination server_name to the EDU JSON to send.
379396

tests/handlers/test_appservice.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,9 @@ def test_notify_interested_services_ephemeral(self):
272272
make_awaitable(([event], None))
273273
)
274274

275-
self.handler.notify_interested_services_ephemeral("receipt_key", 580)
275+
self.handler.notify_interested_services_ephemeral(
276+
"receipt_key", 580, ["@fakerecipient:example.com"]
277+
)
276278
self.mock_scheduler.submit_ephemeral_events_for_as.assert_called_once_with(
277279
interested_service, [event]
278280
)
@@ -300,7 +302,9 @@ def test_notify_interested_services_ephemeral_out_of_order(self):
300302
make_awaitable(([event], None))
301303
)
302304

303-
self.handler.notify_interested_services_ephemeral("receipt_key", 579)
305+
self.handler.notify_interested_services_ephemeral(
306+
"receipt_key", 580, ["@fakerecipient:example.com"]
307+
)
304308
self.mock_scheduler.submit_ephemeral_events_for_as.assert_not_called()
305309

306310
def _mkservice(self, is_interested, protocols=None):

0 commit comments

Comments
 (0)