From 79e8dea622b3741fb67585ebe35de2d3e7514f0a Mon Sep 17 00:00:00 2001 From: Adrien Date: Fri, 10 May 2024 18:05:25 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A7=20Add=20Account=20identity=20and?= =?UTF-8?q?=20messaging=20and=20store=20interfaces?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 1 + src/domain/model/account.rs | 127 ++++++++++++++++++++++++ src/domain/model/common.rs | 7 ++ src/domain/model/messaging_interface.rs | 68 +++++++++++++ src/domain/model/mod.rs | 4 + src/domain/model/store_interface.rs | 23 +++++ 6 files changed, 230 insertions(+) create mode 100644 src/domain/model/account.rs create mode 100644 src/domain/model/common.rs create mode 100644 src/domain/model/messaging_interface.rs create mode 100644 src/domain/model/store_interface.rs diff --git a/Cargo.toml b/Cargo.toml index 452401f..a41d243 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ tracing = "0.1.40" tracing-web = "0.1.3" tracing-subscriber = "0.3.18" git-version = "0.3.9" +async-trait = "0.1.80" [target.'cfg(target_family = "wasm")'.dependencies] web-sys = "0.3.69" diff --git a/src/domain/model/account.rs b/src/domain/model/account.rs new file mode 100644 index 0000000..ebd4299 --- /dev/null +++ b/src/domain/model/account.rs @@ -0,0 +1,127 @@ +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; + +use async_trait::async_trait; +use tracing::error; + +use super::{ + common::PresenceState, + messaging_interface::{ + AccountMessagingConsumerInterface, AccountMessagingProviderInterface, + RoomMessagingConsumerInterface, SpaceMessagingConsumerInterface, + }, + room::{Room, RoomId}, + space::{Space, SpaceId}, + store_interface::AccountStoreProviderInterface, +}; + +type Rooms = HashMap>; +type Spaces = HashMap>; + +pub struct Account { + display_name: RefCell>, + avatar: RefCell>>, + + #[allow(dead_code)] + presence_state: RefCell>, + + by_id_rooms: RefCell, + by_id_spaces: RefCell, + + messaging_provider: Option>, + store: &'static dyn AccountStoreProviderInterface, +} + +impl Account { + pub fn new(store: &'static dyn AccountStoreProviderInterface) -> Self { + Self { + display_name: RefCell::new(None), + avatar: RefCell::new(None), + presence_state: RefCell::new(None), + + by_id_rooms: RefCell::new(Rooms::new()), + by_id_spaces: RefCell::new(Spaces::new()), + + messaging_provider: None, + store, + } + } + + pub fn set_messaging_provider(&mut self, provider: Rc) { + self.messaging_provider = Some(provider.clone()); + } + + pub fn get_room(&self, room_id: &RoomId) -> Option> { + self.by_id_rooms.borrow().get(room_id).cloned() + } + + pub async fn get_display_name(&self) -> &RefCell> { + if self.display_name.borrow().is_none() { + if let Some(requester) = &self.messaging_provider { + let resp = requester.get_display_name().await; + if let Ok(display_name) = resp { + if let Some(display_name) = display_name { + self.display_name.borrow_mut().replace(display_name); + } else { + self.display_name.borrow_mut().take(); + } + } else { + error!("err={:?}", resp); + } + } + } + &self.display_name + } + + pub async fn get_avatar(&self) -> &RefCell>> { + if self.avatar.borrow().is_none() { + if let Some(requester) = &self.messaging_provider { + let resp = requester.get_avatar().await; + if let Ok(avatar) = resp { + if let Some(avatar) = avatar { + self.avatar.borrow_mut().replace(avatar); + } else { + self.avatar.borrow_mut().take(); + } + } else { + error!("err={:?}", resp); + } + } + } + &self.avatar + } +} + +#[async_trait(?Send)] +impl AccountMessagingConsumerInterface for Account { + async fn on_new_room(&self, room: Room) -> Rc { + let room_id = room.id().clone(); + let room = Rc::new(room); + + self.by_id_rooms + .borrow_mut() + .insert(room_id, Rc::clone(&room)); + + let room_store = Box::new(self.store.on_new_room(Rc::clone(&room))); + + room.set_store(Some(room_store)); + + room + } + + async fn on_new_space(&self, space: Space) -> Rc { + let space_id = space.id().clone(); + let space = Rc::new(space); + + self.by_id_spaces + .borrow_mut() + .insert(space_id, Rc::clone(&space)); + + let space_store = Box::new(self.store.on_new_space(Rc::clone(&space))); + + space.set_store(Some(space_store)); + + space + } +} diff --git a/src/domain/model/common.rs b/src/domain/model/common.rs new file mode 100644 index 0000000..ed71f00 --- /dev/null +++ b/src/domain/model/common.rs @@ -0,0 +1,7 @@ +use matrix_sdk::ruma::{presence::PresenceState as MatrixPresenceState, OwnedUserId}; + +pub type Avatar = Vec; + +pub type PresenceState = MatrixPresenceState; + +pub type UserId = OwnedUserId; diff --git a/src/domain/model/messaging_interface.rs b/src/domain/model/messaging_interface.rs new file mode 100644 index 0000000..9031e6d --- /dev/null +++ b/src/domain/model/messaging_interface.rs @@ -0,0 +1,68 @@ +use std::rc::Rc; + +use async_trait::async_trait; +use tokio::sync::broadcast::Receiver; + +use crate::infrastructure::messaging::matrix::worker_tasks::AccountEvent; + +use super::{ + common::{Avatar, UserId}, + room::{Room, RoomId}, + room_member::RoomMember, + space::Space, +}; + +#[async_trait(?Send)] +pub trait AccountMessagingConsumerInterface { + async fn on_new_room(&self, room: Room) -> Rc; + async fn on_new_space(&self, space: Space) -> Rc; +} + +#[async_trait(?Send)] +pub trait AccountMessagingProviderInterface { + async fn get_display_name(&self) -> anyhow::Result>; + async fn get_avatar(&self) -> anyhow::Result>>; + + async fn run_forever( + &self, + account_events_consumer: &dyn AccountMessagingConsumerInterface, + account_events_receiver: Receiver, + ) -> anyhow::Result<()>; +} + +#[async_trait(?Send)] +pub trait RoomMessagingConsumerInterface { + async fn on_invitation(&self) {} + + async fn on_new_topic(&self, _topic: Option) {} + async fn on_new_name(&self, _name: Option) {} + + #[allow(dead_code)] + async fn on_membership(&self, _member: RoomMember) {} +} + +#[async_trait(?Send)] +pub trait RoomMessagingProviderInterface { + async fn get_avatar(&self, id: &RoomId) -> anyhow::Result>; + async fn get_members(&self, id: &RoomId) -> anyhow::Result>; +} + +#[async_trait(?Send)] +pub trait SpaceMessagingConsumerInterface { + async fn on_child(&self, _room_id: RoomId) {} + async fn on_new_topic(&self, _topic: Option) {} + async fn on_new_name(&self, _name: Option) {} +} + +#[async_trait(?Send)] +pub trait SpaceMessagingProviderInterface {} + +// TODO: Rework +#[async_trait(?Send)] +pub trait MemberMessagingProviderInterface { + async fn get_avatar( + &self, + room_id: &RoomId, + user_id: &UserId, + ) -> anyhow::Result>; +} diff --git a/src/domain/model/mod.rs b/src/domain/model/mod.rs index 87868cd..9eca3df 100644 --- a/src/domain/model/mod.rs +++ b/src/domain/model/mod.rs @@ -1,2 +1,6 @@ +pub(crate) mod account; +pub(crate) mod common; +pub(crate) mod messaging_interface; pub(crate) mod room; pub(crate) mod session; +pub(crate) mod store_interface; diff --git a/src/domain/model/store_interface.rs b/src/domain/model/store_interface.rs new file mode 100644 index 0000000..7a097a9 --- /dev/null +++ b/src/domain/model/store_interface.rs @@ -0,0 +1,23 @@ +use std::rc::Rc; + +use super::room::Room; +use super::space::Space; +use crate::base::{StoreRoom, StoreSpace}; + +#[allow(dead_code)] +pub trait AccountStoreConsumerInterface {} + +pub trait AccountStoreProviderInterface { + fn on_new_room(&self, room: Rc) -> StoreRoom; + fn on_new_space(&self, space: Rc) -> StoreSpace; +} + +#[allow(dead_code)] +pub trait RoomStoreConsumerInterface {} +pub trait RoomStoreProviderInterface {} + +#[allow(dead_code)] +pub trait SpaceStoreConsumerInterface {} +pub trait SpaceStoreProviderInterface { + fn set_name(&mut self, _name: Option) {} +}