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