🏗️ 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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dioxus = "0.4.0"
|
dioxus = "0.4.3"
|
||||||
dioxus-desktop = "0.4.0"
|
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 = { version = "0.6.2", features = ["js"] }
|
||||||
matrix-sdk = { git = "https://github.com/matrix-org/matrix-rust-sdk.git", branch = "main" , 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"
|
anyhow = "1.0.75"
|
||||||
tokio = "1.29.1"
|
url = "2.5.0"
|
||||||
dirs = "5.0.1"
|
dirs = "5.0.1"
|
||||||
ctrlc-async = "3.2.2"
|
ctrlc-async = "3.2.2"
|
||||||
tracing-subscriber = "0.3.17"
|
tracing-subscriber = "0.3.18"
|
||||||
dioxus-free-icons = { version = "0.7.0", features = ["material-design-icons-navigation", "ionicons"] }
|
thiserror = "1.0.50"
|
||||||
thiserror = "1.0.44"
|
turf = "0.7.0"
|
||||||
turf = "0.5.0"
|
tokio = "1.34.0"
|
||||||
dioxus-std = { version = "0.4.0", features = ["utils"] }
|
flume = "0.11.0"
|
||||||
|
log = "0.4.20"
|
||||||
|
tracing = "0.1.40"
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
target = "x86_64-unknown-linux-gnu"
|
target = "x86_64-unknown-linux-gnu"
|
||||||
|
|
||||||
|
37
src/base.rs
37
src/base.rs
@@ -1,9 +1,6 @@
|
|||||||
use std::{
|
use std::{cell::RefCell, collections::HashMap, sync::Arc};
|
||||||
collections::HashMap,
|
|
||||||
sync::{Arc, RwLock},
|
|
||||||
};
|
|
||||||
|
|
||||||
use dioxus_std::utils::rw::UseRw;
|
use fermi::*;
|
||||||
use matrix_sdk::room::Room as MatrixRoom;
|
use matrix_sdk::room::Room as MatrixRoom;
|
||||||
use matrix_sdk::{
|
use matrix_sdk::{
|
||||||
room::RoomMember,
|
room::RoomMember,
|
||||||
@@ -36,7 +33,7 @@ impl UserInfo {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Room {
|
pub struct Room {
|
||||||
pub matrix_room: Arc<MatrixRoom>,
|
pub matrix_room: Arc<MatrixRoom>,
|
||||||
pub topic: Option<String>,
|
pub topic: Option<RefCell<String>>,
|
||||||
pub members: HashMap<OwnedUserId, RoomMember>,
|
pub members: HashMap<OwnedUserId, RoomMember>,
|
||||||
pub is_direct: Option<bool>,
|
pub is_direct: Option<bool>,
|
||||||
}
|
}
|
||||||
@@ -44,7 +41,7 @@ pub struct Room {
|
|||||||
impl Room {
|
impl Room {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
matrix_room: Arc<MatrixRoom>,
|
matrix_room: Arc<MatrixRoom>,
|
||||||
topic: Option<String>,
|
topic: Option<RefCell<String>>,
|
||||||
is_direct: Option<bool>,
|
is_direct: Option<bool>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -58,21 +55,23 @@ impl Room {
|
|||||||
pub fn name(&self) -> Option<String> {
|
pub fn name(&self) -> Option<String> {
|
||||||
self.matrix_room.name()
|
self.matrix_room.name()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> OwnedRoomId {
|
||||||
|
OwnedRoomId::from(self.matrix_room.room_id())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Room {
|
impl PartialEq for Room {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
// TODO: Look for a better way to compare Matrix rooms
|
// TODO: Look for a better way to compare Matrix rooms
|
||||||
self.matrix_room.room_id() == other.matrix_room.room_id()
|
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>;
|
pub type ByIdUserInfos = HashMap<OwnedUserId, UserInfo>;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone)]
|
||||||
pub struct Store {
|
pub struct Store {
|
||||||
pub is_logged: bool,
|
pub is_logged: bool,
|
||||||
pub rooms: ByIdRooms,
|
pub rooms: ByIdRooms,
|
||||||
@@ -80,7 +79,7 @@ pub struct Store {
|
|||||||
pub user_id: Option<OwnedUserId>,
|
pub user_id: Option<OwnedUserId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Store {
|
impl Store {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
is_logged: false,
|
is_logged: false,
|
||||||
@@ -107,15 +106,19 @@ impl PartialEq for Store {
|
|||||||
|
|
||||||
impl Eq for Store {}
|
impl Eq for Store {}
|
||||||
|
|
||||||
pub type ReactiveStore = Arc<UseRw<Store>>;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct AppSettings {
|
pub struct AppSettings {
|
||||||
pub requester: Option<Arc<Requester>>,
|
pub requester: Option<Requester>,
|
||||||
|
pub store: Store,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppSettings {
|
impl AppSettings {
|
||||||
pub fn new() -> Self {
|
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 dioxus::prelude::*;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::components::avatar_selector::AvatarSelector;
|
use crate::components::avatar_selector::AvatarSelector;
|
||||||
use crate::components::chats_window::edit_section::EditSection;
|
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");
|
turf::style_sheet!("src/components/chats_window/chats_window.scss");
|
||||||
|
|
||||||
pub fn ChatsWindow(cx: Scope) -> Element {
|
pub fn ChatsWindow(cx: Scope) -> Element {
|
||||||
|
debug!("ChatsWindow rendering");
|
||||||
|
|
||||||
let room_names = vec![
|
let room_names = vec![
|
||||||
"MON POTE",
|
"MON POTE",
|
||||||
"Second room",
|
"Second room",
|
||||||
|
@@ -1,36 +1,46 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use dioxus::prelude::*;
|
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::AppSettings;
|
||||||
use crate::base::Store;
|
use crate::base::{ByIdRooms, Room, APP_SETTINGS, ROOMS};
|
||||||
use crate::components::contacts_window::contacts_section::ContactsSection;
|
use crate::components::contacts_window::contacts_section::{
|
||||||
|
filter_people_conversations, filter_room_conversations, ContactsSection,
|
||||||
|
};
|
||||||
|
|
||||||
turf::style_sheet!("src/components/contacts_window/contacts.scss");
|
turf::style_sheet!("src/components/contacts_window/contacts.scss");
|
||||||
|
|
||||||
#[inline_props]
|
pub fn Contacts(cx: Scope) -> Element {
|
||||||
pub fn Contacts<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
debug!("Contacts rendering");
|
||||||
println!("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();
|
if requester.is_some() {
|
||||||
let mut groups = Vec::<Room>::with_capacity(rooms_len);
|
let rooms_receiver = &requester.as_ref().unwrap().rooms_receiver;
|
||||||
let mut directs = Vec::<Room>::with_capacity(rooms_len);
|
let room = rooms_receiver.recv_async().await.unwrap();
|
||||||
|
let room_id = room.id();
|
||||||
for arc_room in rooms.values() {
|
dbg!(&room_id);
|
||||||
let room = arc_room.read().unwrap().to_owned();
|
rooms_atom
|
||||||
|
.write()
|
||||||
let is_direct = room.is_direct.unwrap();
|
.insert(room_id, RefCell::<Room>::new(room));
|
||||||
if is_direct {
|
|
||||||
directs.push(room);
|
|
||||||
} else {
|
} 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: Test overflow
|
||||||
// TODO: Add offline users ?
|
// TODO: Add offline users ?
|
||||||
@@ -40,8 +50,8 @@ pub fn Contacts<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
|||||||
div {
|
div {
|
||||||
class: ClassName::CONTACTS,
|
class: ClassName::CONTACTS,
|
||||||
|
|
||||||
ContactsSection {name: "Groups", contacts: RefCell::new(groups)},
|
ContactsSection {name: "Groups", filter: &filter_room_conversations},
|
||||||
ContactsSection {name: "Available", contacts: RefCell::new(directs)},
|
ContactsSection {name: "Available", filter: &filter_people_conversations},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@@ -3,9 +3,11 @@ use std::cell::RefCell;
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_free_icons::icons::io_icons::IoChevronDown;
|
use dioxus_free_icons::icons::io_icons::IoChevronDown;
|
||||||
use dioxus_free_icons::Icon;
|
use dioxus_free_icons::Icon;
|
||||||
|
use fermi::prelude::*;
|
||||||
use matrix_sdk::RoomState;
|
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");
|
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";
|
static NO_SUBJECT_REPR: &str = "No subject";
|
||||||
|
|
||||||
#[inline_props]
|
pub fn filter_people_conversations(rooms_atom: UseAtomRef<ByIdRooms>) -> Vec<RefCell<Room>> {
|
||||||
pub fn ContactsSection<'a>(cx: Scope, name: &'a str, contacts: RefCell<Vec<Room>>) -> Element {
|
let rooms = rooms_atom.read();
|
||||||
println!("ContactsSection rendering");
|
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);
|
let show = use_state(cx, || false);
|
||||||
|
|
||||||
@@ -33,11 +70,19 @@ pub fn ContactsSection<'a>(cx: Scope, name: &'a str, contacts: RefCell<Vec<Room>
|
|||||||
]
|
]
|
||||||
.join(" ");
|
.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 is_invited = room.matrix_room.state() == RoomState::Invited;
|
||||||
|
|
||||||
let formatted = format!(
|
let formatted = format!(
|
||||||
"{room_name} - {}",
|
"{room_name} - {}",
|
||||||
if is_invited {
|
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 {
|
rsx!(li {
|
||||||
img {
|
img {
|
||||||
src: "./images/status_online.png",
|
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;",
|
style: "color: darkgrey;",
|
||||||
room_topic,
|
room_topic,
|
||||||
},
|
},
|
||||||
},
|
})
|
||||||
)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
|
@@ -1,14 +1,14 @@
|
|||||||
use dioxus::prelude::*;
|
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::contacts::Contacts;
|
||||||
use crate::components::contacts_window::user_infos::UserInfos;
|
use crate::components::contacts_window::user_infos::UserInfos;
|
||||||
|
|
||||||
turf::style_sheet!("src/components/contacts_window/contacts_window.scss");
|
turf::style_sheet!("src/components/contacts_window/contacts_window.scss");
|
||||||
|
|
||||||
#[inline_props]
|
pub fn ContactsWindow(cx: Scope) -> Element {
|
||||||
pub fn ContactsWindow<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
debug!("ContactsWindow rendering");
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
style { STYLE_SHEET },
|
style { STYLE_SHEET },
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ pub fn ContactsWindow<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
|||||||
class: ClassName::USER_INFO,
|
class: ClassName::USER_INFO,
|
||||||
},
|
},
|
||||||
|
|
||||||
UserInfos {rw_store: rw_store},
|
UserInfos {},
|
||||||
},
|
},
|
||||||
|
|
||||||
div {
|
div {
|
||||||
@@ -84,7 +84,7 @@ pub fn ContactsWindow<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
Contacts {rw_store: rw_store},
|
Contacts {},
|
||||||
|
|
||||||
div {
|
div {
|
||||||
class: ClassName::FOOTER,
|
class: ClassName::FOOTER,
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
use dioxus::prelude::*;
|
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::avatar_selector::AvatarSelector;
|
||||||
use crate::components::icons::DownArrowIcon;
|
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>";
|
static MESSAGE_PLACEHOLDER: &str = "<Enter a personal message>";
|
||||||
|
|
||||||
#[inline_props]
|
pub fn UserInfos(cx: Scope) -> Element {
|
||||||
pub fn UserInfos<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
debug!("UserInfos rendering");
|
||||||
|
|
||||||
|
let app_settings = use_atom_ref(cx, &APP_SETTINGS);
|
||||||
|
let store = &app_settings.read().store;
|
||||||
|
|
||||||
|
println!("----------------------------------");
|
||||||
println!("UserInfos rendering");
|
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 mut user_info_option = None;
|
||||||
let user_info = store.user_infos.get(&user_id).unwrap();
|
let mut user_display_name_option = None;
|
||||||
let user_display_name = user_info.display_name.as_ref().unwrap();
|
|
||||||
|
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! {
|
cx.render(rsx! {
|
||||||
style { STYLE_SHEET },
|
style { STYLE_SHEET },
|
||||||
@@ -37,7 +54,7 @@ pub fn UserInfos<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
|||||||
class: ClassName::USER_ID,
|
class: ClassName::USER_ID,
|
||||||
p {
|
p {
|
||||||
class: ClassName::USER_NAME,
|
class: ClassName::USER_NAME,
|
||||||
"{user_display_name}",
|
if user_display_name_option.is_some() { "{user_display_name}" } else { "AIE" },
|
||||||
},
|
},
|
||||||
p {
|
p {
|
||||||
class: ClassName::USER_STATUS,
|
class: ClassName::USER_STATUS,
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use dioxus::prelude::*;
|
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::avatar_selector::AvatarSelector;
|
||||||
use crate::components::header::Header;
|
use crate::components::header::Header;
|
||||||
use crate::matrix_client::{LoginStyle, MatrixClient};
|
use crate::matrix_client::{LoginStyle, MatrixClient};
|
||||||
@@ -13,14 +13,14 @@ turf::style_sheet!("src/components/login.scss");
|
|||||||
|
|
||||||
static EMPTY_PLACEHOLDER: &str = "Tmp placeholder";
|
static EMPTY_PLACEHOLDER: &str = "Tmp placeholder";
|
||||||
|
|
||||||
#[inline_props]
|
pub fn Login(cx: Scope) -> Element {
|
||||||
pub fn Login<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
debug!("Login rendering");
|
||||||
let app_context = use_shared_state::<AppSettings>(cx).unwrap();
|
|
||||||
|
let app_settings = use_atom_ref(cx, &APP_SETTINGS);
|
||||||
|
|
||||||
let invalid_login = use_state(cx, || false);
|
let invalid_login = use_state(cx, || false);
|
||||||
let login = use_ref(cx, || Login::new());
|
let login = use_ref(cx, || Login::new());
|
||||||
|
|
||||||
let arc_store = Arc::new(rw_store.to_owned().clone());
|
|
||||||
|
|
||||||
let password_class = if **invalid_login {
|
let password_class = if **invalid_login {
|
||||||
ClassName::INVALID_INPUT
|
ClassName::INVALID_INPUT
|
||||||
} else {
|
} else {
|
||||||
@@ -29,7 +29,7 @@ pub fn Login<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
|||||||
|
|
||||||
let run_matrix_client = move |_| {
|
let run_matrix_client = move |_| {
|
||||||
cx.spawn({
|
cx.spawn({
|
||||||
to_owned![app_context, invalid_login, login, arc_store];
|
to_owned![invalid_login, login, app_settings];
|
||||||
|
|
||||||
let login_ref = login.read();
|
let login_ref = login.read();
|
||||||
let homeserver_url = login_ref.homeserver_url.clone().unwrap();
|
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();
|
let password = login_ref.password.clone().unwrap();
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
let requester = MatrixClient::spawn(homeserver_url, arc_store.clone()).await;
|
let new_matrix_client = MatrixClient::spawn(homeserver_url).await;
|
||||||
requester.init();
|
|
||||||
|
|
||||||
match requester.login(LoginStyle::Password(username, password)) {
|
new_matrix_client.init();
|
||||||
|
|
||||||
|
match new_matrix_client.login(LoginStyle::Password(username, password)) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
println!("successfully logged");
|
debug!("successfully logged");
|
||||||
|
app_settings.write().store.is_logged = true;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("Error during login: {err}");
|
error!("Error during login: {err}");
|
||||||
invalid_login.modify(|_| true);
|
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::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::contacts_window::contacts_window::ContactsWindow;
|
||||||
use crate::components::login::Login;
|
use crate::components::login::Login;
|
||||||
|
|
||||||
#[inline_props]
|
pub fn MainWindow(cx: Scope) -> Element {
|
||||||
pub fn MainWindow<'a>(cx: Scope, rw_store: &'a UseRw<Store>) -> Element {
|
debug!("MainWindow rendering");
|
||||||
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;
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
if is_logged {
|
if is_logged {
|
||||||
rsx!(ContactsWindow {rw_store: rw_store})
|
rsx!(ContactsWindow {})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rsx!(Login {rw_store: rw_store})
|
rsx!(Login {})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
34
src/main.rs
34
src/main.rs
@@ -2,33 +2,35 @@
|
|||||||
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_desktop::Config;
|
use dioxus_desktop::Config;
|
||||||
use dioxus_std::utils::rw::use_rw;
|
use fermi::*;
|
||||||
|
use tracing::{debug, Level};
|
||||||
|
|
||||||
pub mod components;
|
pub mod components;
|
||||||
pub mod matrix_client;
|
pub mod matrix_client;
|
||||||
|
|
||||||
use crate::base::AppSettings;
|
use crate::base::APP_SETTINGS;
|
||||||
use crate::base::Store;
|
|
||||||
use crate::components::chats_window::chats_window::ChatsWindow;
|
use crate::components::chats_window::chats_window::ChatsWindow;
|
||||||
use crate::components::main_window::MainWindow;
|
use crate::components::main_window::MainWindow;
|
||||||
|
|
||||||
mod base;
|
mod base;
|
||||||
|
|
||||||
fn App(cx: Scope<AppSettings>) -> Element {
|
fn App(cx: Scope) -> Element {
|
||||||
use_shared_state_provider(cx, || cx.props.clone());
|
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);
|
let chats_win_state = use_state(cx, || None);
|
||||||
|
|
||||||
if is_logged && chats_win_state.is_none() {
|
if is_logged && chats_win_state.is_none() {
|
||||||
let chats_window = dioxus_desktop::use_window(cx);
|
let chats_window = dioxus_desktop::use_window(cx);
|
||||||
|
|
||||||
let chats_dom = VirtualDom::new(ChatsWindow);
|
let chats_dom = VirtualDom::new(ChatsWindow);
|
||||||
let window_cfg = Config::default().with_custom_head(
|
let window_cfg = Config::default().with_custom_head(
|
||||||
r#"
|
r#"
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
html, body {
|
html, body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -39,8 +41,8 @@ fn App(cx: Scope<AppSettings>) -> Element {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
"#
|
"#
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
);
|
);
|
||||||
let chats_window_desktop_service = chats_window.new_window(chats_dom, window_cfg);
|
let chats_window_desktop_service = chats_window.new_window(chats_dom, window_cfg);
|
||||||
@@ -48,17 +50,19 @@ fn App(cx: Scope<AppSettings>) -> Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
MainWindow {rw_store: rw_store}
|
MainWindow {}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
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(App);
|
||||||
|
// dioxus_web::launch(App);
|
||||||
dioxus_desktop::launch_with_props(App, app_settings, Config::default());
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@@ -1,18 +1,21 @@
|
|||||||
|
// TODO: make a choice: mpsc vs flume.
|
||||||
|
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
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::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
|
use tracing::{debug, error, warn};
|
||||||
|
|
||||||
use matrix_sdk::{
|
use matrix_sdk::{
|
||||||
config::SyncSettings,
|
config::SyncSettings,
|
||||||
event_handler::Ctx,
|
|
||||||
room::Room as MatrixRoom,
|
room::Room as MatrixRoom,
|
||||||
ruma::{
|
ruma::events::{
|
||||||
events::{
|
|
||||||
key::verification::{
|
key::verification::{
|
||||||
done::{OriginalSyncKeyVerificationDoneEvent, ToDeviceKeyVerificationDoneEvent},
|
done::{OriginalSyncKeyVerificationDoneEvent, ToDeviceKeyVerificationDoneEvent},
|
||||||
key::{OriginalSyncKeyVerificationKeyEvent, ToDeviceKeyVerificationKeyEvent},
|
key::{OriginalSyncKeyVerificationKeyEvent, ToDeviceKeyVerificationKeyEvent},
|
||||||
@@ -31,12 +34,10 @@ use matrix_sdk::{
|
|||||||
typing::SyncTypingEvent,
|
typing::SyncTypingEvent,
|
||||||
SyncMessageLikeEvent, SyncStateEvent,
|
SyncMessageLikeEvent, SyncStateEvent,
|
||||||
},
|
},
|
||||||
OwnedRoomId, OwnedUserId,
|
Client,
|
||||||
},
|
|
||||||
Client, DisplayName, RoomMemberships,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::base::{ByIdRooms, ReactiveStore, Room, Store, UserInfo};
|
use crate::base::Room;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum LoginStyle {
|
pub enum LoginStyle {
|
||||||
@@ -104,53 +105,183 @@ fn oneshot<T>() -> (ClientReply<T>, ClientResponse<T>) {
|
|||||||
pub struct Requester {
|
pub struct Requester {
|
||||||
pub client: Arc<Client>,
|
pub client: Arc<Client>,
|
||||||
pub tx: UnboundedSender<WorkerTask>,
|
pub tx: UnboundedSender<WorkerTask>,
|
||||||
|
pub rooms_receiver: flume::Receiver<Room>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Requester {
|
impl Requester {
|
||||||
pub fn init(&self) {
|
pub fn init(&self) {
|
||||||
println!("Requester.init BEG");
|
|
||||||
let (reply, response) = oneshot();
|
let (reply, response) = oneshot();
|
||||||
|
|
||||||
self.tx.send(WorkerTask::Init(reply)).unwrap();
|
self.tx.send(WorkerTask::Init(reply)).unwrap();
|
||||||
|
|
||||||
println!("Requester.init END");
|
|
||||||
return response.recv();
|
return response.recv();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn login(&self, style: LoginStyle) -> anyhow::Result<()> {
|
pub fn login(&self, style: LoginStyle) -> anyhow::Result<()> {
|
||||||
println!("Requester.login BEG");
|
|
||||||
let (reply, response) = oneshot();
|
let (reply, response) = oneshot();
|
||||||
|
|
||||||
self.tx.send(WorkerTask::Login(style, reply)).unwrap();
|
self.tx.send(WorkerTask::Login(style, reply)).unwrap();
|
||||||
|
|
||||||
println!("Requester.login END");
|
|
||||||
return response.recv();
|
return response.recv();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MatrixClient {
|
pub struct MatrixClient {
|
||||||
initialized: bool,
|
initialized: bool,
|
||||||
client: Arc<Client>,
|
client: Option<Arc<Client>>,
|
||||||
// sync_token: Option<String>,
|
|
||||||
load_handle: Option<JoinHandle<()>>,
|
load_handle: Option<JoinHandle<()>>,
|
||||||
sync_handle: Option<JoinHandle<()>>,
|
sync_handle: Option<JoinHandle<()>>,
|
||||||
store: ReactiveStore,
|
rooms_sender: Option<flume::Sender<Room>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MatrixClient {
|
impl MatrixClient {
|
||||||
fn new(store: ReactiveStore, client: Arc<Client>) -> Self {
|
pub fn new(client: Arc<Client>, rooms_sender: flume::Sender<Room>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
client: client,
|
|
||||||
initialized: false,
|
initialized: false,
|
||||||
// sync_token: None,
|
client: Some(client),
|
||||||
load_handle: None,
|
load_handle: None,
|
||||||
sync_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 (tx, rx) = unbounded_channel::<WorkerTask>();
|
||||||
|
let (rooms_sender, rooms_receiver) = unbounded::<Room>();
|
||||||
|
|
||||||
let client = Arc::new(
|
let client = Arc::new(
|
||||||
Client::builder()
|
Client::builder()
|
||||||
@@ -160,7 +291,7 @@ impl MatrixClient {
|
|||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut matrix_client = MatrixClient::new(store, client.clone());
|
let mut matrix_client = MatrixClient::new(client.clone(), rooms_sender);
|
||||||
|
|
||||||
tokio::spawn({
|
tokio::spawn({
|
||||||
async move {
|
async move {
|
||||||
@@ -168,209 +299,18 @@ impl MatrixClient {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Requester { client, tx }
|
Requester {
|
||||||
}
|
client,
|
||||||
|
tx,
|
||||||
async fn work(&mut self, mut rx: UnboundedReceiver<WorkerTask>) {
|
rooms_receiver,
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(&mut self, task: WorkerTask) {
|
fn init(&mut self) {
|
||||||
println!("Run({:?}", task);
|
let client = self.client.clone().unwrap();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn on_sync_typing_event(
|
// let store = self.store.clone();
|
||||||
_ev: SyncTypingEvent,
|
// client.add_event_handler_context(store);
|
||||||
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 _ = client.add_event_handler(MatrixClient::on_sync_typing_event);
|
let _ = client.add_event_handler(MatrixClient::on_sync_typing_event);
|
||||||
let _ = client.add_event_handler(MatrixClient::on_presence_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_topic_event);
|
||||||
let _ = client.add_event_handler(MatrixClient::on_room_member_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;
|
self.initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_user_infos(&self) {
|
async fn refresh_rooms(client: &Client, rooms_sender: &Sender<Room>) {
|
||||||
let mut store = self.store.read().unwrap().to_owned();
|
let joined_matrix_rooms_ref = &client.joined_rooms();
|
||||||
|
let invited_matrix_rooms_ref = &client.invited_rooms();
|
||||||
|
|
||||||
let user_id = self.client.user_id().unwrap();
|
for matrix_rooms in vec![joined_matrix_rooms_ref, invited_matrix_rooms_ref] {
|
||||||
store.user_id = Some(OwnedUserId::from(user_id));
|
for matrix_room in matrix_rooms.iter() {
|
||||||
|
let room = Room::new(
|
||||||
let res = self.client.account().get_profile().await.unwrap();
|
Arc::new(matrix_room.to_owned()),
|
||||||
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()),
|
|
||||||
None,
|
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() {
|
async fn refresh_rooms_forever(client: &Client, rooms_channel: &Sender<Room>) {
|
||||||
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>) {
|
|
||||||
// TODO: Add interval to config
|
// TODO: Add interval to config
|
||||||
let mut interval = tokio::time::interval(Duration::from_secs(5));
|
let mut interval = tokio::time::interval(Duration::from_secs(5));
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
Self::refresh_rooms(client, store).await;
|
Self::refresh_rooms(client, rooms_channel).await;
|
||||||
|
|
||||||
|
error!("== Interval tick BEG ==");
|
||||||
interval.tick().await;
|
interval.tick().await;
|
||||||
|
error!("== Interval tick END ==");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn login_and_sync(&mut self, style: LoginStyle) -> anyhow::Result<()> {
|
async fn login_and_sync(&mut self, style: LoginStyle) -> anyhow::Result<()> {
|
||||||
let client = self.client.clone();
|
let client = self.client.clone().unwrap();
|
||||||
|
|
||||||
match style {
|
match style {
|
||||||
LoginStyle::Password(username, password) => {
|
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({
|
self.sync_handle = tokio::spawn({
|
||||||
async move {
|
async move {
|
||||||
// Sync once so we receive the client state and old messages
|
// Sync once so we receive the client state and old messages
|
||||||
let _ = client.sync_once(SyncSettings::default()).await;
|
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 {
|
loop {
|
||||||
let settings = SyncSettings::default();
|
let settings = SyncSettings::default();
|
||||||
let _ = client.sync(settings).await;
|
let _ = client.sync(settings).await;
|
||||||
@@ -518,11 +399,61 @@ impl MatrixClient {
|
|||||||
})
|
})
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
let mut store = self.store.read().unwrap().to_owned();
|
self.start_background_tasks(synchronized_rx);
|
||||||
store.is_logged = true;
|
|
||||||
let _ = self.store.write(store);
|
|
||||||
|
|
||||||
println!("User connected to the homeserver");
|
|
||||||
Ok(())
|
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