tuwunel_api/client/
typing.rs1use 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
7pub(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 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}