From 0190cf91659d346beeb843616fa39e37829635ae Mon Sep 17 00:00:00 2001 From: Adrien Date: Fri, 10 May 2024 19:13:46 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Rework=20the=20Room=20enti?= =?UTF-8?q?ty?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/domain/model/room.rs | 250 ++++++++++++++++++++++++--------------- 1 file changed, 157 insertions(+), 93 deletions(-) diff --git a/src/domain/model/room.rs b/src/domain/model/room.rs index 131deeb..a54cf01 100644 --- a/src/domain/model/room.rs +++ b/src/domain/model/room.rs @@ -1,24 +1,52 @@ use std::cell::RefCell; -use std::{collections::HashMap, sync::Arc}; +use std::collections::HashMap; +use std::rc::Rc; +use async_trait::async_trait; +use futures::future::{join, join_all}; use matrix_sdk::ruma::OwnedRoomId; -use matrix_sdk::{Room as MatrixRoom, RoomState as MatrixRoomState}; -use tracing::error; +use matrix_sdk::RoomState as MatrixRoomState; +use tracing::{debug, error, trace}; -pub(crate) type RoomId = OwnedRoomId; +use super::{ + common::{Avatar, UserId}, + messaging_interface::{RoomMessagingConsumerInterface, RoomMessagingProviderInterface}, + room_member::RoomMember, + space::SpaceId, + store_interface::RoomStoreProviderInterface, +}; -#[derive(Clone, Debug)] -pub(crate) struct Room { +use crate::infrastructure::services::mozaik_builder::create_mozaik; + +pub type RoomId = OwnedRoomId; + +pub struct Room { id: RoomId, - name: Option, + + #[allow(dead_code)] + spaces: Vec, + + name: RefCell>, topic: Option, is_direct: Option, state: Option, + avatar: RefCell>, + members: RefCell>, + + messaging_provider: Option>, + store: RefCell>>, +} + +impl PartialEq for Room { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } } impl Room { - fn new( + pub fn new( id: RoomId, + spaces: Vec, name: Option, topic: Option, is_direct: Option, @@ -26,120 +54,156 @@ impl Room { ) -> Self { Self { id, - name, + + spaces, + name: RefCell::new(name), topic, is_direct, state, + avatar: RefCell::new(None), + members: RefCell::new(HashMap::new()), + + messaging_provider: None, + store: RefCell::new(None), } } - // TODO: Use a factory instead... - pub async fn from_matrix_room(matrix_room: &MatrixRoom) -> Self { - // let room_topic = matrix_room.topic().map(RefCell::new); - - let id = RoomId::from(matrix_room.room_id()); - let name = matrix_room.name(); - let room_topic = matrix_room.topic(); - let is_direct = match matrix_room.is_direct().await { - Ok(is_direct) => Some(is_direct), - Err(err) => { - error!("Unable to know if the room \"{id}\" is direct: {err}"); - None - } - }; - let state = Some(matrix_room.state()); - - Self::new(id, name, room_topic, is_direct, state) - - // room.timeline.subscribe().await - - // Arc::new(matrix_room.to_owned()), + pub fn set_messaging_provider( + &mut self, + messaging_provider: Rc, + ) { + self.messaging_provider = Some(messaging_provider); } - pub fn id(&self) -> &OwnedRoomId { + pub fn set_store(&self, store: Option>) { + *self.store.borrow_mut() = store; + } + + pub fn id(&self) -> &RoomId { &self.id } - pub fn name(&self) -> &Option { - &self.name + pub fn name(&self) -> Option { + self.name.borrow().clone() } + #[allow(dead_code)] pub fn topic(&self) -> &Option { &self.topic } + + #[allow(dead_code)] pub fn set_topic(&mut self, topic: Option) { 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 } + + #[allow(dead_code)] pub fn is_invited(&self) -> Option { - match self.state { - Some(state) => Some(state == MatrixRoomState::Invited), - None => None, + self.state.map(|state| state == MatrixRoomState::Invited) + } + + #[allow(dead_code)] + fn add_member(&self, member: RoomMember) { + self.members.borrow_mut().insert(member.id.clone(), member); + } + + pub async fn get_avatar(&self) -> Option { + if self.avatar.borrow().is_none() { + if let Some(requester) = &self.messaging_provider { + let resp = requester.get_avatar(&self.id).await; + if let Ok(avatar) = resp { + if let Some(avatar) = avatar { + return Some(avatar); + } else { + debug!("The room has no avatar... let's generate one"); + match self.render_room_avatar_with_members().await { + Ok(avatar) => { + if let Some(avatar) = avatar { + return Some(avatar); + } + } + Err(err) => { + error!("err={}", err); + } + } + } + } else { + error!("err={:?}", resp); + } + } } + 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(); + + 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); + } + } + } + Ok(None) } } -pub type ByIdRooms = HashMap>; - -// pub type ByIdRooms = HashMap>; - -// #[derive(Clone)] -// pub struct Room { -// // pub matrix_room: Arc, -// pub topic: Option>, -// pub members: HashMap, -// pub is_direct: Option, -// // pub timeline: Arc, -// } - -// impl Room { -// pub async fn new( -// matrix_room: Arc, -// topic: Option>, -// is_direct: Option, -// ) -> Self { -// // TODO: Filter events -// // let timeline = Arc::new(matrix_room.timeline_builder().build().await.ok().unwrap()); -// Self { -// matrix_room, -// topic, -// members: HashMap::new(), -// is_direct, -// // timeline, -// } -// } - -// pub async fn from_matrix_room(matrix_room: &MatrixRoom) -> Self { -// let room_topic = matrix_room.topic().map(RefCell::new); - -// Self::new( -// Arc::new(matrix_room.to_owned()), -// room_topic, -// matrix_room.is_direct().await.ok(), -// ) -// .await -// // room.timeline.subscribe().await -// } - -// pub fn name(&self) -> Option { -// self.matrix_room.name() -// } - -// pub fn id(&self) -> OwnedRoomId { -// OwnedRoomId::from(self.matrix_room.room_id()) -// } -// } - -// impl PartialEq for Room { -// fn eq(&self, other: &Self) -> bool { -// // TODO: Look for a better way to compare Matrix rooms -// self.matrix_room.room_id() == other.matrix_room.room_id() -// } -// } +#[async_trait(?Send)] +impl RoomMessagingConsumerInterface for Room { + async fn on_invitation(&self) { + trace!("Room::on_invitation"); + } + async fn on_membership(&self, member: RoomMember) { + trace!("Room::on_membership({:?})", member); + } + async fn on_new_topic(&self, topic: Option) { + trace!("Room::on_new_topic({:?})", topic); + } + async fn on_new_name(&self, name: Option) { + trace!("Room::on_new_name({:?})", name); + } +}