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 duration = Ord::clamp(
34				info.timeout
35					.as_millis()
36					.try_into()
37					.unwrap_or(u64::MAX),
38				services
39					.server
40					.config
41					.typing_client_timeout_min_s
42					.try_mul(1000)?,
43				services
44					.server
45					.config
46					.typing_client_timeout_max_s
47					.try_mul(1000)?,
48			);
49			services
50				.typing
51				.typing_add(
52					sender_user,
53					&body.room_id,
54					utils::millis_since_unix_epoch()
55						.checked_add(duration)
56						.expect("user typing timeout should not get this high"),
57				)
58				.await?;
59		},
60		| _ => {
61			services
62				.typing
63				.typing_remove(sender_user, &body.room_id)
64				.await?;
65		},
66	}
67
68	// ping presence
69	let ping = Ping {
70		device_id: body.sender_device.as_deref(),
71		client_ip: Some(client),
72		appservice: body.appservice_info.as_ref(),
73		..Default::default()
74	};
75
76	services
77		.presence
78		.maybe_ping_presence(&body.user_id, ping)
79		.await?;
80
81	Ok(create_typing_event::v3::Response {})
82}