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 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 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}