tuwunel_api/client/
presence.rs1use std::time::Duration;
2
3use axum::extract::State;
4use ruma::api::client::presence::{get_presence, set_presence};
5use tuwunel_core::{Err, Result};
6
7use crate::Ruma;
8
9pub(crate) async fn set_presence_route(
13 State(services): State<crate::State>,
14 body: Ruma<set_presence::v3::Request>,
15) -> Result<set_presence::v3::Response> {
16 if !services.config.allow_local_presence {
17 return Err!(Request(Forbidden("Presence is disabled on this server")));
18 }
19
20 if body.sender_user() != body.user_id && body.appservice_info.is_none() {
21 return Err!(Request(InvalidParam("Not allowed to set presence of other users")));
22 }
23
24 services
25 .presence
26 .set_presence_for_device(
27 body.sender_user(),
28 body.sender_device.as_deref(),
29 &body.presence,
30 body.status_msg.clone(),
31 )
32 .await?;
33
34 Ok(set_presence::v3::Response {})
35}
36
37pub(crate) async fn get_presence_route(
43 State(services): State<crate::State>,
44 body: Ruma<get_presence::v3::Request>,
45) -> Result<get_presence::v3::Response> {
46 if !services.config.allow_local_presence {
47 return Err!(Request(Forbidden("Presence is disabled on this server",)));
48 }
49
50 let mut presence_event = None;
51 let has_shared_rooms = services
52 .state_cache
53 .user_sees_user(body.sender_user(), &body.user_id)
54 .await;
55
56 if has_shared_rooms
57 && let Ok(presence) = services
58 .presence
59 .get_presence(&body.user_id)
60 .await
61 {
62 presence_event = Some(presence);
63 }
64
65 match presence_event {
66 | Some(presence) => {
67 let status_msg = if presence
68 .content
69 .status_msg
70 .as_ref()
71 .is_some_and(String::is_empty)
72 {
73 None
74 } else {
75 presence.content.status_msg
76 };
77
78 let last_active_ago = match presence.content.currently_active {
79 | Some(true) => None,
80 | _ => presence
81 .content
82 .last_active_ago
83 .map(|millis| Duration::from_millis(millis.into())),
84 };
85
86 Ok(get_presence::v3::Response {
87 status_msg,
89 currently_active: presence.content.currently_active,
90 last_active_ago,
91 presence: presence.content.presence,
92 })
93 },
94 | _ => Err!(Request(NotFound("Presence state for this user was not found"))),
95 }
96}