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

Commit b5834ab

Browse files
committed
Add infrastructure to pass notifications per thread.
1 parent c30ec4f commit b5834ab

File tree

6 files changed

+89
-23
lines changed

6 files changed

+89
-23
lines changed

synapse/handlers/sync.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
from synapse.logging.context import current_context
4141
from synapse.logging.opentracing import SynapseTags, log_kv, set_tag, start_active_span
4242
from synapse.push.clientformat import format_push_rules_for_user
43-
from synapse.storage.databases.main.event_push_actions import NotifCounts
43+
from synapse.storage.databases.main.event_push_actions import RoomNotifCounts
4444
from synapse.storage.roommember import MemberSummary
4545
from synapse.storage.state import StateFilter
4646
from synapse.types import (
@@ -128,6 +128,7 @@ class JoinedSyncResult:
128128
ephemeral: List[JsonDict]
129129
account_data: List[JsonDict]
130130
unread_notifications: JsonDict
131+
unread_thread_notifications: JsonDict
131132
summary: Optional[JsonDict]
132133
unread_count: int
133134

@@ -278,6 +279,8 @@ def __init__(self, hs: "HomeServer"):
278279

279280
self.rooms_to_exclude = hs.config.server.rooms_to_exclude_from_sync
280281

282+
self._msc3773_enabled = hs.config.experimental.msc3773_enabled
283+
281284
async def wait_for_sync_for_user(
282285
self,
283286
requester: Requester,
@@ -1272,7 +1275,7 @@ async def _find_missing_partial_state_memberships(
12721275

12731276
async def unread_notifs_for_room_id(
12741277
self, room_id: str, sync_config: SyncConfig
1275-
) -> NotifCounts:
1278+
) -> RoomNotifCounts:
12761279
with Measure(self.clock, "unread_notifs_for_room_id"):
12771280

12781281
return await self.store.get_unread_event_push_actions_by_room_for_user(
@@ -2343,17 +2346,44 @@ async def _generate_room_entry(
23432346
ephemeral=ephemeral,
23442347
account_data=account_data_events,
23452348
unread_notifications=unread_notifications,
2349+
unread_thread_notifications={},
23462350
summary=summary,
23472351
unread_count=0,
23482352
)
23492353

23502354
if room_sync or always_include:
23512355
notifs = await self.unread_notifs_for_room_id(room_id, sync_config)
23522356

2353-
unread_notifications["notification_count"] = notifs.notify_count
2354-
unread_notifications["highlight_count"] = notifs.highlight_count
2357+
# Notifications for the main timeline.
2358+
notify_count = notifs.main_timeline.notify_count
2359+
highlight_count = notifs.main_timeline.highlight_count
2360+
unread_count = notifs.main_timeline.unread_count
23552361

2356-
room_sync.unread_count = notifs.unread_count
2362+
# Check the sync configuration.
2363+
if (
2364+
self._msc3773_enabled
2365+
and sync_config.filter_collection.unread_thread_notifications()
2366+
):
2367+
# And add info for each thread.
2368+
room_sync.unread_thread_notifications = {
2369+
thread_id: {
2370+
"notification_count": thread_notifs.notify_count,
2371+
"highlight_count": thread_notifs.highlight_count,
2372+
}
2373+
for thread_id, thread_notifs in notifs.threads.items()
2374+
if thread_id is not None
2375+
}
2376+
2377+
else:
2378+
# Combine the unread counts for all threads and main timeline.
2379+
for thread_notifs in notifs.threads.values():
2380+
notify_count += thread_notifs.notify_count
2381+
highlight_count += thread_notifs.highlight_count
2382+
unread_count += thread_notifs.unread_count
2383+
2384+
unread_notifications["notification_count"] = notify_count
2385+
unread_notifications["highlight_count"] = highlight_count
2386+
room_sync.unread_count = unread_count
23572387

23582388
sync_result_builder.joined.append(room_sync)
23592389

synapse/push/push_tools.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,20 @@ async def get_room_unread_count(room_id: str) -> None:
3939
await concurrently_execute(get_room_unread_count, joins, 10)
4040

4141
for notifs in room_notifs:
42-
if notifs.notify_count == 0:
42+
# Combine the counts from all the threads.
43+
notify_count = notifs.main_timeline.notify_count + sum(
44+
n.notify_count for n in notifs.threads.values()
45+
)
46+
47+
if notify_count == 0:
4348
continue
4449

4550
if group_by_room:
4651
# return one badge count per conversation
4752
badge += 1
4853
else:
4954
# increment the badge count by the number of unread messages in the room
50-
badge += notifs.notify_count
55+
badge += notify_count
5156
return badge
5257

5358

synapse/rest/client/sync.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,10 @@ async def encode_room(
509509
ephemeral_events = room.ephemeral
510510
result["ephemeral"] = {"events": ephemeral_events}
511511
result["unread_notifications"] = room.unread_notifications
512+
if room.unread_thread_notifications:
513+
result[
514+
"org.matrix.msc3773.unread_thread_notifications"
515+
] = room.unread_thread_notifications
512516
result["summary"] = room.summary
513517
if self._msc2654_enabled:
514518
result["org.matrix.msc2654.unread_count"] = room.unread_count

synapse/storage/databases/main/event_push_actions.py

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -157,14 +157,29 @@ class UserPushAction(EmailPushAction):
157157
@attr.s(slots=True, auto_attribs=True)
158158
class NotifCounts:
159159
"""
160-
The per-user, per-room count of notifications. Used by sync and push.
160+
The per-user, per-room, per-thread count of notifications. Used by sync and push.
161161
"""
162162

163163
notify_count: int = 0
164164
unread_count: int = 0
165165
highlight_count: int = 0
166166

167167

168+
@attr.s(slots=True, auto_attribs=True)
169+
class RoomNotifCounts:
170+
"""
171+
The per-user, per-room count of notifications. Used by sync and push.
172+
"""
173+
174+
main_timeline: NotifCounts
175+
# Map of thread ID to the notification counts.
176+
threads: Dict[str, NotifCounts]
177+
178+
def __len__(self) -> int:
179+
# To properly account for the amount of space in any caches.
180+
return len(self.threads) + 1
181+
182+
168183
def _serialize_action(
169184
actions: Collection[Union[Mapping, str]], is_highlight: bool
170185
) -> str:
@@ -331,12 +346,12 @@ def add_thread_id_txn(
331346

332347
return result
333348

334-
@cached(tree=True, max_entries=5000)
349+
@cached(tree=True, max_entries=5000, iterable=True)
335350
async def get_unread_event_push_actions_by_room_for_user(
336351
self,
337352
room_id: str,
338353
user_id: str,
339-
) -> NotifCounts:
354+
) -> RoomNotifCounts:
340355
"""Get the notification count, the highlight count and the unread message count
341356
for a given user in a given room after their latest read receipt.
342357
@@ -349,8 +364,9 @@ async def get_unread_event_push_actions_by_room_for_user(
349364
user_id: The user to retrieve the counts for.
350365
351366
Returns
352-
A NotifCounts object containing the notification count, the highlight count
353-
and the unread message count.
367+
A RoomNotifCounts object containing the notification count, the
368+
highlight count and the unread message count for both the main timeline
369+
and threads.
354370
"""
355371
return await self.db_pool.runInteraction(
356372
"get_unread_event_push_actions_by_room",
@@ -364,7 +380,7 @@ def _get_unread_counts_by_receipt_txn(
364380
txn: LoggingTransaction,
365381
room_id: str,
366382
user_id: str,
367-
) -> NotifCounts:
383+
) -> RoomNotifCounts:
368384
# Get the stream ordering of the user's latest receipt in the room.
369385
result = self.get_last_receipt_for_user_txn(
370386
txn,
@@ -402,7 +418,7 @@ def _get_unread_counts_by_pos_txn(
402418
room_id: str,
403419
user_id: str,
404420
receipt_stream_ordering: int,
405-
) -> NotifCounts:
421+
) -> RoomNotifCounts:
406422
"""Get the number of unread messages for a user/room that have happened
407423
since the given stream ordering.
408424
@@ -414,9 +430,10 @@ def _get_unread_counts_by_pos_txn(
414430
receipt in the room. If there are no receipts, the stream ordering
415431
of the user's join event.
416432
417-
Returns
418-
A NotifCounts object containing the notification count, the highlight count
419-
and the unread message count.
433+
Returns:
434+
A RoomNotifCounts object containing the notification count, the
435+
highlight count and the unread message count for both the main timeline
436+
and threads.
420437
"""
421438

422439
counts = NotifCounts()
@@ -481,7 +498,7 @@ def _get_unread_counts_by_pos_txn(
481498
counts.notify_count += notify_count
482499
counts.unread_count += unread_count
483500

484-
return counts
501+
return RoomNotifCounts(counts, {})
485502

486503
def _get_notif_unread_count_for_user_room(
487504
self,

tests/replication/slave/storage/test_events.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
from synapse.events import FrozenEvent, _EventInternalMetadata, make_event_from_dict
2323
from synapse.handlers.room import RoomEventSource
2424
from synapse.replication.slave.storage.events import SlavedEventStore
25-
from synapse.storage.databases.main.event_push_actions import NotifCounts
25+
from synapse.storage.databases.main.event_push_actions import (
26+
NotifCounts,
27+
RoomNotifCounts,
28+
)
2629
from synapse.storage.roommember import GetRoomsForUserWithStreamOrdering, RoomsForUser
2730
from synapse.types import PersistedEventPosition
2831

@@ -178,7 +181,9 @@ def test_push_actions_for_user(self, send_receipt: bool):
178181
self.check(
179182
"get_unread_event_push_actions_by_room_for_user",
180183
[ROOM_ID, USER_ID_2],
181-
NotifCounts(highlight_count=0, unread_count=0, notify_count=0),
184+
RoomNotifCounts(
185+
NotifCounts(highlight_count=0, unread_count=0, notify_count=0), {}
186+
),
182187
)
183188

184189
self.persist(
@@ -191,7 +196,9 @@ def test_push_actions_for_user(self, send_receipt: bool):
191196
self.check(
192197
"get_unread_event_push_actions_by_room_for_user",
193198
[ROOM_ID, USER_ID_2],
194-
NotifCounts(highlight_count=0, unread_count=0, notify_count=1),
199+
RoomNotifCounts(
200+
NotifCounts(highlight_count=0, unread_count=0, notify_count=1), {}
201+
),
195202
)
196203

197204
self.persist(
@@ -206,7 +213,9 @@ def test_push_actions_for_user(self, send_receipt: bool):
206213
self.check(
207214
"get_unread_event_push_actions_by_room_for_user",
208215
[ROOM_ID, USER_ID_2],
209-
NotifCounts(highlight_count=1, unread_count=0, notify_count=2),
216+
RoomNotifCounts(
217+
NotifCounts(highlight_count=1, unread_count=0, notify_count=2), {}
218+
),
210219
)
211220

212221
def test_get_rooms_for_user_with_stream_ordering(self):

tests/storage/test_event_push_actions.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,14 @@ def _assert_counts(noitf_count: int, highlight_count: int) -> None:
7777
)
7878
)
7979
self.assertEqual(
80-
counts,
80+
counts.main_timeline,
8181
NotifCounts(
8282
notify_count=noitf_count,
8383
unread_count=0,
8484
highlight_count=highlight_count,
8585
),
8686
)
87+
self.assertEqual(counts.threads, {})
8788

8889
def _create_event(highlight: bool = False) -> str:
8990
result = self.helper.send_event(

0 commit comments

Comments
 (0)