Skip to main content

tuwunel_api/client/read_marker/
mod.rs

1mod read_markers;
2mod receipt;
3
4use ruma::{EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId, events::receipt::ReceiptThread};
5use tuwunel_core::{Err, PduCount, Result, err, utils::result::LogErr};
6use tuwunel_service::{Services, rooms::read_receipt::PrivateRead};
7
8pub(crate) use self::{read_markers::set_read_marker_route, receipt::create_receipt_route};
9
10/// Resolves `event` to its timeline position and stores the private read
11/// marker for `thread` there.
12///
13/// Returns whether the marker advanced. A backfilled event carries no forward
14/// position, so it is rejected rather than stored.
15async fn set_private_marker(
16	services: &Services,
17	room_id: &RoomId,
18	user_id: &UserId,
19	event: &EventId,
20	thread: &ReceiptThread,
21) -> Result<bool> {
22	let count = services
23		.timeline
24		.get_pdu_count(event)
25		.await
26		.map_err(|_| err!(Request(NotFound("Event not found."))))?;
27
28	let PduCount::Normal(count) = count else {
29		return Err!(Request(InvalidParam(
30			"Event is a backfilled PDU and cannot be marked as read."
31		)));
32	};
33
34	let advanced = services
35		.read_receipt
36		.private_read_set(PrivateRead {
37			room_id,
38			user_id,
39			count,
40			ts: MilliSecondsSinceUnixEpoch::now(),
41			thread,
42			announce: true,
43		})
44		.await;
45
46	Ok(advanced)
47}
48
49/// Clears the receipt's notification counts and refreshes the push badge.
50///
51/// The refresh follows every advance because the gateway can hold a stale
52/// badge while the stored count is already zero; only a delivery reconciles
53/// it.
54async fn reset_and_refresh_badge(
55	services: &Services,
56	user_id: &UserId,
57	room_id: &RoomId,
58	thread: &ReceiptThread,
59) {
60	services
61		.pusher
62		.reset_notification_counts_for_thread(user_id, room_id, thread)
63		.await;
64
65	services
66		.sending
67		.refresh_push_badge(user_id)
68		.await
69		.log_err()
70		.ok();
71}