feat: implement GET /presence
This commit is contained in:
		
							parent
							
								
									767fe76d3e
								
							
						
					
					
						commit
						24793891e0
					
				
					 4 changed files with 92 additions and 5 deletions
				
			
		|  | @ -108,5 +108,5 @@ maintainer-scripts = "debian/" | |||
| systemd-units = { unit-name = "matrix-conduit" } | ||||
| 
 | ||||
| # For flamegraphs: | ||||
| #[profile.release] | ||||
| #debug = true | ||||
| [profile.release] | ||||
| debug = true | ||||
|  |  | |||
|  | @ -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!(); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue