feat(presence): implement presence functionality

This commit is contained in:
Jakub Kubík 2023-07-10 16:41:00 +02:00 committed by girlbossceo
parent 22eff2d29c
commit ba03edfae9
12 changed files with 545 additions and 354 deletions

View file

@ -1,5 +1,8 @@
use crate::{services, utils, Result, Ruma};
use ruma::api::client::presence::{get_presence, set_presence};
use crate::{services, Error, Result, Ruma};
use ruma::api::client::{
error::ErrorKind,
presence::{get_presence, set_presence},
};
use std::time::Duration;
/// # `PUT /_matrix/client/r0/presence/{userId}/status`
@ -9,28 +12,16 @@ pub async fn set_presence_route(
body: Ruma<set_presence::v3::Request>,
) -> Result<set_presence::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
for room_id in services().rooms.state_cache.rooms_joined(sender_user) {
let room_id = room_id?;
services().rooms.edus.presence.update_presence(
sender_user,
services().rooms.edus.presence.set_presence(
&room_id,
ruma::events::presence::PresenceEvent {
content: ruma::events::presence::PresenceEventContent {
avatar_url: services().users.avatar_url(sender_user)?,
currently_active: None,
displayname: services().users.displayname(sender_user)?,
last_active_ago: Some(
utils::millis_since_unix_epoch()
.try_into()
.expect("time is valid"),
),
presence: body.presence.clone(),
status_msg: body.status_msg.clone(),
},
sender: sender_user.clone(),
},
sender_user,
body.presence.clone(),
None,
None,
body.status_msg.clone(),
)?;
}
@ -60,7 +51,7 @@ pub async fn get_presence_route(
.rooms
.edus
.presence
.get_last_presence_event(sender_user, &room_id)?
.get_presence(&room_id, sender_user)?
{
presence_event = Some(presence);
break;
@ -79,6 +70,9 @@ pub async fn get_presence_route(
presence: presence.content.presence,
})
} else {
todo!();
Err(Error::BadRequest(
ErrorKind::NotFound,
"Presence state for this used was not found",
))
}
}

View file

@ -1,4 +1,4 @@
use crate::{service::pdu::PduBuilder, services, utils, Error, Result, Ruma};
use crate::{service::pdu::PduBuilder, services, Error, Result, Ruma};
use ruma::{
api::{
client::{
@ -10,6 +10,7 @@ use ruma::{
federation::{self, query::get_profile_information::v1::ProfileField},
},
events::{room::member::RoomMemberEventContent, StateEventType, TimelineEventType},
presence::PresenceState,
};
use serde_json::value::to_raw_value;
use std::sync::Arc;
@ -89,29 +90,15 @@ pub async fn set_displayname_route(
&room_id,
&state_lock,
);
// Presence update
services().rooms.edus.presence.update_presence(
sender_user,
&room_id,
ruma::events::presence::PresenceEvent {
content: ruma::events::presence::PresenceEventContent {
avatar_url: services().users.avatar_url(sender_user)?,
currently_active: None,
displayname: services().users.displayname(sender_user)?,
last_active_ago: Some(
utils::millis_since_unix_epoch()
.try_into()
.expect("time is valid"),
),
presence: ruma::presence::PresenceState::Online,
status_msg: None,
},
sender: sender_user.clone(),
},
)?;
}
// Presence update
services()
.rooms
.edus
.presence
.ping_presence(sender_user, PresenceState::Online)?;
Ok(set_display_name::v3::Response {})
}
@ -224,29 +211,15 @@ pub async fn set_avatar_url_route(
&room_id,
&state_lock,
);
// Presence update
services().rooms.edus.presence.update_presence(
sender_user,
&room_id,
ruma::events::presence::PresenceEvent {
content: ruma::events::presence::PresenceEventContent {
avatar_url: services().users.avatar_url(sender_user)?,
currently_active: None,
displayname: services().users.displayname(sender_user)?,
last_active_ago: Some(
utils::millis_since_unix_epoch()
.try_into()
.expect("time is valid"),
),
presence: ruma::presence::PresenceState::Online,
status_msg: None,
},
sender: sender_user.clone(),
},
)?;
}
// Presence update
services()
.rooms
.edus
.presence
.ping_presence(sender_user, PresenceState::Online)?;
Ok(set_avatar_url::v3::Response {})
}

View file

@ -170,8 +170,12 @@ async fn sync_helper(
body: sync_events::v3::Request,
// bool = caching allowed
) -> Result<(sync_events::v3::Response, bool), Error> {
// TODO: match body.set_presence {
services().rooms.edus.presence.ping_presence(&sender_user)?;
// Presence update
services()
.rooms
.edus
.presence
.ping_presence(&sender_user, body.set_presence)?;
// Setup watchers, so if there's no response, we can wait for them
let watcher = services().globals.watch(&sender_user, &sender_device);
@ -248,36 +252,36 @@ async fn sync_helper(
}
// Take presence updates from this room
for (user_id, presence) in services()
for presence_data in services()
.rooms
.edus
.presence
.presence_since(&room_id, since)?
.presence_since(&room_id, since)
{
let (user_id, _, presence_event) = presence_data?;
match presence_updates.entry(user_id) {
Entry::Vacant(v) => {
v.insert(presence);
Entry::Vacant(slot) => {
slot.insert(presence_event);
}
Entry::Occupied(mut o) => {
let p = o.get_mut();
Entry::Occupied(mut slot) => {
let curr_event = slot.get_mut();
let curr_content = &mut curr_event.content;
let new_content = presence_event.content;
// Update existing presence event with more info
p.content.presence = presence.content.presence;
if let Some(status_msg) = presence.content.status_msg {
p.content.status_msg = Some(status_msg);
}
if let Some(last_active_ago) = presence.content.last_active_ago {
p.content.last_active_ago = Some(last_active_ago);
}
if let Some(displayname) = presence.content.displayname {
p.content.displayname = Some(displayname);
}
if let Some(avatar_url) = presence.content.avatar_url {
p.content.avatar_url = Some(avatar_url);
}
if let Some(currently_active) = presence.content.currently_active {
p.content.currently_active = Some(currently_active);
}
curr_content.presence = new_content.presence;
curr_content.status_msg =
curr_content.status_msg.clone().or(new_content.status_msg);
curr_content.last_active_ago =
curr_content.last_active_ago.or(new_content.last_active_ago);
curr_content.displayname =
curr_content.displayname.clone().or(new_content.displayname);
curr_content.avatar_url =
curr_content.avatar_url.clone().or(new_content.avatar_url);
curr_content.currently_active = curr_content
.currently_active
.or(new_content.currently_active);
}
}
}

View file

@ -838,7 +838,20 @@ pub async fn send_transaction_message_route(
.filter_map(|edu| serde_json::from_str::<Edu>(edu.json().get()).ok())
{
match edu {
Edu::Presence(_) => {}
Edu::Presence(presence) => {
for update in presence.push {
for room_id in services().rooms.state_cache.rooms_joined(&update.user_id) {
services().rooms.edus.presence.set_presence(
&room_id?,
&update.user_id,
update.presence.clone(),
Some(update.currently_active),
Some(update.last_active_ago),
update.status_msg.clone(),
)?;
}
}
}
Edu::Receipt(receipt) => {
for (room_id, room_updates) in receipt.receipts {
for (user_id, user_updates) in room_updates.read {