feat: implement GET /presence

This commit is contained in:
Timo Kösters 2021-05-14 11:03:18 +02:00
parent 767fe76d3e
commit 24793891e0
No known key found for this signature in database
GPG key ID: 24DA7517711A2BA4
4 changed files with 92 additions and 5 deletions

View file

@ -108,5 +108,5 @@ maintainer-scripts = "debian/"
systemd-units = { unit-name = "matrix-conduit" }
# For flamegraphs:
#[profile.release]
#debug = true
[profile.release]
debug = true

View file

@ -1,10 +1,10 @@
use super::State;
use crate::{utils, ConduitResult, Database, Ruma};
use ruma::api::client::r0::presence::set_presence;
use std::convert::TryInto;
use ruma::api::client::r0::presence::{get_presence, set_presence};
use std::{convert::TryInto, time::Duration};
#[cfg(feature = "conduit_bin")]
use rocket::put;
use rocket::{get, put};
#[cfg_attr(
feature = "conduit_bin",
@ -46,3 +46,48 @@ pub async fn set_presence_route(
Ok(set_presence::Response.into())
}
#[cfg_attr(
feature = "conduit_bin",
get("/_matrix/client/r0/presence/<_>/status", data = "<body>")
)]
#[tracing::instrument(skip(db, body))]
pub async fn get_presence_route(
db: State<'_, Database>,
body: Ruma<get_presence::Request<'_>>,
) -> ConduitResult<get_presence::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let mut presence_event = None;
for room_id in db
.rooms
.get_shared_rooms(vec![sender_user.clone(), body.user_id.clone()])
{
let room_id = room_id?;
if let Some(presence) = db
.rooms
.edus
.get_last_presence_event(&sender_user, &room_id)?
{
presence_event = Some(presence);
}
}
if let Some(presence) = presence_event {
Ok(get_presence::Response {
// TODO: Should ruma just use the presenceeventcontent type here?
status_msg: presence.content.status_msg,
currently_active: presence.content.currently_active,
last_active_ago: presence
.content
.last_active_ago
.map(|millis| Duration::from_millis(millis.into())),
presence: presence.content.presence,
}
.into())
} else {
todo!();
}
}

View file

@ -367,6 +367,47 @@ impl RoomEdus {
.transpose()
}
pub fn get_last_presence_event(
&self,
user_id: &UserId,
room_id: &RoomId,
) -> Result<Option<PresenceEvent>> {
let last_update = match self.last_presence_update(user_id)? {
Some(last) => last,
None => return Ok(None),
};
let mut presence_id = room_id.as_bytes().to_vec();
presence_id.push(0xff);
presence_id.extend_from_slice(&last_update.to_be_bytes());
presence_id.push(0xff);
presence_id.extend_from_slice(&user_id.as_bytes());
self.presenceid_presence
.get(presence_id)?
.map(|value| {
let mut presence = serde_json::from_slice::<PresenceEvent>(&value)
.map_err(|_| Error::bad_database("Invalid presence event in db."))?;
let current_timestamp: UInt = utils::millis_since_unix_epoch()
.try_into()
.expect("time is valid");
if presence.content.presence == PresenceState::Online {
// Don't set last_active_ago when the user is online
presence.content.last_active_ago = None;
} else {
// Convert from timestamp to duration
presence.content.last_active_ago = presence
.content
.last_active_ago
.map(|timestamp| current_timestamp - timestamp);
}
Ok(presence)
})
.transpose()
}
/// Sets all users to offline who have been quiet for too long.
pub fn presence_maintain(
&self,

View file

@ -69,6 +69,7 @@ fn setup_rocket(config: Figment, data: Database) -> rocket::Rocket<rocket::Build
client_server::get_avatar_url_route,
client_server::get_profile_route,
client_server::set_presence_route,
client_server::get_presence_route,
client_server::upload_keys_route,
client_server::get_keys_route,
client_server::claim_keys_route,