🏗️ Rearchitecting the interface with the MatrixClient
- Replace RwStore with channels. - Use of fermi to handle application data. - Use of tracing.
This commit is contained in:
27
Cargo.toml
27
Cargo.toml
@@ -6,20 +6,27 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
dioxus = "0.4.0"
|
||||
dioxus-desktop = "0.4.0"
|
||||
dioxus = "0.4.3"
|
||||
dioxus-desktop = "0.4.3"
|
||||
dioxus-free-icons = { version = "0.7.0", features = ["material-design-icons-navigation", "ionicons"] }
|
||||
dioxus-std = { version = "0.4.1", features = ["utils"] }
|
||||
fermi = { version = "0.4.3" }
|
||||
|
||||
# matrix-sdk = { version = "0.6.2", features = ["js"] }
|
||||
matrix-sdk = { git = "https://github.com/matrix-org/matrix-rust-sdk.git", branch = "main" , features = ["js"]}
|
||||
anyhow = "1.0.72"
|
||||
url = "2.4.0"
|
||||
tokio = "1.29.1"
|
||||
|
||||
anyhow = "1.0.75"
|
||||
url = "2.5.0"
|
||||
dirs = "5.0.1"
|
||||
ctrlc-async = "3.2.2"
|
||||
tracing-subscriber = "0.3.17"
|
||||
dioxus-free-icons = { version = "0.7.0", features = ["material-design-icons-navigation", "ionicons"] }
|
||||
thiserror = "1.0.44"
|
||||
turf = "0.5.0"
|
||||
dioxus-std = { version = "0.4.0", features = ["utils"] }
|
||||
tracing-subscriber = "0.3.18"
|
||||
thiserror = "1.0.50"
|
||||
turf = "0.7.0"
|
||||
tokio = "1.34.0"
|
||||
flume = "0.11.0"
|
||||
log = "0.4.20"
|
||||
tracing = "0.1.40"
|
||||
|
||||
[build]
|
||||
target = "x86_64-unknown-linux-gnu"
|
||||
|
||||
|
37
src/base.rs
37
src/base.rs
@@ -1,9 +1,6 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
use std::{cell::RefCell, collections::HashMap, sync::Arc};
|
||||
|
||||
use dioxus_std::utils::rw::UseRw;
|
||||
use fermi::*;
|
||||
use matrix_sdk::room::Room as MatrixRoom;
|
||||
use matrix_sdk::{
|
||||
room::RoomMember,
|
||||
@@ -36,7 +33,7 @@ impl UserInfo {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Room {
|
||||
pub matrix_room: Arc<MatrixRoom>,
|
||||
pub topic: Option<String>,
|
||||
pub topic: Option<RefCell<String>>,
|
||||
pub members: HashMap<OwnedUserId, RoomMember>,
|
||||
pub is_direct: Option<bool>,
|
||||
}
|
||||
@@ -44,7 +41,7 @@ pub struct Room {
|
||||
impl Room {
|
||||
pub fn new(
|
||||
matrix_room: Arc<MatrixRoom>,
|
||||
topic: Option<String>,
|
||||
topic: Option<RefCell<String>>,
|
||||
is_direct: Option<bool>,
|
||||
) -> Self {
|
||||
Self {
|
||||
@@ -58,21 +55,23 @@ impl Room {
|
||||
pub fn name(&self) -> Option<String> {
|
||||
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()
|
||||
&& self.topic == other.topic
|
||||
&& self.is_direct == other.is_direct
|
||||
}
|
||||
}
|
||||
|
||||
pub type ByIdRooms = HashMap<OwnedRoomId, Arc<RwLock<Room>>>;
|
||||
pub type ByIdRooms = HashMap<OwnedRoomId, RefCell<Room>>;
|
||||
pub type ByIdUserInfos = HashMap<OwnedUserId, UserInfo>;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct Store {
|
||||
pub is_logged: bool,
|
||||
pub rooms: ByIdRooms,
|
||||
@@ -80,7 +79,7 @@ pub struct Store {
|
||||
pub user_id: Option<OwnedUserId>,
|
||||
}
|
||||
|
||||
impl<'a> Store {
|
||||
impl Store {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
is_logged: false,
|
||||
@@ -107,15 +106,19 @@ impl PartialEq for Store {
|
||||
|
||||
impl Eq for Store {}
|
||||
|
||||
pub type ReactiveStore = Arc<UseRw<Store>>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppSettings {
|
||||
pub requester: Option<Arc<Requester>>,
|
||||
pub requester: Option<Requester>,
|
||||
pub store: Store,
|
||||
}
|
||||
|
||||
impl AppSettings {
|
||||
pub fn new() -> Self {
|
||||
Self { requester: None }
|
||||
Self {
|
||||
requester: None,
|
||||
store: Store::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub static APP_SETTINGS: AtomRef<AppSettings> = AtomRef(|_| AppSettings::new());
|
||||
pub static ROOMS: AtomRef<ByIdRooms> = AtomRef(|_| ByIdRooms::new());
|
||||
|
@@ -1,4 +1,5 @@
|
||||
use dioxus::prelude::*;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::components::avatar_selector::AvatarSelector;
|
||||
use crate::components::chats_window::edit_section::EditSection;
|
||||
@@ -7,6 +8,8 @@ use crate::components::icons::DownArrowIcon;
|
||||
turf::style_sheet!("src/components/chats_window/chats_window.scss");
|
||||
|
||||
pub fn ChatsWindow(cx: Scope) -> Element {
|
||||
debug!("ChatsWindow rendering");
|
||||
|
||||
let room_names = vec![
|
||||
"MON POTE",
|
||||
"Second room",
|
||||
|
@@ -1,36 +1,46 @@
|
||||
use std::cell::RefCell;
|
||||
use std::time::Duration;
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_std::utils::rw::UseRw;
|
||||
use fermi::*;
|
||||
use tokio::time::sleep;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::base::Room;
|
||||
use crate::base::Store;
|
||||
use crate::components::contacts_window::contacts_section::ContactsSection;
|
||||
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,
|
||||
};
|
||||
|
||||
turf::style_sheet!("src/components/contacts_window/contacts.scss");
|
||||
|
||||
#[inline_props]
|
||||
pub fn Contacts<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
||||
println!("Contacts rendering");
|
||||
pub fn Contacts(cx: Scope) -> Element {
|
||||
debug!("Contacts rendering");
|
||||
|
||||
let store = rw_store.read().unwrap();
|
||||
let app_settings_atom = use_atom_ref(cx, &APP_SETTINGS);
|
||||
let rooms_atom = use_atom_ref(cx, &ROOMS);
|
||||
|
||||
let rooms = &store.rooms;
|
||||
async fn sync_rooms(app_settings: UseAtomRef<AppSettings>, rooms_atom: UseAtomRef<ByIdRooms>) {
|
||||
loop {
|
||||
let requester = &app_settings.read().requester;
|
||||
|
||||
let rooms_len = rooms.len();
|
||||
let mut groups = Vec::<Room>::with_capacity(rooms_len);
|
||||
let mut directs = Vec::<Room>::with_capacity(rooms_len);
|
||||
|
||||
for arc_room in rooms.values() {
|
||||
let room = arc_room.read().unwrap().to_owned();
|
||||
|
||||
let is_direct = room.is_direct.unwrap();
|
||||
if is_direct {
|
||||
directs.push(room);
|
||||
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::<Room>::new(room));
|
||||
} else {
|
||||
groups.push(room);
|
||||
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 ?
|
||||
@@ -40,8 +50,8 @@ pub fn Contacts<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
||||
div {
|
||||
class: ClassName::CONTACTS,
|
||||
|
||||
ContactsSection {name: "Groups", contacts: RefCell::new(groups)},
|
||||
ContactsSection {name: "Available", contacts: RefCell::new(directs)},
|
||||
ContactsSection {name: "Groups", filter: &filter_room_conversations},
|
||||
ContactsSection {name: "Available", filter: &filter_people_conversations},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@@ -3,9 +3,11 @@ use std::cell::RefCell;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_free_icons::icons::io_icons::IoChevronDown;
|
||||
use dioxus_free_icons::Icon;
|
||||
use fermi::prelude::*;
|
||||
use matrix_sdk::RoomState;
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use crate::base::Room;
|
||||
use crate::base::{ByIdRooms, Room, ROOMS};
|
||||
|
||||
turf::style_sheet!("src/components/contacts_window/contacts_section.scss");
|
||||
|
||||
@@ -19,11 +21,46 @@ fn ContactsArrow(cx: Scope) -> Element {
|
||||
})
|
||||
}
|
||||
|
||||
static NO_NAME_REPR: &str = "No name";
|
||||
static NO_SUBJECT_REPR: &str = "No subject";
|
||||
|
||||
#[inline_props]
|
||||
pub fn ContactsSection<'a>(cx: Scope, name: &'a str, contacts: RefCell<Vec<Room>>) -> Element {
|
||||
println!("ContactsSection rendering");
|
||||
pub fn filter_people_conversations(rooms_atom: UseAtomRef<ByIdRooms>) -> Vec<RefCell<Room>> {
|
||||
let rooms = rooms_atom.read();
|
||||
let mut filtered_rooms = Vec::<RefCell<Room>>::with_capacity(rooms.len());
|
||||
|
||||
for room in rooms.values() {
|
||||
let is_direct = room.borrow().is_direct.unwrap();
|
||||
if !is_direct {
|
||||
filtered_rooms.push(room.to_owned());
|
||||
}
|
||||
}
|
||||
filtered_rooms
|
||||
}
|
||||
|
||||
pub fn filter_room_conversations(rooms_atom: UseAtomRef<ByIdRooms>) -> Vec<RefCell<Room>> {
|
||||
let rooms = rooms_atom.read();
|
||||
let mut filtered_rooms = Vec::<RefCell<Room>>::with_capacity(rooms.len());
|
||||
|
||||
for room in rooms.values() {
|
||||
let is_direct = room.borrow().is_direct.unwrap();
|
||||
if is_direct {
|
||||
filtered_rooms.push(room.to_owned());
|
||||
}
|
||||
}
|
||||
filtered_rooms
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn ContactsSection<'a>(
|
||||
cx: Scope,
|
||||
name: &'a str,
|
||||
filter: &'a dyn Fn(UseAtomRef<ByIdRooms>) -> Vec<RefCell<Room>>,
|
||||
) -> Element {
|
||||
debug!("ContactsSection rendering");
|
||||
|
||||
let rooms_atom = use_atom_ref(cx, &ROOMS);
|
||||
let contacts = filter(rooms_atom.clone());
|
||||
let contacts_len = contacts.len();
|
||||
|
||||
let show = use_state(cx, || false);
|
||||
|
||||
@@ -33,11 +70,19 @@ pub fn ContactsSection<'a>(cx: Scope, name: &'a str, contacts: RefCell<Vec<Room>
|
||||
]
|
||||
.join(" ");
|
||||
|
||||
let contacts_len = contacts.borrow().len();
|
||||
let rendered_contacts = contacts.into_iter().map(|room_ref| {
|
||||
let room = room_ref.borrow();
|
||||
|
||||
let room_topic = room
|
||||
.topic
|
||||
.as_ref()
|
||||
.unwrap_or(&RefCell::new(NO_SUBJECT_REPR.to_string()))
|
||||
.borrow()
|
||||
.to_owned();
|
||||
let room_name = room.name().unwrap_or(NO_NAME_REPR.to_string());
|
||||
|
||||
let rendered_contacts = contacts.borrow_mut().clone().into_iter().map(|room| {
|
||||
let room_name = room.name().unwrap();
|
||||
let is_invited = room.matrix_room.state() == RoomState::Invited;
|
||||
|
||||
let formatted = format!(
|
||||
"{room_name} - {}",
|
||||
if is_invited {
|
||||
@@ -47,8 +92,6 @@ pub fn ContactsSection<'a>(cx: Scope, name: &'a str, contacts: RefCell<Vec<Room>
|
||||
}
|
||||
);
|
||||
|
||||
let room_topic = room.topic.unwrap_or(NO_SUBJECT_REPR.to_string()).to_owned();
|
||||
|
||||
rsx!(li {
|
||||
img {
|
||||
src: "./images/status_online.png",
|
||||
@@ -60,8 +103,7 @@ pub fn ContactsSection<'a>(cx: Scope, name: &'a str, contacts: RefCell<Vec<Room>
|
||||
style: "color: darkgrey;",
|
||||
room_topic,
|
||||
},
|
||||
},
|
||||
)
|
||||
})
|
||||
});
|
||||
|
||||
cx.render(rsx! {
|
||||
|
@@ -1,14 +1,14 @@
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_std::utils::rw::UseRw;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::base::Store;
|
||||
use crate::components::contacts_window::contacts::Contacts;
|
||||
use crate::components::contacts_window::user_infos::UserInfos;
|
||||
|
||||
turf::style_sheet!("src/components/contacts_window/contacts_window.scss");
|
||||
|
||||
#[inline_props]
|
||||
pub fn ContactsWindow<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
||||
pub fn ContactsWindow(cx: Scope) -> Element {
|
||||
debug!("ContactsWindow rendering");
|
||||
|
||||
cx.render(rsx! {
|
||||
style { STYLE_SHEET },
|
||||
|
||||
@@ -26,7 +26,7 @@ pub fn ContactsWindow<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
||||
class: ClassName::USER_INFO,
|
||||
},
|
||||
|
||||
UserInfos {rw_store: rw_store},
|
||||
UserInfos {},
|
||||
},
|
||||
|
||||
div {
|
||||
@@ -84,7 +84,7 @@ pub fn ContactsWindow<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
||||
},
|
||||
},
|
||||
|
||||
Contacts {rw_store: rw_store},
|
||||
Contacts {},
|
||||
|
||||
div {
|
||||
class: ClassName::FOOTER,
|
||||
|
@@ -1,7 +1,8 @@
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_std::utils::rw::UseRw;
|
||||
use fermi::*;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::base::Store;
|
||||
use crate::base::APP_SETTINGS;
|
||||
use crate::components::avatar_selector::AvatarSelector;
|
||||
use crate::components::icons::DownArrowIcon;
|
||||
|
||||
@@ -9,15 +10,31 @@ turf::style_sheet!("src/components/contacts_window/user_infos.scss");
|
||||
|
||||
static MESSAGE_PLACEHOLDER: &str = "<Enter a personal message>";
|
||||
|
||||
#[inline_props]
|
||||
pub fn UserInfos<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
||||
pub fn UserInfos(cx: Scope) -> Element {
|
||||
debug!("UserInfos rendering");
|
||||
|
||||
let app_settings = use_atom_ref(cx, &APP_SETTINGS);
|
||||
let store = &app_settings.read().store;
|
||||
|
||||
println!("----------------------------------");
|
||||
println!("UserInfos rendering");
|
||||
// println!("store={:?}", &store);
|
||||
dbg!(&store.user_id);
|
||||
println!("----------------------------------");
|
||||
|
||||
let store = rw_store.read().unwrap().clone();
|
||||
// let user_id = store.user_id..as_ref().unwrap();
|
||||
|
||||
let user_id = store.user_id.unwrap();
|
||||
let user_info = store.user_infos.get(&user_id).unwrap();
|
||||
let user_display_name = user_info.display_name.as_ref().unwrap();
|
||||
// let mut user_info_option = None;
|
||||
let mut user_display_name_option = None;
|
||||
|
||||
let user_id_option = &store.user_id;
|
||||
if user_id_option.is_some() {
|
||||
let user_id = user_id_option.as_ref().unwrap();
|
||||
let user_info_option = store.user_infos.get(user_id);
|
||||
if user_info_option.is_some() {
|
||||
user_display_name_option = user_info_option.unwrap().display_name.as_ref();
|
||||
}
|
||||
}
|
||||
|
||||
cx.render(rsx! {
|
||||
style { STYLE_SHEET },
|
||||
@@ -37,7 +54,7 @@ pub fn UserInfos<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
||||
class: ClassName::USER_ID,
|
||||
p {
|
||||
class: ClassName::USER_NAME,
|
||||
"{user_display_name}",
|
||||
if user_display_name_option.is_some() { "{user_display_name}" } else { "AIE" },
|
||||
},
|
||||
p {
|
||||
class: ClassName::USER_STATUS,
|
||||
|
@@ -1,10 +1,10 @@
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_std::utils::rw::UseRw;
|
||||
use fermi::*;
|
||||
use tracing::{debug, error};
|
||||
|
||||
use crate::base::{AppSettings, Store};
|
||||
use crate::base::APP_SETTINGS;
|
||||
use crate::components::avatar_selector::AvatarSelector;
|
||||
use crate::components::header::Header;
|
||||
use crate::matrix_client::{LoginStyle, MatrixClient};
|
||||
@@ -13,14 +13,14 @@ turf::style_sheet!("src/components/login.scss");
|
||||
|
||||
static EMPTY_PLACEHOLDER: &str = "Tmp placeholder";
|
||||
|
||||
#[inline_props]
|
||||
pub fn Login<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
||||
let app_context = use_shared_state::<AppSettings>(cx).unwrap();
|
||||
pub fn Login(cx: Scope) -> Element {
|
||||
debug!("Login rendering");
|
||||
|
||||
let app_settings = use_atom_ref(cx, &APP_SETTINGS);
|
||||
|
||||
let invalid_login = use_state(cx, || false);
|
||||
let login = use_ref(cx, || Login::new());
|
||||
|
||||
let arc_store = Arc::new(rw_store.to_owned().clone());
|
||||
|
||||
let password_class = if **invalid_login {
|
||||
ClassName::INVALID_INPUT
|
||||
} else {
|
||||
@@ -29,7 +29,7 @@ pub fn Login<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
||||
|
||||
let run_matrix_client = move |_| {
|
||||
cx.spawn({
|
||||
to_owned![app_context, invalid_login, login, arc_store];
|
||||
to_owned![invalid_login, login, app_settings];
|
||||
|
||||
let login_ref = login.read();
|
||||
let homeserver_url = login_ref.homeserver_url.clone().unwrap();
|
||||
@@ -37,20 +37,22 @@ pub fn Login<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
||||
let password = login_ref.password.clone().unwrap();
|
||||
|
||||
async move {
|
||||
let requester = MatrixClient::spawn(homeserver_url, arc_store.clone()).await;
|
||||
requester.init();
|
||||
let new_matrix_client = MatrixClient::spawn(homeserver_url).await;
|
||||
|
||||
match requester.login(LoginStyle::Password(username, password)) {
|
||||
new_matrix_client.init();
|
||||
|
||||
match new_matrix_client.login(LoginStyle::Password(username, password)) {
|
||||
Ok(_) => {
|
||||
println!("successfully logged");
|
||||
debug!("successfully logged");
|
||||
app_settings.write().store.is_logged = true;
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error during login: {err}");
|
||||
error!("Error during login: {err}");
|
||||
invalid_login.modify(|_| true);
|
||||
}
|
||||
}
|
||||
|
||||
app_context.write().requester = Some(Arc::new(requester));
|
||||
app_settings.write().requester = Some(new_matrix_client);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@@ -1,20 +1,23 @@
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_std::utils::rw::UseRw;
|
||||
use fermi::*;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::base::Store;
|
||||
use crate::base::APP_SETTINGS;
|
||||
use crate::components::contacts_window::contacts_window::ContactsWindow;
|
||||
use crate::components::login::Login;
|
||||
|
||||
#[inline_props]
|
||||
pub fn MainWindow<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
||||
let is_logged = rw_store.read().unwrap().is_logged;
|
||||
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;
|
||||
|
||||
cx.render(rsx! {
|
||||
if is_logged {
|
||||
rsx!(ContactsWindow {rw_store: rw_store})
|
||||
rsx!(ContactsWindow {})
|
||||
}
|
||||
else {
|
||||
rsx!(Login {rw_store: rw_store})
|
||||
rsx!(Login {})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
28
src/main.rs
28
src/main.rs
@@ -2,29 +2,31 @@
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_desktop::Config;
|
||||
use dioxus_std::utils::rw::use_rw;
|
||||
use fermi::*;
|
||||
use tracing::{debug, Level};
|
||||
|
||||
pub mod components;
|
||||
pub mod matrix_client;
|
||||
|
||||
use crate::base::AppSettings;
|
||||
use crate::base::Store;
|
||||
use crate::base::APP_SETTINGS;
|
||||
use crate::components::chats_window::chats_window::ChatsWindow;
|
||||
use crate::components::main_window::MainWindow;
|
||||
|
||||
mod base;
|
||||
|
||||
fn App(cx: Scope<AppSettings>) -> Element {
|
||||
use_shared_state_provider(cx, || cx.props.clone());
|
||||
fn App(cx: Scope) -> Element {
|
||||
debug!("App rendering");
|
||||
|
||||
let rw_store = use_rw(cx, || Store::new());
|
||||
use_init_atom_root(cx);
|
||||
|
||||
let is_logged = rw_store.read().unwrap().is_logged;
|
||||
let app_settings = use_atom_ref(cx, &APP_SETTINGS);
|
||||
let is_logged = app_settings.read().store.is_logged;
|
||||
|
||||
let chats_win_state = use_state(cx, || None);
|
||||
|
||||
if is_logged && chats_win_state.is_none() {
|
||||
let chats_window = dioxus_desktop::use_window(cx);
|
||||
|
||||
let chats_dom = VirtualDom::new(ChatsWindow);
|
||||
let window_cfg = Config::default().with_custom_head(
|
||||
r#"
|
||||
@@ -48,17 +50,19 @@ fn App(cx: Scope<AppSettings>) -> Element {
|
||||
}
|
||||
|
||||
cx.render(rsx! {
|
||||
MainWindow {rw_store: rw_store}
|
||||
MainWindow {}
|
||||
})
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
tracing_subscriber::fmt::init();
|
||||
tracing_subscriber::fmt()
|
||||
// .pretty()
|
||||
.with_max_level(Level::DEBUG)
|
||||
.init();
|
||||
|
||||
let app_settings = AppSettings::new();
|
||||
|
||||
dioxus_desktop::launch_with_props(App, app_settings, Config::default());
|
||||
dioxus_desktop::launch(App);
|
||||
// dioxus_web::launch(App);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@@ -1,18 +1,21 @@
|
||||
// TODO: make a choice: mpsc vs flume.
|
||||
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use dioxus_std::utils::rw::UseRw;
|
||||
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::task::JoinHandle;
|
||||
use tracing::{debug, error, warn};
|
||||
|
||||
use matrix_sdk::{
|
||||
config::SyncSettings,
|
||||
event_handler::Ctx,
|
||||
room::Room as MatrixRoom,
|
||||
ruma::{
|
||||
events::{
|
||||
ruma::events::{
|
||||
key::verification::{
|
||||
done::{OriginalSyncKeyVerificationDoneEvent, ToDeviceKeyVerificationDoneEvent},
|
||||
key::{OriginalSyncKeyVerificationKeyEvent, ToDeviceKeyVerificationKeyEvent},
|
||||
@@ -31,12 +34,10 @@ use matrix_sdk::{
|
||||
typing::SyncTypingEvent,
|
||||
SyncMessageLikeEvent, SyncStateEvent,
|
||||
},
|
||||
OwnedRoomId, OwnedUserId,
|
||||
},
|
||||
Client, DisplayName, RoomMemberships,
|
||||
Client,
|
||||
};
|
||||
|
||||
use crate::base::{ByIdRooms, ReactiveStore, Room, Store, UserInfo};
|
||||
use crate::base::Room;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LoginStyle {
|
||||
@@ -104,53 +105,183 @@ fn oneshot<T>() -> (ClientReply<T>, ClientResponse<T>) {
|
||||
pub struct Requester {
|
||||
pub client: Arc<Client>,
|
||||
pub tx: UnboundedSender<WorkerTask>,
|
||||
pub rooms_receiver: flume::Receiver<Room>,
|
||||
}
|
||||
|
||||
impl Requester {
|
||||
pub fn init(&self) {
|
||||
println!("Requester.init BEG");
|
||||
let (reply, response) = oneshot();
|
||||
|
||||
self.tx.send(WorkerTask::Init(reply)).unwrap();
|
||||
|
||||
println!("Requester.init END");
|
||||
return response.recv();
|
||||
}
|
||||
|
||||
pub fn login(&self, style: LoginStyle) -> anyhow::Result<()> {
|
||||
println!("Requester.login BEG");
|
||||
let (reply, response) = oneshot();
|
||||
|
||||
self.tx.send(WorkerTask::Login(style, reply)).unwrap();
|
||||
|
||||
println!("Requester.login END");
|
||||
return response.recv();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MatrixClient {
|
||||
initialized: bool,
|
||||
client: Arc<Client>,
|
||||
// sync_token: Option<String>,
|
||||
client: Option<Arc<Client>>,
|
||||
load_handle: Option<JoinHandle<()>>,
|
||||
sync_handle: Option<JoinHandle<()>>,
|
||||
store: ReactiveStore,
|
||||
rooms_sender: Option<flume::Sender<Room>>,
|
||||
}
|
||||
|
||||
impl MatrixClient {
|
||||
fn new(store: ReactiveStore, client: Arc<Client>) -> Self {
|
||||
pub fn new(client: Arc<Client>, rooms_sender: flume::Sender<Room>) -> Self {
|
||||
Self {
|
||||
client: client,
|
||||
initialized: false,
|
||||
// sync_token: None,
|
||||
client: Some(client),
|
||||
load_handle: None,
|
||||
sync_handle: None,
|
||||
store: store,
|
||||
rooms_sender: Some(rooms_sender),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn spawn(homeserver_url: String, store: ReactiveStore) -> Requester {
|
||||
async fn on_sync_typing_event(_ev: SyncTypingEvent, room: MatrixRoom) {
|
||||
debug!("== on_sync_typing_event ==");
|
||||
let room_id = room.room_id().to_owned();
|
||||
dbg!(room_id);
|
||||
}
|
||||
|
||||
async fn on_presence_event(_ev: PresenceEvent) {
|
||||
debug!("== on_presence_event ==");
|
||||
dbg!(_ev);
|
||||
}
|
||||
|
||||
async fn on_sync_state_event(_ev: SyncStateEvent<RoomNameEventContent>, _room: MatrixRoom) {
|
||||
debug!("== on_sync_state_event ==");
|
||||
dbg!(_ev);
|
||||
}
|
||||
|
||||
async fn on_room_topic_event(ev: SyncStateEvent<RoomTopicEventContent>, _room: MatrixRoom) {
|
||||
debug!("== on_room_topic_event ==");
|
||||
dbg!(&ev);
|
||||
// if let SyncStateEvent::Original(ev) = ev {
|
||||
// let room_id = room.room_id().to_owned();
|
||||
// let store = reactive_store.read().unwrap().to_owned();
|
||||
|
||||
// if let Some(store_room) = store.rooms.get(&room_id) {
|
||||
// // store_room.write().unwrap().topic = Some(ev.content.topic);
|
||||
// // let _ = reactive_store.write(store);
|
||||
// println!("HOP");
|
||||
// } else {
|
||||
// println!("No room with \"{room_id}\" id known");
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
async fn on_room_member_event(ev: SyncStateEvent<RoomMemberEventContent>, _room: MatrixRoom) {
|
||||
debug!("== on_room_member_event ==");
|
||||
dbg!(ev);
|
||||
// // dbg!(room);
|
||||
// if room.invited_members_count() > 0 {
|
||||
// dbg!(room);
|
||||
// }
|
||||
// if let SyncStateEvent::Original(ev) = ev {}
|
||||
}
|
||||
|
||||
async fn on_sync_message_like_room_message_event(
|
||||
ev: SyncMessageLikeEvent<RoomMessageEventContent>,
|
||||
_room: MatrixRoom,
|
||||
_client: Client,
|
||||
) {
|
||||
debug!("== on_sync_message_like_room_message_event ==");
|
||||
dbg!(ev);
|
||||
}
|
||||
|
||||
async fn on_sync_message_like_reaction_event(
|
||||
ev: SyncMessageLikeEvent<ReactionEventContent>,
|
||||
_room: MatrixRoom,
|
||||
) {
|
||||
debug!("== on_sync_message_like_reaction_event ==");
|
||||
dbg!(ev);
|
||||
}
|
||||
|
||||
async fn on_original_sync_room_redaction_event(
|
||||
ev: OriginalSyncRoomRedactionEvent,
|
||||
_room: MatrixRoom,
|
||||
) {
|
||||
debug!("== on_original_sync_room_redaction_event ==");
|
||||
dbg!(ev);
|
||||
}
|
||||
|
||||
async fn on_original_sync_room_member_event(
|
||||
ev: OriginalSyncRoomMemberEvent,
|
||||
room: MatrixRoom,
|
||||
_client: Client,
|
||||
) {
|
||||
debug!("== on_original_sync_room_member_event ==");
|
||||
dbg!(ev);
|
||||
let room_id = room.room_id();
|
||||
dbg!(room_id);
|
||||
|
||||
// let mut store = store_ctx.read().unwrap().to_owned();
|
||||
// dbg!(store.rooms.keys());
|
||||
// let is_direct = room.is_direct().await.ok();
|
||||
// store.rooms.insert(
|
||||
// OwnedRoomId::from(room_id),
|
||||
// Arc::new(RwLock::new(Room::new(Arc::new(room), None, is_direct))),
|
||||
// );
|
||||
// let _ = store_ctx.write(store);
|
||||
}
|
||||
|
||||
async fn on_original_sync_key_verif_start_event(
|
||||
ev: OriginalSyncKeyVerificationStartEvent,
|
||||
_client: Client,
|
||||
) {
|
||||
debug!("== on_original_sync_key_verif_start_event ==");
|
||||
dbg!(ev);
|
||||
}
|
||||
|
||||
async fn on_original_sync_key_verif_key_event(
|
||||
ev: OriginalSyncKeyVerificationKeyEvent,
|
||||
_client: Client,
|
||||
) {
|
||||
debug!("== on_original_sync_key_verif_key_event ==");
|
||||
dbg!(ev);
|
||||
}
|
||||
|
||||
async fn on_original_sync_key_verif_done_event(
|
||||
ev: OriginalSyncKeyVerificationDoneEvent,
|
||||
_client: Client,
|
||||
) {
|
||||
debug!("== on_original_sync_key_verif_done_event ==");
|
||||
dbg!(ev);
|
||||
}
|
||||
|
||||
async fn on_device_key_verif_req_event(
|
||||
ev: ToDeviceKeyVerificationRequestEvent,
|
||||
_client: Client,
|
||||
) {
|
||||
debug!("== on_device_key_verif_req_event ==");
|
||||
dbg!(ev);
|
||||
}
|
||||
|
||||
async fn on_device_key_verif_start_event(
|
||||
ev: ToDeviceKeyVerificationStartEvent,
|
||||
_client: Client,
|
||||
) {
|
||||
debug!("== on_device_key_verif_start_event ==");
|
||||
dbg!(ev);
|
||||
}
|
||||
|
||||
async fn on_device_key_verif_key_event(ev: ToDeviceKeyVerificationKeyEvent, _client: Client) {
|
||||
debug!("== on_device_key_verif_key_event ==");
|
||||
dbg!(ev);
|
||||
}
|
||||
|
||||
async fn on_device_key_verif_done_event(ev: ToDeviceKeyVerificationDoneEvent, _client: Client) {
|
||||
debug!("== on_device_key_verif_done_event ==");
|
||||
dbg!(ev);
|
||||
}
|
||||
|
||||
pub async fn spawn(homeserver_url: String) -> Requester {
|
||||
let (tx, rx) = unbounded_channel::<WorkerTask>();
|
||||
let (rooms_sender, rooms_receiver) = unbounded::<Room>();
|
||||
|
||||
let client = Arc::new(
|
||||
Client::builder()
|
||||
@@ -160,7 +291,7 @@ impl MatrixClient {
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let mut matrix_client = MatrixClient::new(store, client.clone());
|
||||
let mut matrix_client = MatrixClient::new(client.clone(), rooms_sender);
|
||||
|
||||
tokio::spawn({
|
||||
async move {
|
||||
@@ -168,209 +299,18 @@ impl MatrixClient {
|
||||
}
|
||||
});
|
||||
|
||||
Requester { client, tx }
|
||||
}
|
||||
|
||||
async fn work(&mut self, mut rx: UnboundedReceiver<WorkerTask>) {
|
||||
println!("MatrixClient.work BEG");
|
||||
loop {
|
||||
let task = rx.recv().await;
|
||||
println!("task={:?}", task);
|
||||
|
||||
match task {
|
||||
Some(task) => self.run(task).await,
|
||||
None => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("MatrixClient.work END");
|
||||
|
||||
if let Some(handle) = self.sync_handle.take() {
|
||||
handle.abort();
|
||||
Requester {
|
||||
client,
|
||||
tx,
|
||||
rooms_receiver,
|
||||
}
|
||||
}
|
||||
|
||||
async fn run(&mut self, task: WorkerTask) {
|
||||
println!("Run({:?}", task);
|
||||
match task {
|
||||
WorkerTask::Init(reply) => {
|
||||
assert_eq!(self.initialized, false);
|
||||
self.init().await;
|
||||
reply.send(());
|
||||
}
|
||||
WorkerTask::Login(style, reply) => {
|
||||
assert!(self.initialized);
|
||||
reply.send(self.login_and_sync(style).await);
|
||||
}
|
||||
}
|
||||
}
|
||||
fn init(&mut self) {
|
||||
let client = self.client.clone().unwrap();
|
||||
|
||||
async fn on_sync_typing_event(
|
||||
_ev: SyncTypingEvent,
|
||||
room: MatrixRoom,
|
||||
_store: Ctx<ReactiveStore>,
|
||||
) {
|
||||
println!("== on_sync_typing_event ==");
|
||||
let room_id = room.room_id().to_owned();
|
||||
// dbg!(room_id);
|
||||
}
|
||||
|
||||
async fn on_presence_event(_ev: PresenceEvent, _store: Ctx<ReactiveStore>) {
|
||||
println!("== on_presence_event ==");
|
||||
dbg!(_ev);
|
||||
}
|
||||
|
||||
async fn on_sync_state_event(
|
||||
_ev: SyncStateEvent<RoomNameEventContent>,
|
||||
_room: MatrixRoom,
|
||||
_store: Ctx<ReactiveStore>,
|
||||
) {
|
||||
println!("== on_sync_state_event ==");
|
||||
dbg!(_ev);
|
||||
}
|
||||
|
||||
async fn on_room_topic_event(
|
||||
ev: SyncStateEvent<RoomTopicEventContent>,
|
||||
room: MatrixRoom,
|
||||
reactive_store: Ctx<ReactiveStore>,
|
||||
) {
|
||||
dbg!(&ev);
|
||||
if let SyncStateEvent::Original(ev) = ev {
|
||||
let room_id = room.room_id().to_owned();
|
||||
let store = reactive_store.read().unwrap().to_owned();
|
||||
|
||||
if let Some(store_room) = store.rooms.get(&room_id) {
|
||||
store_room.write().unwrap().topic = Some(ev.content.topic);
|
||||
let _ = reactive_store.write(store);
|
||||
println!("HOP");
|
||||
} else {
|
||||
println!("No room with \"{room_id}\" id known");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn on_room_member_event(
|
||||
ev: SyncStateEvent<RoomMemberEventContent>,
|
||||
room: MatrixRoom,
|
||||
store_ctx: Ctx<ReactiveStore>,
|
||||
) {
|
||||
println!("== on_room_member_event ==");
|
||||
// // dbg!(ev);
|
||||
// // dbg!(room);
|
||||
// if room.invited_members_count() > 0 {
|
||||
// dbg!(room);
|
||||
// }
|
||||
// if let SyncStateEvent::Original(ev) = ev {}
|
||||
}
|
||||
|
||||
async fn on_sync_message_like_room_message_event(
|
||||
_ev: SyncMessageLikeEvent<RoomMessageEventContent>,
|
||||
_room: MatrixRoom,
|
||||
_client: Client,
|
||||
_store: Ctx<ReactiveStore>,
|
||||
) {
|
||||
println!("== on_sync_message_like_room_message_event ==");
|
||||
// dbg!(_ev);
|
||||
}
|
||||
|
||||
async fn on_sync_message_like_reaction_event(
|
||||
_ev: SyncMessageLikeEvent<ReactionEventContent>,
|
||||
_room: MatrixRoom,
|
||||
_store: Ctx<ReactiveStore>,
|
||||
) {
|
||||
println!("== on_sync_message_like_reaction_event ==");
|
||||
}
|
||||
|
||||
async fn on_original_sync_room_redaction_event(
|
||||
_ev: OriginalSyncRoomRedactionEvent,
|
||||
_room: MatrixRoom,
|
||||
_store: Ctx<ReactiveStore>,
|
||||
) {
|
||||
println!("== on_original_sync_room_redaction_event ==");
|
||||
}
|
||||
|
||||
async fn on_original_sync_room_member_event(
|
||||
_ev: OriginalSyncRoomMemberEvent,
|
||||
room: MatrixRoom,
|
||||
_client: Client,
|
||||
store_ctx: Ctx<ReactiveStore>,
|
||||
) {
|
||||
println!("== on_original_sync_room_member_event ==");
|
||||
let room_id = room.room_id();
|
||||
dbg!(room_id);
|
||||
|
||||
let mut store = store_ctx.read().unwrap().to_owned();
|
||||
dbg!(store.rooms.keys());
|
||||
let is_direct = room.is_direct().await.ok();
|
||||
store.rooms.insert(
|
||||
OwnedRoomId::from(room_id),
|
||||
Arc::new(RwLock::new(Room::new(Arc::new(room), None, is_direct))),
|
||||
);
|
||||
let _ = store_ctx.write(store);
|
||||
}
|
||||
|
||||
async fn on_original_sync_key_verif_start_event(
|
||||
_ev: OriginalSyncKeyVerificationStartEvent,
|
||||
_client: Client,
|
||||
_store: Ctx<ReactiveStore>,
|
||||
) {
|
||||
println!("== on_original_sync_key_verif_start_event ==");
|
||||
}
|
||||
|
||||
async fn on_original_sync_key_verif_key_event(
|
||||
_ev: OriginalSyncKeyVerificationKeyEvent,
|
||||
_client: Client,
|
||||
_store: Ctx<ReactiveStore>,
|
||||
) {
|
||||
println!("== on_original_sync_key_verif_key_event ==");
|
||||
}
|
||||
|
||||
async fn on_original_sync_key_verif_done_event(
|
||||
_ev: OriginalSyncKeyVerificationDoneEvent,
|
||||
_client: Client,
|
||||
_store: Ctx<ReactiveStore>,
|
||||
) {
|
||||
println!("== on_original_sync_key_verif_done_event ==");
|
||||
}
|
||||
|
||||
async fn on_device_key_verif_req_event(
|
||||
_ev: ToDeviceKeyVerificationRequestEvent,
|
||||
_client: Client,
|
||||
_store: Ctx<ReactiveStore>,
|
||||
) {
|
||||
println!("== on_device_key_verif_req_event ==");
|
||||
}
|
||||
|
||||
async fn on_device_key_verif_start_event(
|
||||
_ev: ToDeviceKeyVerificationStartEvent,
|
||||
_client: Client,
|
||||
_store: Ctx<ReactiveStore>,
|
||||
) {
|
||||
println!("== on_device_key_verif_start_event ==");
|
||||
}
|
||||
|
||||
async fn on_device_key_verif_key_event(
|
||||
_ev: ToDeviceKeyVerificationKeyEvent,
|
||||
_client: Client,
|
||||
_store: Ctx<ReactiveStore>,
|
||||
) {
|
||||
println!("== on_device_key_verif_key_event ==");
|
||||
}
|
||||
|
||||
async fn on_device_key_verif_done_event(
|
||||
_ev: ToDeviceKeyVerificationDoneEvent,
|
||||
_client: Client,
|
||||
_store: Ctx<ReactiveStore>,
|
||||
) {
|
||||
println!("== on_device_key_verif_done_event ==");
|
||||
}
|
||||
|
||||
async fn init(&mut self) {
|
||||
let client = self.client.clone();
|
||||
let store = self.store.clone();
|
||||
client.add_event_handler_context(store);
|
||||
// let store = self.store.clone();
|
||||
// client.add_event_handler_context(store);
|
||||
|
||||
let _ = client.add_event_handler(MatrixClient::on_sync_typing_event);
|
||||
let _ = client.add_event_handler(MatrixClient::on_presence_event);
|
||||
@@ -389,107 +329,42 @@ impl MatrixClient {
|
||||
let _ = client.add_event_handler(MatrixClient::on_room_topic_event);
|
||||
let _ = client.add_event_handler(MatrixClient::on_room_member_event);
|
||||
|
||||
self.load_handle = tokio::spawn({
|
||||
let client = self.client.clone();
|
||||
let store = self.store.clone();
|
||||
|
||||
async move {
|
||||
let rooms_refresh = Self::refresh_rooms_forever(client.as_ref(), store.as_ref());
|
||||
let ((),) = tokio::join!(rooms_refresh);
|
||||
}
|
||||
})
|
||||
.into();
|
||||
|
||||
self.initialized = true;
|
||||
}
|
||||
|
||||
async fn load_user_infos(&self) {
|
||||
let mut store = self.store.read().unwrap().to_owned();
|
||||
async fn refresh_rooms(client: &Client, rooms_sender: &Sender<Room>) {
|
||||
let joined_matrix_rooms_ref = &client.joined_rooms();
|
||||
let invited_matrix_rooms_ref = &client.invited_rooms();
|
||||
|
||||
let user_id = self.client.user_id().unwrap();
|
||||
store.user_id = Some(OwnedUserId::from(user_id));
|
||||
|
||||
let res = self.client.account().get_profile().await.unwrap();
|
||||
let user_info = UserInfo::new(res.avatar_url, res.displayname, res.blurhash);
|
||||
|
||||
store
|
||||
.user_infos
|
||||
.insert(OwnedUserId::from(user_id), user_info);
|
||||
|
||||
let _ = self.store.write(store);
|
||||
}
|
||||
|
||||
async fn get_formatted_room_name(room: &MatrixRoom) -> String {
|
||||
room.display_name()
|
||||
.await
|
||||
.unwrap_or(DisplayName::Empty)
|
||||
.to_string()
|
||||
}
|
||||
|
||||
async fn refresh_rooms(client: &Client, store: &UseRw<Store>) {
|
||||
// println!("== refresh_rooms ==");
|
||||
|
||||
let mut _store = store.read().unwrap().to_owned();
|
||||
|
||||
let mut new_rooms = ByIdRooms::new();
|
||||
|
||||
for room in &client.joined_rooms() {
|
||||
let room_id = room.room_id();
|
||||
|
||||
let members = room.members(RoomMemberships::empty()).await.unwrap();
|
||||
if !_store.rooms.contains_key(room_id) {
|
||||
let is_direct = room.is_direct().await.ok();
|
||||
new_rooms.insert(
|
||||
OwnedRoomId::from(room_id),
|
||||
Arc::new(RwLock::new(Room::new(
|
||||
Arc::new(room.to_owned()),
|
||||
for matrix_rooms in vec![joined_matrix_rooms_ref, invited_matrix_rooms_ref] {
|
||||
for matrix_room in matrix_rooms.iter() {
|
||||
let room = Room::new(
|
||||
Arc::new(matrix_room.to_owned()),
|
||||
None,
|
||||
is_direct,
|
||||
))),
|
||||
matrix_room.is_direct().await.ok(),
|
||||
);
|
||||
if let Err(err) = rooms_sender.send_async(room).await {
|
||||
warn!("Error: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for room in client.invited_rooms().into_iter() {
|
||||
let room_id = room.room_id();
|
||||
|
||||
if !_store.rooms.contains_key(room_id) {
|
||||
let is_direct = room.is_direct().await.ok();
|
||||
new_rooms.insert(
|
||||
OwnedRoomId::from(room_id),
|
||||
Arc::new(RwLock::new(Room::new(
|
||||
Arc::new(room.to_owned()),
|
||||
None,
|
||||
is_direct,
|
||||
))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let mut updated = false;
|
||||
for (room_id, room) in new_rooms.into_iter() {
|
||||
updated = true;
|
||||
_store.rooms.insert(room_id, room);
|
||||
}
|
||||
|
||||
if updated {
|
||||
let _ = store.write(_store);
|
||||
}
|
||||
}
|
||||
|
||||
async fn refresh_rooms_forever(client: &Client, store: &UseRw<Store>) {
|
||||
async fn refresh_rooms_forever(client: &Client, rooms_channel: &Sender<Room>) {
|
||||
// TODO: Add interval to config
|
||||
let mut interval = tokio::time::interval(Duration::from_secs(5));
|
||||
|
||||
loop {
|
||||
Self::refresh_rooms(client, store).await;
|
||||
Self::refresh_rooms(client, rooms_channel).await;
|
||||
|
||||
error!("== Interval tick BEG ==");
|
||||
interval.tick().await;
|
||||
error!("== Interval tick END ==");
|
||||
}
|
||||
}
|
||||
|
||||
async fn login_and_sync(&mut self, style: LoginStyle) -> anyhow::Result<()> {
|
||||
let client = self.client.clone();
|
||||
let client = self.client.clone().unwrap();
|
||||
|
||||
match style {
|
||||
LoginStyle::Password(username, password) => {
|
||||
@@ -503,13 +378,19 @@ impl MatrixClient {
|
||||
}
|
||||
}
|
||||
|
||||
self.load_user_infos().await;
|
||||
let (synchronized_tx, synchronized_rx) = bounded(1);
|
||||
|
||||
self.sync_handle = tokio::spawn({
|
||||
async move {
|
||||
// Sync once so we receive the client state and old messages
|
||||
let _ = client.sync_once(SyncSettings::default()).await;
|
||||
|
||||
debug!("User connected to the homeserver");
|
||||
|
||||
if let Err(err) = synchronized_tx.send(true) {
|
||||
warn!("Unable to notify that the Matrix client is now synchronized ({err})");
|
||||
}
|
||||
|
||||
loop {
|
||||
let settings = SyncSettings::default();
|
||||
let _ = client.sync(settings).await;
|
||||
@@ -518,11 +399,61 @@ impl MatrixClient {
|
||||
})
|
||||
.into();
|
||||
|
||||
let mut store = self.store.read().unwrap().to_owned();
|
||||
store.is_logged = true;
|
||||
let _ = self.store.write(store);
|
||||
self.start_background_tasks(synchronized_rx);
|
||||
|
||||
println!("User connected to the homeserver");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn start_background_tasks(&mut self, synchronized_rx: FlumeReceiver<bool>) {
|
||||
let client = self.client.clone().unwrap();
|
||||
let rooms_sender_ref = &self.rooms_sender;
|
||||
|
||||
self.load_handle = tokio::spawn({
|
||||
to_owned![rooms_sender_ref];
|
||||
|
||||
async move {
|
||||
if let Err(err) = synchronized_rx.recv() {
|
||||
error!("Unable to setup the rx channel notifying that the Matrix client is now synchronized ({err})");
|
||||
}
|
||||
|
||||
let rooms_refresh = Self::refresh_rooms_forever(
|
||||
client.as_ref(),
|
||||
rooms_sender_ref.as_ref().unwrap(),
|
||||
);
|
||||
let ((),) = tokio::join!(rooms_refresh);
|
||||
}
|
||||
})
|
||||
.into();
|
||||
}
|
||||
|
||||
async fn work(&mut self, mut rx: UnboundedReceiver<WorkerTask>) {
|
||||
loop {
|
||||
let task = rx.recv().await;
|
||||
|
||||
match task {
|
||||
Some(task) => self.run(task).await,
|
||||
None => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(handle) = self.sync_handle.take() {
|
||||
handle.abort();
|
||||
}
|
||||
}
|
||||
|
||||
async fn run(&mut self, task: WorkerTask) {
|
||||
match task {
|
||||
WorkerTask::Init(reply) => {
|
||||
assert_eq!(self.initialized, false);
|
||||
self.init();
|
||||
reply.send(());
|
||||
}
|
||||
WorkerTask::Login(style, reply) => {
|
||||
assert!(self.initialized);
|
||||
reply.send(self.login_and_sync(style).await);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user