Skip to main content

tuwunel_api/client/
typing.rs

1use axum::extract::State;
2use ruma::{api::client::typing::create_typing_event, presence::PresenceState};
3use tuwunel_core::{Err, Result, utils, utils::math::Tried};
4
5use crate::{ClientIp, Ruma};
6
7/// # `PUT /_matrix/client/r0/rooms/{roomId}/typing/{userId}`
8///
9/// Sets the typing state of the sender user.
10pub(crate) async fn create_typing_event_route(
11	State(services): State<crate::State>,
12	ClientIp(client): ClientIp,
13	body: Ruma<create_typing_event::v3::Request>,
14) -> Result<create_typing_event::v3::Response> {
15	use create_typing_event::v3::Typing;
16	let sender_user = body.sender_user();
17
18	if sender_user != body.user_id && body.appservice_info.is_none() {
19		return Err!(Request(Forbidden("You cannot update typing status of other users.")));
20	}
21
22	if !services
23		.state_cache
24		.is_joined(sender_user, &body.room_id)
25		.await
26	{
27		return Err!(Request(Forbidden("You are not in this room.")));
28	}
29
30	match body.state {
31		| Typing::Yes(info) => {
32			let duration = Ord::clamp(
33				info.timeout
34					.as_millis()
35					.try_into()
36					.unwrap_or(u64::MAX),
37				services
38					.server
39					.config
40					.typing_client_timeout_min_s
41					.try_mul(1000)?,
42				services
43					.server
44					.config
45					.typing_client_timeout_max_s
46					.try_mul(1000)?,
47			);
48			services
49				.typing
50				.typing_add(
51					sender_user,
52					&body.room_id,
53					utils::millis_since_unix_epoch()
54						.checked_add(duration)
55						.expect("user typing timeout should not get this high"),
56				)
57				.await?;
58		},
59		| _ => {
60			services
61				.typing
62				.typing_remove(sender_user, &body.room_id)
63				.await?;
64		},
65	}
66
67	// ping presence
68	services
69		.presence
70		.maybe_ping_presence(
71			&body.user_id,
72			body.sender_device.as_deref(),
73			Some(client),
74			&PresenceState::Online,
75		)
76		.await?;
77
78	Ok(create_typing_event::v3::Response {})
79}