Skip to main content

tuwunel_api_client/
typing.rs

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