Skip to main content

tuwunel_api/client/read_marker/
mod.rs

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