From c9292fd6136ac161f1aa812dbadd8f0ddbd4438e Mon Sep 17 00:00:00 2001 From: Adrien Date: Thu, 21 Dec 2023 22:07:08 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=20Remove=20data=20handlin?= =?UTF-8?q?g=20from=20components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The data sent by matrix_interface senders is now handled by the App. --- Cargo.toml | 2 + src/base.rs | 122 ++++++++++++++++++++- src/components/contacts_window/contacts.rs | 32 ------ src/components/login.rs | 35 ++---- src/components/main_window.rs | 6 +- src/main.rs | 25 ++++- src/matrix_interface/client.rs | 26 +++-- 7 files changed, 177 insertions(+), 71 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 64fa11c..9e2843f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,8 @@ tokio = "1.34.0" flume = "0.11.0" log = "0.4.20" tracing = "0.1.40" +futures-util = "0.3.29" +futures = "0.3.29" [build] target = "x86_64-unknown-linux-gnu" diff --git a/src/base.rs b/src/base.rs index 8802cfb..4a1cec0 100644 --- a/src/base.rs +++ b/src/base.rs @@ -1,13 +1,24 @@ +use futures::select; + +// 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, collections::HashMap, sync::Arc}; +use dioxus::prelude::*; use fermi::*; use matrix_sdk::room::Room as MatrixRoom; use matrix_sdk::{ room::RoomMember, ruma::{OwnedMxcUri, OwnedRoomId, OwnedUserId}, }; +use tracing::{debug, error, warn}; +use crate::matrix_interface::client::Client; use crate::matrix_interface::requester::Requester; +use crate::matrix_interface::worker_tasks::LoginStyle; #[derive(Clone, Debug)] pub struct UserInfo { @@ -107,7 +118,7 @@ impl PartialEq for Store { impl Eq for Store {} pub struct AppSettings { - pub requester: Option, + requester: Option>, pub store: Store, } @@ -118,7 +129,116 @@ impl AppSettings { store: Store::new(), } } + + pub fn set_requester(&mut self, requester: Box) { + self.requester = Some(requester); + } } pub static APP_SETTINGS: AtomRef = AtomRef(|_| AppSettings::new()); + +async fn on_room(room_option: Option, rooms_ref: &UseAtomRef) { + if let Some(room) = room_option { + let room_id = room.id(); + + // TODO: Update rooms + rooms_ref + .write() + .insert(room_id, RefCell::::new(room)); + } +} + +pub async fn sync_rooms( + mut rx: UnboundedReceiver, + app_settings_ref: UseAtomRef, + rooms_ref: UseAtomRef, +) { + error!("=== SYNC ROOMS BEG ==="); + while let Some(_is_logged) = rx.next().await { + let app_settings_ref = app_settings_ref.read(); + let requester = &app_settings_ref.requester; + + if requester.is_some() { + let rooms_receiver = &requester.as_ref().unwrap().rooms_receiver; + + let mut room_stream = rooms_receiver.stream(); + + loop { + select! { + room = room_stream.next() => on_room(room, &rooms_ref).await, + } + } + } + } +} + +pub async fn login( + mut rx: UnboundedReceiver, + app_settings_ref: UseAtomRef, + session_ref: UseAtomRef, +) { + error!("=== LOGIN BEG ==="); + + while let Some(is_logged) = rx.next().await { + error!("State updated"); + if !is_logged { + let homeserver_url = session_ref.read().homeserver_url.clone(); + let username = session_ref.read().username.clone(); + let password = session_ref.read().password.clone(); + + if homeserver_url.is_some() && username.is_some() && password.is_some() { + let client = Client::spawn(homeserver_url.unwrap()).await; + + client.init(); + + match client.login(LoginStyle::Password(username.unwrap(), password.unwrap())) { + Ok(_) => { + debug!("successfully logged"); + session_ref.write().is_logged = true; + } + Err(err) => { + error!("Error during login: {err}"); + // invalid_login.modify(|_| true); + } + } + app_settings_ref.write().set_requester(Box::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 static ROOMS: AtomRef = AtomRef(|_| ByIdRooms::new()); + +pub struct Session { + pub homeserver_url: Option, + pub username: Option, + pub password: Option, + pub is_logged: bool, +} +impl Session { + 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 SESSION: AtomRef = AtomRef(|_| Session::new()); diff --git a/src/components/contacts_window/contacts.rs b/src/components/contacts_window/contacts.rs index 020982b..7a7a495 100644 --- a/src/components/contacts_window/contacts.rs +++ b/src/components/contacts_window/contacts.rs @@ -1,13 +1,6 @@ -use std::cell::RefCell; -use std::time::Duration; - use dioxus::prelude::*; -use fermi::*; -use tokio::time::sleep; use tracing::debug; -use crate::base::AppSettings; -use crate::base::{ByIdRooms, Room, APP_SETTINGS, ROOMS}; use crate::components::contacts_window::contacts_section::{ filter_people_conversations, filter_room_conversations, ContactsSection, }; @@ -17,31 +10,6 @@ turf::style_sheet!("src/components/contacts_window/contacts.scss"); pub fn Contacts(cx: Scope) -> Element { debug!("Contacts rendering"); - let app_settings_atom = use_atom_ref(cx, &APP_SETTINGS); - let rooms_atom = use_atom_ref(cx, &ROOMS); - - async fn sync_rooms(app_settings: UseAtomRef, rooms_atom: UseAtomRef) { - loop { - let requester = &app_settings.read().requester; - - if requester.is_some() { - let rooms_receiver = &requester.as_ref().unwrap().rooms_receiver; - let room = rooms_receiver.recv_async().await.unwrap(); - let room_id = room.id(); - dbg!(&room_id); - rooms_atom - .write() - .insert(room_id, RefCell::::new(room)); - } else { - sleep(Duration::from_millis(1000)).await; - } - } - } - - use_coroutine(cx, |_: UnboundedReceiver<()>| { - sync_rooms(app_settings_atom.clone(), rooms_atom.clone()) - }); - // TODO: Test overflow // TODO: Add offline users ? cx.render(rsx! { diff --git a/src/components/login.rs b/src/components/login.rs index e6f1a0d..4f9dad2 100644 --- a/src/components/login.rs +++ b/src/components/login.rs @@ -2,9 +2,10 @@ use std::str::FromStr; use dioxus::prelude::*; use fermi::*; +use matrix_sdk::ruma::user_id; use tracing::{debug, error}; -use crate::base::APP_SETTINGS; +use crate::base::{APP_SETTINGS, SESSION}; use crate::components::avatar_selector::AvatarSelector; use crate::components::header::Header; use crate::matrix_interface::client::Client; @@ -17,9 +18,10 @@ static EMPTY_PLACEHOLDER: &str = "Tmp placeholder"; pub fn Login(cx: Scope) -> Element { debug!("Login rendering"); - let app_settings = use_atom_ref(cx, &APP_SETTINGS); + let session = use_atom_ref(cx, &SESSION); let invalid_login = use_state(cx, || false); + let login = use_ref(cx, || Login::new()); let password_class = if **invalid_login { @@ -30,32 +32,19 @@ pub fn Login(cx: Scope) -> Element { let run_matrix_client = move |_| { cx.spawn({ - to_owned![invalid_login, login, app_settings]; - let login_ref = login.read(); - let homeserver_url = login_ref.homeserver_url.clone().unwrap(); - let username = login_ref.email.clone().unwrap(); - let password = login_ref.password.clone().unwrap(); + to_owned![session, login]; async move { - let new_matrix_client = Client::spawn(homeserver_url).await; + let login_ref = login.read(); - new_matrix_client.init(); - - match new_matrix_client.login(LoginStyle::Password(username, password)) { - Ok(_) => { - debug!("successfully logged"); - app_settings.write().store.is_logged = true; - } - Err(err) => { - error!("Error during login: {err}"); - invalid_login.modify(|_| true); - } - } - - app_settings.write().requester = Some(new_matrix_client); + session.write().update( + login_ref.homeserver_url.clone(), + login_ref.email.clone(), + login_ref.password.clone(), + ); } - }); + }) }; let login_ref = login.read(); diff --git a/src/components/main_window.rs b/src/components/main_window.rs index 55f7bfd..0514503 100644 --- a/src/components/main_window.rs +++ b/src/components/main_window.rs @@ -2,15 +2,15 @@ use dioxus::prelude::*; use fermi::*; use tracing::debug; -use crate::base::APP_SETTINGS; +use crate::base::SESSION; use crate::components::contacts_window::contacts_window::ContactsWindow; use crate::components::login::Login; pub fn MainWindow(cx: Scope) -> Element { debug!("MainWindow rendering"); - let app_settings = use_atom_ref(cx, &APP_SETTINGS); - let is_logged = app_settings.read().store.is_logged; + let session_ref = use_atom_ref(cx, &SESSION); + let is_logged = session_ref.read().is_logged; cx.render(rsx! { if is_logged { diff --git a/src/main.rs b/src/main.rs index 13ef0b7..5b547ba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,19 +8,36 @@ use tracing::{debug, Level}; pub mod components; pub mod matrix_interface; -use crate::base::APP_SETTINGS; +use crate::base::{login, sync_rooms, APP_SETTINGS, ROOMS, SESSION}; use crate::components::chats_window::chats_window::ChatsWindow; use crate::components::main_window::MainWindow; mod base; fn App(cx: Scope) -> Element { - debug!("App rendering"); + debug!("*** App rendering ***"); use_init_atom_root(cx); - let app_settings = use_atom_ref(cx, &APP_SETTINGS); - let is_logged = app_settings.read().store.is_logged; + let app_settings_ref = use_atom_ref(cx, &APP_SETTINGS); + let session_ref = use_atom_ref(cx, &SESSION); + let rooms_ref = use_atom_ref(cx, &ROOMS); + + let login_coro = use_coroutine(cx, |rx| { + login(rx, app_settings_ref.clone(), session_ref.clone()) + }); + + let sync_rooms_coro = use_coroutine(cx, |rx| { + sync_rooms(rx, app_settings_ref.clone(), rooms_ref.clone()) + }); + + let is_logged = session_ref.read().is_logged; + + login_coro.send(is_logged); + + if is_logged { + sync_rooms_coro.send(is_logged); + } let chats_win_state = use_state(cx, || None); diff --git a/src/matrix_interface/client.rs b/src/matrix_interface/client.rs index e53b8b5..b64779f 100644 --- a/src/matrix_interface/client.rs +++ b/src/matrix_interface/client.rs @@ -5,12 +5,13 @@ use std::time::Duration; use dioxus::prelude::to_owned; use flume::{bounded, unbounded}; use flume::{Receiver as FlumeReceiver, Sender}; -use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; +use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver}; use tokio::task::JoinHandle; use tracing::{debug, error, warn}; use matrix_sdk::{ config::SyncSettings, + event_handler::Ctx, room::Room as MatrixRoom, ruma::events::{ key::verification::{ @@ -44,12 +45,23 @@ pub enum ClientError { Matrix(#[from] matrix_sdk::Error), } +#[derive(Clone)] +struct Senders { + rooms_sender: flume::Sender, +} + +impl Senders { + fn new(rooms_sender: flume::Sender) -> Self { + Self { rooms_sender } + } +} + pub struct Client { initialized: bool, client: Option>, load_handle: Option>, sync_handle: Option>, - rooms_sender: Option>, + senders: Senders, } impl Client { @@ -59,7 +71,7 @@ impl Client { client: Some(client), load_handle: None, sync_handle: None, - rooms_sender: Some(rooms_sender), + senders: Senders::new(rooms_sender), } } @@ -237,9 +249,7 @@ impl Client { fn init(&mut self) { let client = self.client.clone().unwrap(); - // let store = self.store.clone(); - // client.add_event_handler_context(store); - // client.add_event_handler_context(self); + client.add_event_handler_context(self.senders.clone()); let _ = client.add_event_handler(Client::on_sync_typing_event); let _ = client.add_event_handler(Client::on_presence_event); @@ -333,7 +343,7 @@ impl Client { fn start_background_tasks(&mut self, synchronized_rx: FlumeReceiver) { let client = self.client.clone().unwrap(); - let rooms_sender_ref = &self.rooms_sender; + let rooms_sender_ref = &self.senders.rooms_sender; self.load_handle = tokio::spawn({ to_owned![rooms_sender_ref]; @@ -345,7 +355,7 @@ impl Client { let rooms_refresh = Self::refresh_rooms_forever( client.as_ref(), - rooms_sender_ref.as_ref().unwrap(), + &rooms_sender_ref ); let ((),) = tokio::join!(rooms_refresh); }