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

Commit 6408372

Browse files
Improve docstrings for methods related to sending EDUs to application services (#11138)
1 parent 0f9adc9 commit 6408372

File tree

7 files changed

+148
-23
lines changed

7 files changed

+148
-23
lines changed

changelog.d/11138.misc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add docstrings and comments to the application service ephemeral event sending code.

synapse/handlers/appservice.py

+82-12
Original file line numberDiff line numberDiff line change
@@ -185,19 +185,26 @@ def notify_interested_services_ephemeral(
185185
new_token: Optional[int],
186186
users: Optional[Collection[Union[str, UserID]]] = None,
187187
) -> None:
188-
"""This is called by the notifier in the background
189-
when a ephemeral event handled by the homeserver.
190-
191-
This will determine which appservices
192-
are interested in the event, and submit them.
188+
"""
189+
This is called by the notifier in the background when an ephemeral event is handled
190+
by the homeserver.
193191
194-
Events will only be pushed to appservices
195-
that have opted into ephemeral events
192+
This will determine which appservices are interested in the event, and submit them.
196193
197194
Args:
198195
stream_key: The stream the event came from.
199-
new_token: The latest stream token
200-
users: The user(s) involved with the event.
196+
197+
`stream_key` can be "typing_key", "receipt_key" or "presence_key". Any other
198+
value for `stream_key` will cause this function to return early.
199+
200+
Ephemeral events will only be pushed to appservices that have opted into
201+
them.
202+
203+
Appservices will only receive ephemeral events that fall within their
204+
registered user and room namespaces.
205+
206+
new_token: The latest stream token.
207+
users: The users that should be informed of the new event, if any.
201208
"""
202209
if not self.notify_appservices:
203210
return
@@ -232,40 +239,87 @@ async def _notify_interested_services_ephemeral(
232239
for service in services:
233240
# Only handle typing if we have the latest token
234241
if stream_key == "typing_key" and new_token is not None:
242+
# Note that we don't persist the token (via set_type_stream_id_for_appservice)
243+
# for typing_key due to performance reasons and due to their highly
244+
# ephemeral nature.
245+
#
246+
# Instead we simply grab the latest typing updates in _handle_typing
247+
# and, if they apply to this application service, send it off.
235248
events = await self._handle_typing(service, new_token)
236249
if events:
237250
self.scheduler.submit_ephemeral_events_for_as(service, events)
238-
# We don't persist the token for typing_key for performance reasons
251+
239252
elif stream_key == "receipt_key":
240253
events = await self._handle_receipts(service)
241254
if events:
242255
self.scheduler.submit_ephemeral_events_for_as(service, events)
256+
257+
# Persist the latest handled stream token for this appservice
243258
await self.store.set_type_stream_id_for_appservice(
244259
service, "read_receipt", new_token
245260
)
261+
246262
elif stream_key == "presence_key":
247263
events = await self._handle_presence(service, users)
248264
if events:
249265
self.scheduler.submit_ephemeral_events_for_as(service, events)
266+
267+
# Persist the latest handled stream token for this appservice
250268
await self.store.set_type_stream_id_for_appservice(
251269
service, "presence", new_token
252270
)
253271

254272
async def _handle_typing(
255273
self, service: ApplicationService, new_token: int
256274
) -> List[JsonDict]:
275+
"""
276+
Return the typing events since the given stream token that the given application
277+
service should receive.
278+
279+
First fetch all typing events between the given typing stream token (non-inclusive)
280+
and the latest typing event stream token (inclusive). Then return only those typing
281+
events that the given application service may be interested in.
282+
283+
Args:
284+
service: The application service to check for which events it should receive.
285+
new_token: A typing event stream token.
286+
287+
Returns:
288+
A list of JSON dictionaries containing data derived from the typing events that
289+
should be sent to the given application service.
290+
"""
257291
typing_source = self.event_sources.sources.typing
258292
# Get the typing events from just before current
259293
typing, _ = await typing_source.get_new_events_as(
260294
service=service,
261295
# For performance reasons, we don't persist the previous
262-
# token in the DB and instead fetch the latest typing information
296+
# token in the DB and instead fetch the latest typing event
263297
# for appservices.
298+
# TODO: It'd likely be more efficient to simply fetch the
299+
# typing event with the given 'new_token' stream token and
300+
# check if the given service was interested, rather than
301+
# iterating over all typing events and only grabbing the
302+
# latest few.
264303
from_key=new_token - 1,
265304
)
266305
return typing
267306

268307
async def _handle_receipts(self, service: ApplicationService) -> List[JsonDict]:
308+
"""
309+
Return the latest read receipts that the given application service should receive.
310+
311+
First fetch all read receipts between the last receipt stream token that this
312+
application service should have previously received (non-inclusive) and the
313+
latest read receipt stream token (inclusive). Then from that set, return only
314+
those read receipts that the given application service may be interested in.
315+
316+
Args:
317+
service: The application service to check for which events it should receive.
318+
319+
Returns:
320+
A list of JSON dictionaries containing data derived from the read receipts that
321+
should be sent to the given application service.
322+
"""
269323
from_key = await self.store.get_type_stream_id_for_appservice(
270324
service, "read_receipt"
271325
)
@@ -278,6 +332,22 @@ async def _handle_receipts(self, service: ApplicationService) -> List[JsonDict]:
278332
async def _handle_presence(
279333
self, service: ApplicationService, users: Collection[Union[str, UserID]]
280334
) -> List[JsonDict]:
335+
"""
336+
Return the latest presence updates that the given application service should receive.
337+
338+
First, filter the given users list to those that the application service is
339+
interested in. Then retrieve the latest presence updates since the
340+
the last-known previously received presence stream token for the given
341+
application service. Return those presence updates.
342+
343+
Args:
344+
service: The application service that ephemeral events are being sent to.
345+
users: The users that should receive the presence update.
346+
347+
Returns:
348+
A list of json dictionaries containing data derived from the presence events
349+
that should be sent to the given application service.
350+
"""
281351
events: List[JsonDict] = []
282352
presence_source = self.event_sources.sources.presence
283353
from_key = await self.store.get_type_stream_id_for_appservice(
@@ -290,9 +360,9 @@ async def _handle_presence(
290360
interested = await service.is_interested_in_presence(user, self.store)
291361
if not interested:
292362
continue
363+
293364
presence_events, _ = await presence_source.get_new_events(
294365
user=user,
295-
service=service,
296366
from_key=from_key,
297367
)
298368
time_now = self.clock.time_msec()

synapse/handlers/device.py

+4
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,10 @@ async def notify_device_update(
454454
) -> None:
455455
"""Notify that a user's device(s) has changed. Pokes the notifier, and
456456
remote servers if the user is local.
457+
458+
Args:
459+
user_id: The Matrix ID of the user who's device list has been updated.
460+
device_ids: The device IDs that have changed.
457461
"""
458462
if not device_ids:
459463
# No changes to notify about, so this is a no-op.

synapse/handlers/presence.py

+29-5
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
from synapse.api.constants import EventTypes, Membership, PresenceState
5353
from synapse.api.errors import SynapseError
5454
from synapse.api.presence import UserPresenceState
55-
from synapse.appservice import ApplicationService
5655
from synapse.events.presence_router import PresenceRouter
5756
from synapse.logging.context import run_in_background
5857
from synapse.logging.utils import log_function
@@ -1483,11 +1482,37 @@ def should_notify(old_state: UserPresenceState, new_state: UserPresenceState) ->
14831482
def format_user_presence_state(
14841483
state: UserPresenceState, now: int, include_user_id: bool = True
14851484
) -> JsonDict:
1486-
"""Convert UserPresenceState to a format that can be sent down to clients
1485+
"""Convert UserPresenceState to a JSON format that can be sent down to clients
14871486
and to other servers.
14881487
1489-
The "user_id" is optional so that this function can be used to format presence
1490-
updates for client /sync responses and for federation /send requests.
1488+
Args:
1489+
state: The user presence state to format.
1490+
now: The current timestamp since the epoch in ms.
1491+
include_user_id: Whether to include `user_id` in the returned dictionary.
1492+
As this function can be used both to format presence updates for client /sync
1493+
responses and for federation /send requests, only the latter needs the include
1494+
the `user_id` field.
1495+
1496+
Returns:
1497+
A JSON dictionary with the following keys:
1498+
* presence: The presence state as a str.
1499+
* user_id: Optional. Included if `include_user_id` is truthy. The canonical
1500+
Matrix ID of the user.
1501+
* last_active_ago: Optional. Included if `last_active_ts` is set on `state`.
1502+
The timestamp that the user was last active.
1503+
* status_msg: Optional. Included if `status_msg` is set on `state`. The user's
1504+
status.
1505+
* currently_active: Optional. Included only if `state.state` is "online".
1506+
1507+
Example:
1508+
1509+
{
1510+
"presence": "online",
1511+
"user_id": "@alice:example.com",
1512+
"last_active_ago": 16783813918,
1513+
"status_msg": "Hello world!",
1514+
"currently_active": True
1515+
}
14911516
"""
14921517
content: JsonDict = {"presence": state.state}
14931518
if include_user_id:
@@ -1526,7 +1551,6 @@ async def get_new_events(
15261551
is_guest: bool = False,
15271552
explicit_room_id: Optional[str] = None,
15281553
include_offline: bool = True,
1529-
service: Optional[ApplicationService] = None,
15301554
) -> Tuple[List[UserPresenceState], int]:
15311555
# The process for getting presence events are:
15321556
# 1. Get the rooms the user is in.

synapse/handlers/receipts.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -241,12 +241,18 @@ async def get_new_events(
241241
async def get_new_events_as(
242242
self, from_key: int, service: ApplicationService
243243
) -> Tuple[List[JsonDict], int]:
244-
"""Returns a set of new receipt events that an appservice
244+
"""Returns a set of new read receipt events that an appservice
245245
may be interested in.
246246
247247
Args:
248248
from_key: the stream position at which events should be fetched from
249249
service: The appservice which may be interested
250+
251+
Returns:
252+
A two-tuple containing the following:
253+
* A list of json dictionaries derived from read receipts that the
254+
appservice may be interested in.
255+
* The current read receipt stream token.
250256
"""
251257
from_key = int(from_key)
252258
to_key = self.get_current_key()

synapse/handlers/typing.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -465,17 +465,23 @@ async def get_new_events_as(
465465
may be interested in.
466466
467467
Args:
468-
from_key: the stream position at which events should be fetched from
469-
service: The appservice which may be interested
468+
from_key: the stream position at which events should be fetched from.
469+
service: The appservice which may be interested.
470+
471+
Returns:
472+
A two-tuple containing the following:
473+
* A list of json dictionaries derived from typing events that the
474+
appservice may be interested in.
475+
* The latest known room serial.
470476
"""
471477
with Measure(self.clock, "typing.get_new_events_as"):
472-
from_key = int(from_key)
473478
handler = self.get_typing_handler()
474479

475480
events = []
476481
for room_id in handler._room_serials.keys():
477482
if handler._room_serials[room_id] <= from_key:
478483
continue
484+
479485
if not await service.matches_user_in_member_list(
480486
room_id, handler.store
481487
):

synapse/notifier.py

+16-2
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,14 @@ def _notify_app_services_ephemeral(
379379
stream_key: str,
380380
new_token: Union[int, RoomStreamToken],
381381
users: Optional[Collection[Union[str, UserID]]] = None,
382-
):
382+
) -> None:
383+
"""Notify application services of ephemeral event activity.
384+
385+
Args:
386+
stream_key: The stream the event came from.
387+
new_token: The value of the new stream token.
388+
users: The users that should be informed of the new event, if any.
389+
"""
383390
try:
384391
stream_token = None
385392
if isinstance(new_token, int):
@@ -402,10 +409,17 @@ def on_new_event(
402409
new_token: Union[int, RoomStreamToken],
403410
users: Optional[Collection[Union[str, UserID]]] = None,
404411
rooms: Optional[Collection[str]] = None,
405-
):
412+
) -> None:
406413
"""Used to inform listeners that something has happened event wise.
407414
408415
Will wake up all listeners for the given users and rooms.
416+
417+
Args:
418+
stream_key: The stream the event came from.
419+
new_token: The value of the new stream token.
420+
users: The users that should be informed of the new event.
421+
rooms: A collection of room IDs for which each joined member will be
422+
informed of the new event.
409423
"""
410424
users = users or []
411425
rooms = rooms or []

0 commit comments

Comments
 (0)