// Cf. https://dioxuslabs.com/learn/0.4/reference/use_coroutine // In order to use/run the rx.next().await statement you will need to extend the [Stream] trait // (used by [UnboundedReceiver]) by adding 'futures_util' as a dependency to your project // and adding the use futures_util::stream::StreamExt; use futures_util::stream::StreamExt; use std::cell::RefCell; use std::{collections::HashMap, sync::Arc}; use crate::infrastructure::messaging::matrix::client::{Client, RoomEvent}; use crate::infrastructure::messaging::matrix::requester::{Receivers, Requester}; use crate::infrastructure::messaging::matrix::worker_tasks::LoginStyle; use dioxus::prelude::*; use matrix_sdk::{ room::{Room as MatrixRoom, RoomMember}, ruma::{OwnedRoomId, OwnedUserId}, }; use tokio::select; use log::{debug, error, warn}; use crate::ui::components::chats_window::interface::Interface as ChatsWinInterface; // #[derive(Clone, Debug)] // pub struct UserInfo { // pub avatar_url: Option, // pub display_name: Option, // pub blurhash: Option, // } // impl UserInfo { // pub fn new( // avatar_url: Option, // display_name: Option, // blurhash: Option, // ) -> Self { // Self { // avatar_url, // display_name, // blurhash, // } // } // } #[derive(Clone)] pub struct Room { pub matrix_room: Arc, pub topic: Option>, pub members: HashMap, pub is_direct: Option, } impl Room { pub fn new( matrix_room: Arc, topic: Option>, is_direct: Option, ) -> Self { Self { matrix_room, topic, members: HashMap::new(), is_direct, } } 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(), ) } 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() } } pub type ByIdRooms = HashMap>; // pub type ByIdUserInfos = HashMap; // #[derive(Clone)] // pub struct Store { // pub is_logged: bool, // pub rooms: ByIdRooms, // pub user_infos: ByIdUserInfos, // pub user_id: Option, // } // impl Store { // pub fn new() -> Self { // Self { // is_logged: false, // rooms: HashMap::new(), // user_infos: HashMap::new(), // user_id: None, // } // } // } // impl PartialEq for Store { // fn eq(&self, other: &Self) -> bool { // self.is_logged == other.is_logged // && self.user_id == other.user_id // && self.user_infos.len() == other.user_infos.len() // && self // .user_infos // .keys() // .all(|k| other.user_infos.contains_key(k)) // && self.rooms.len() == other.rooms.len() // && self.rooms.keys().all(|k| other.rooms.contains_key(k)) // } // } // impl Eq for Store {} pub struct AppSettings { pub requester: Option>, } impl AppSettings { pub fn new() -> Self { Self { requester: None } } pub fn set_requester(&mut self, requester: RefCell) { self.requester = Some(requester); } } async fn on_room(room_id: OwnedRoomId, room: Room, by_id_rooms: &GlobalSignal) { // TODO: Update rooms by_id_rooms .write() .insert(room_id, RefCell::::new(room)); } async fn on_joining_invitation( room_id: OwnedRoomId, room: Room, by_id_rooms: &GlobalSignal, ) { debug!( "You're invited to join the \"{}\" room", room.name().unwrap() ); // TODO: Update rooms by_id_rooms .write() .insert(room_id, RefCell::::new(room)); } async fn on_room_topic(room_id: OwnedRoomId, topic: String, by_id_rooms: &GlobalSignal) { if let Some(room) = by_id_rooms.read().get(&room_id) { let mut room = room.borrow_mut(); room.topic = Some(RefCell::new(topic)); } else { warn!("No room found with the \"{}\" id", room_id); } } pub async fn sync_messages(by_id_rooms: &GlobalSignal, room_id: OwnedRoomId) { error!("== sync_messages =="); } pub async fn sync_rooms( mut rx: UnboundedReceiver, receivers: Receivers, by_id_rooms: &GlobalSignal, ) { if let Some(_is_logged) = rx.next().await { let mut rooms_receiver = receivers.room_receiver.borrow_mut(); loop { // TODO: Remove select if no more receivers will be used. select! { res = rooms_receiver.recv() => { if let Ok(room_event) = res { match room_event { RoomEvent::MemberEvent(room_id, room) => on_room(room_id, room, &by_id_rooms).await, RoomEvent::InviteEvent(room_id, room) => on_joining_invitation(room_id, room, &by_id_rooms).await, RoomEvent::TopicEvent(room_id, topic) => on_room_topic(room_id, topic, &by_id_rooms).await, }; } }, } } } } pub async fn login( mut rx: UnboundedReceiver, app_settings: &GlobalSignal, session: &GlobalSignal, ) { while let Some(is_logged) = rx.next().await { if !is_logged { let homeserver_url = session.read().homeserver_url.clone(); let username = session.read().username.clone(); let password = session.read().password.clone(); if homeserver_url.is_some() && username.is_some() && password.is_some() { let client = Client::spawn(homeserver_url.unwrap()).await; if let Err(err) = client.init().await { error!("Following error occureds during client init: {}", err); } match client .login(LoginStyle::Password(username.unwrap(), password.unwrap())) .await { Ok(_) => { debug!("successfully logged"); session.write().is_logged = true; } Err(err) => { error!("Error during login: {err}"); // invalid_login.modify(|_| true); } } app_settings.write().set_requester(RefCell::new(client)); } else { warn!("At least one of the following values is/are invalid: homeserver, username or password"); } } else { warn!("already logged... skip login"); } } error!("=== LOGIN END ==="); } pub struct Session { pub homeserver_url: Option, pub username: Option, pub password: Option, pub is_logged: bool, } impl Session { pub fn new() -> Self { Self { homeserver_url: None, username: None, password: None, is_logged: false, } } pub fn update( &mut self, homeserver_url: Option, username: Option, password: Option, ) { self.homeserver_url = homeserver_url; self.username = username; self.password = password; } } pub static APP_SETTINGS: GlobalSignal = Signal::global(AppSettings::new); pub static ROOMS: GlobalSignal = Signal::global(ByIdRooms::new); pub static SESSION: GlobalSignal = Signal::global(Session::new); pub static CHATS_WIN_INTERFACE: GlobalSignal = Signal::global(ChatsWinInterface::new);