diff --git a/src/base.rs b/src/base.rs index 0cc57e1..4d62c58 100644 --- a/src/base.rs +++ b/src/base.rs @@ -40,7 +40,6 @@ pub async fn login(mut rx: UnboundedReceiver, session: &GlobalSignal, + avatar_url: Option, + room_id: RoomId, + user_id: UserId, ) -> anyhow::Result>; } diff --git a/src/domain/model/room.rs b/src/domain/model/room.rs index b0e1df0..c47742b 100644 --- a/src/domain/model/room.rs +++ b/src/domain/model/room.rs @@ -79,11 +79,12 @@ impl PartialEq for Room { impl Room { pub fn new( id: RoomId, - spaces: Vec, + // TODO: move space at the end of the list of params name: Option, topic: Option, is_direct: Option, state: Option, + spaces: Vec, ) -> Self { Self { id, @@ -93,10 +94,8 @@ impl Room { is_direct, state, avatar: RefCell::new(None), - invitations: RefCell::new(HashMap::new()), members: RefCell::new(HashMap::new()), - spaces, messaging_provider: None, @@ -133,11 +132,6 @@ impl Room { self.topic = topic; } - #[allow(dead_code)] - pub fn is_direct(&self) -> &Option { - &self.is_direct - } - #[allow(dead_code)] pub fn state(&self) -> &Option { &self.state @@ -160,6 +154,29 @@ impl Room { store.on_invitation(invitation); } } + + #[instrument(name = "Room", skip_all)] + fn add_member(&self, member: RoomMember) { + let mut members = self.members.borrow_mut(); + + members.insert(member.id().clone(), member.clone()); + + // USe the member display name to name the room if it's direct and has no name set. + if self.name.borrow().is_none() && members.len() == 1 { + if let Some(member_display_name) = member.display_name() { + let name = Some(member_display_name.clone()); + + self.name.borrow_mut().clone_from(&name); + + if let Some(store) = self.store.borrow().as_ref() { + store.on_new_name(name); + } + } + } + + if let Some(store) = self.store.borrow().as_ref() { + store.on_new_member(member); + } } pub async fn get_avatar(&self) -> Option { @@ -171,7 +188,7 @@ impl Room { return Some(avatar); } else { debug!("The room has no avatar... let's generate one"); - match self.render_room_avatar_with_members().await { + match self.gen_room_avatar_with_members().await { Ok(avatar) => { if let Some(avatar) = avatar { return Some(avatar); @@ -190,50 +207,42 @@ impl Room { self.avatar.borrow().clone() } - async fn render_room_avatar_with_members(&self) -> anyhow::Result> { - if let Some(requester) = &self.messaging_provider { - match requester.get_members(&self.id).await { - Ok(members) => { - let mut account_member = None::<&RoomMember>; - let mut other_members = Vec::<&RoomMember>::new(); + #[instrument(name = "Room", skip_all)] + async fn gen_room_avatar_with_members(&self) -> anyhow::Result> { + let mut account_member = None::<&RoomMember>; + let mut other_members = Vec::<&RoomMember>::new(); - for member in &members { - if member.is_account_user() { - account_member = Some(member); - } else { - other_members.push(member); - } - } - - let other_avatars_futures = - join_all(other_members.iter().map(|member| member.get_avatar())); - - let (other_avatars, account_avatar) = if let Some(account_member) = - account_member - { - join(other_avatars_futures, account_member.get_avatar()).await - } else { - ( - join_all(other_members.iter().map(|member| member.get_avatar())).await, - None, - ) - }; - - let other_avatars: Vec> = other_avatars.into_iter().flatten().collect(); - - return Ok(Some(create_mozaik( - 256, - 256, - &other_avatars, - &account_avatar, - ))); - } - Err(err) => { - error!("err={}", err); - } + let members = self.members.borrow(); + for member in members.values() { + if member.is_account_user() { + account_member = Some(member); + } else { + other_members.push(member); } } - Ok(None) + + let other_avatars_futures = + join_all(other_members.iter().map(|member| member.get_avatar())); + + let (other_avatars, account_avatar) = if let Some(account_member) = account_member { + join(other_avatars_futures, account_member.get_avatar()).await + } else { + ( + join_all(other_members.iter().map(|member| member.get_avatar())).await, + None, + ) + }; + + let other_avatars: Vec> = other_avatars.into_iter().flatten().collect(); + + if account_avatar.is_some() || !other_avatars.is_empty() { + let _guard = debug_span!("AvatarRendering").entered(); + Ok(Some( + create_mozaik(256, 256, other_avatars, account_avatar).await, + )) + } else { + Ok(None) + } } } @@ -277,6 +286,10 @@ impl RoomMessagingConsumerInterface for Room { #[instrument(name = "Room", skip_all)] async fn on_new_avatar(&self, avatar: Option) { trace!("on_new_avatar"); + self.avatar.borrow_mut().clone_from(&avatar); + if let Some(store) = self.store.borrow().as_ref() { + store.on_new_avatar(avatar); + } } } @@ -294,6 +307,10 @@ impl RoomStoreConsumerInterface for Room { self.name.borrow().clone() } + async fn avatar(&self) -> Option { + self.get_avatar().await + } + fn spaces(&self) -> &Vec { &self.spaces } diff --git a/src/domain/model/room_member.rs b/src/domain/model/room_member.rs index 8714c74..ac7cdd2 100644 --- a/src/domain/model/room_member.rs +++ b/src/domain/model/room_member.rs @@ -4,7 +4,7 @@ use std::{ rc::Rc, }; -use matrix_sdk::{room::RoomMember as MatrixRoomMember, ruma::OwnedRoomId}; +use matrix_sdk::ruma::OwnedMxcUri; use tracing::error; use super::{ @@ -13,9 +13,14 @@ use super::{ room::RoomId, }; +pub type AvatarUrl = OwnedMxcUri; + #[derive(Clone)] pub struct RoomMember { id: UserId, + + display_name: Option, + avatar_url: Option, room_id: RoomId, is_account_user: bool, @@ -26,14 +31,18 @@ pub struct RoomMember { } impl RoomMember { - fn new( + pub fn new( id: UserId, + display_name: Option, + avatar_url: Option, room_id: RoomId, is_account_user: bool, messaging_provider: Rc, ) -> Self { Self { id, + display_name, + avatar_url, room_id, is_account_user, avatar: RefCell::new(None), @@ -41,24 +50,14 @@ impl RoomMember { } } - // TODO: Use a factory instead... - pub async fn from_matrix( - matrix_room_member: &MatrixRoomMember, - room_id: &OwnedRoomId, - messaging_provider: Rc, - ) -> Self { - Self::new( - UserId::from(matrix_room_member.user_id()), - room_id.clone(), - matrix_room_member.is_account_user(), - messaging_provider, - ) - } - pub fn id(&self) -> &UserId { &self.id } + pub fn display_name(&self) -> &Option { + &self.display_name + } + #[allow(dead_code)] pub fn room_id(&self) -> &RoomId { &self.room_id @@ -71,7 +70,11 @@ impl RoomMember { pub async fn get_avatar(&self) -> Option { match self .messaging_provider - .get_avatar(&self.room_id, &self.id) + .get_avatar( + self.avatar_url.clone(), + self.room_id.clone(), + self.id.clone(), + ) .await { Ok(avatar) => avatar, diff --git a/src/infrastructure/messaging/matrix/client.rs b/src/infrastructure/messaging/matrix/client.rs index 33f9eee..008ce76 100644 --- a/src/infrastructure/messaging/matrix/client.rs +++ b/src/infrastructure/messaging/matrix/client.rs @@ -723,41 +723,39 @@ impl Client { async fn get_room_member_avatar( &self, + avatar_url: &Option, room_id: &RoomId, user_id: &UserId, - avatar_url: &Option, ) -> anyhow::Result>> { let client = self.client.as_ref().unwrap(); if let Some(room) = client.get_room(room_id) { - // TODO: Check if we can get member before fetching the data and received an error... - - match room.get_member(user_id).await { - Ok(room_member) => { - if let Some(room_member) = room_member { - let res = match room_member - .avatar(MediaFormat::Thumbnail(MediaThumbnailSize { - method: Method::Scale, - width: uint!(256), - height: uint!(256), - })) - .await - { - Ok(avatar) => Ok(avatar), - Err(err) => Err(err.into()), - }; - return res; - } + match avatar_url { + Some(avatar_url) => { + let thumbnail = self.get_thumbnail(avatar_url.clone()).await; + return Ok(Some(thumbnail?)); } - Err(err) => { - warn!("Unable to get room member {user_id}: {err}"); - if let Some(avatar_url) = avatar_url { - let thumbnail = self.get_thumbnail(avatar_url.clone()).await; - return Ok(Some(thumbnail?)); - } else { - debug!("No avatar url set for the {room_id} room"); + None => match room.get_member(user_id).await { + Ok(room_member) => { + if let Some(room_member) = room_member { + let res = match room_member + .avatar(MediaFormat::Thumbnail(MediaThumbnailSize { + method: Method::Scale, + width: uint!(256), + height: uint!(256), + })) + .await + { + Ok(avatar) => Ok(avatar), + Err(err) => Err(err.into()), + }; + return res; + } } - } + Err(err) => { + warn!("Unable to get room member {user_id}: {err}"); + } + }, } } Ok(None) @@ -799,10 +797,10 @@ impl Client { WorkerTask::GetRoomAvatar(id, reply) => { reply.send(self.get_room_avatar(&id).await).await; } - WorkerTask::GetRoomMemberAvatar(room_id, user_id, avatar_url, reply) => { + WorkerTask::GetRoomMemberAvatar(avatar_url, room_id, user_id, reply) => { reply .send( - self.get_room_member_avatar(&room_id, &user_id, &avatar_url) + self.get_room_member_avatar(&avatar_url, &room_id, &user_id) .await, ) .await; diff --git a/src/infrastructure/messaging/matrix/requester.rs b/src/infrastructure/messaging/matrix/requester.rs index 63bc10a..85f7f29 100644 --- a/src/infrastructure/messaging/matrix/requester.rs +++ b/src/infrastructure/messaging/matrix/requester.rs @@ -242,7 +242,7 @@ impl AccountMessagingProviderInterface for Requester { new_room_tx, span ) => { - let mut room = Room::new(id, spaces, name, topic, is_direct, Some(state)); + let mut room = Room::new(id, name, topic, is_direct, Some(state), spaces); let room_id = room.id().clone(); room.set_messaging_provider(client.clone()); @@ -371,16 +371,16 @@ impl SpaceMessagingProviderInterface for Requester {} impl MemberMessagingProviderInterface for Requester { async fn get_avatar( &self, - room_id: &RoomId, - user_id: &UserId, - avatar_url: &Option, + avatar_url: Option, + room_id: RoomId, + user_id: UserId, ) -> anyhow::Result> { request_to_worker!( self, WorkerTask::GetRoomMemberAvatar, - room_id.clone(), - user_id.clone(), - avatar_url.clone() + avatar_url, + room_id, + user_id ) } } diff --git a/src/infrastructure/messaging/matrix/worker_tasks.rs b/src/infrastructure/messaging/matrix/worker_tasks.rs index 74fdb0f..e8bb291 100644 --- a/src/infrastructure/messaging/matrix/worker_tasks.rs +++ b/src/infrastructure/messaging/matrix/worker_tasks.rs @@ -18,9 +18,9 @@ pub enum WorkerTask { GetRoomAvatar(OwnedRoomId, Sender>>>), GetRoomMemberAvatar( + Option, OwnedRoomId, OwnedUserId, - Option, Sender>>>, ), } @@ -57,9 +57,9 @@ impl Debug for WorkerTask { .finish(), WorkerTask::GetRoomMemberAvatar(room_id, user_id, avatar_url, _) => f .debug_tuple("WorkerTask::GetRoomMemberAvatar") + .field(avatar_url) .field(room_id) .field(user_id) - .field(avatar_url) .finish(), } }