commit ade988a190a6b63c67b1ae7cd59818220e8485b3
parent e86de62fa427004e847c9bbf21fb9b701925a23a
Author: Marcel <mtrnord1@gmail.com>
Date: Thu, 28 May 2020 19:37:06 +0200
Optimize Sync flow
Took 2 hours 6 minutes
Diffstat:
8 files changed, 199 insertions(+), 135 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -23,11 +23,10 @@ wee_alloc = "0.4"
yew = { git = "https://github.com/yewstack/yew" }
yew-router = { git = "https://github.com/yewstack/yew" }
yewtil = { git = "https://github.com/yewstack/yew" }
-matrix-sdk = { version = "0.1.0", git = "https://github.com/matrix-org/matrix-rust-sdk.git", default-features = false}
+matrix-sdk = { version = "0.1.0", git = "https://github.com/MTRNord/matrix-rust-sdk", branch = "expose-send-rebased", default-features = false}
url = "2.1.1"
thiserror = "1.0"
futures-locks = { git = "https://github.com/asomers/futures-locks", default-features = false }
-js_int = "0.1.5"
linked_hash_set = {version = "0.1.3", features = ["serde"] }
[dev-dependencies]
diff --git a/src/app.rs b/src/app.rs
@@ -1,10 +1,10 @@
use log::*;
use yew::{prelude::*, virtual_dom::VNode};
+use yew_router::agent::RouteRequest::ChangeRoute;
use yew_router::{prelude::*, Switch};
use crate::app::matrix::{MatrixAgent, Response};
use crate::app::views::{login::Login, main_view::MainView};
-use yew_router::agent::RouteRequest::ChangeRoute;
pub mod components;
mod matrix;
diff --git a/src/app/components/event_list.rs b/src/app/components/event_list.rs
@@ -5,8 +5,8 @@ use serde::{Deserialize, Serialize};
use yew::prelude::*;
use yewtil::NeqAssign;
-use crate::app::matrix::{MatrixAgent, Request, Response};
use crate::app::matrix::types::MessageWrapper;
+use crate::app::matrix::{MatrixAgent, Request, Response};
pub struct EventList {
link: ComponentLink<Self>,
@@ -50,7 +50,7 @@ impl Component for EventList {
if state
.events
.iter()
- .filter(|x| x.room_id == room_id)
+ .filter(|x| x.room_id.clone().unwrap() == room_id)
.collect::<LinkedHashSet<&MessageWrapper>>()
.is_empty()
{
@@ -58,8 +58,6 @@ impl Component for EventList {
}
}
-
-
EventList {
props,
link,
@@ -80,19 +78,17 @@ impl Component for EventList {
Response::OldMessages(messages) => {
// TODO this doesn't seem smart
let mut new_events_map = LinkedHashSet::new();
- for event in messages.into_iter() {
+ for event in self.state.events.clone().into_iter() {
new_events_map.insert(event);
}
- for event in self.state.events.clone().into_iter() {
+ for event in messages.into_iter() {
new_events_map.insert(event);
}
self.state.events = new_events_map;
true
}
- _ => {
- false
- }
+ _ => false,
}
}
}
@@ -107,7 +103,7 @@ impl Component for EventList {
<div class="container uk-flex uk-flex-column uk-width-5-6 uk-padding uk-padding-remove-bottom" style="height: 100%">
<h1>{ self.props.displayname.clone() }</h1>
<div class="scrollable" style="height: 100%">
- { self.state.events.iter().filter(|x| x.room_id == self.props.current_room.clone().unwrap()).map(|event| self.get_event(event.clone())).collect::<Html>() }
+ { self.state.events.iter().filter(|x| x.room_id.clone().unwrap() == self.props.current_room.clone().unwrap()).map(|event| self.get_event(event.clone())).collect::<Html>() }
<div id="anchor"></div>
</div>
</div>
@@ -115,11 +111,10 @@ impl Component for EventList {
}
}
-
impl EventList {
fn get_event(&self, event: MessageWrapper) -> Html {
html! {
- <p>{event.sender_displayname.clone()}{": "}{event.content.clone()}</p>
+ <p>{event.sender_displayname.unwrap_or(event.sender.to_string()).clone()}{": "}{event.content.clone()}</p>
}
}
}
diff --git a/src/app/components/room_list.rs b/src/app/components/room_list.rs
@@ -1,15 +1,14 @@
use std::collections::HashMap;
-use js_int::UInt;
use log::*;
-use matrix_sdk::identifiers::RoomId;
+use matrix_sdk::{identifiers::RoomId, js_int::UInt};
use serde::{Deserialize, Serialize};
use yew::prelude::*;
use yew::{Bridge, Bridged, Component, ComponentLink, Html};
use yewtil::NeqAssign;
use crate::app::matrix::types::SmallRoom;
-use crate::app::matrix::{MatrixAgent, Response};
+use crate::app::matrix::{MatrixAgent, Request, Response};
pub struct RoomList {
link: ComponentLink<Self>,
@@ -49,7 +48,7 @@ impl Component for RoomList {
rooms: Default::default(),
current_room: None,
loading: true,
- search_query: None
+ search_query: None,
};
RoomList {
@@ -68,14 +67,41 @@ impl Component for RoomList {
self.state.loading = false;
true
}
+ // Handle new rooms from sync
+ Response::Sync(msg) => {
+ info!("room_list sync_message: {:#?}", msg);
+ if !(self
+ .state
+ .rooms
+ .keys()
+ .map(|x| x.clone())
+ .collect::<Vec<RoomId>>()
+ .contains(&msg.room_id.clone().unwrap()))
+ {
+ self.matrix_agent
+ .send(Request::GetJoinedRoom(msg.room_id.clone().unwrap()));
+ }
+ true
+ }
+ Response::JoinedRoom((room_id, room)) => {
+ self.state.rooms.insert(room_id, room);
+ true
+ }
_ => false,
},
Msg::ChangeRoom(room) => {
- let displayname = self.state.rooms.iter().filter(|(id, _)| **id == room).map(|(_, room)| room.name.clone()).collect::<String>();
+ let displayname = self
+ .state
+ .rooms
+ .iter()
+ .filter(|(id, _)| **id == room)
+ .map(|(_, room)| room.name.clone())
+ .collect::<String>();
self.props.change_room_callback.emit((displayname, room));
false
}
Msg::SetFilter(query) => {
+ info!("{}", query);
self.state.search_query = Some(query);
true
}
@@ -105,6 +131,7 @@ impl Component for RoomList {
class="uk-search-input"
type="search"
placeholder="Filter Rooms..."
+ value=&self.state.search_query.clone().unwrap_or("".to_string())
oninput=self.link.callback(|e: InputData| Msg::SetFilter(e.value)) />
</form>
</div>
diff --git a/src/app/matrix.rs b/src/app/matrix.rs
@@ -1,16 +1,16 @@
use std::collections::{HashMap, HashSet};
-use std::convert::TryFrom;
+use std::convert::{TryFrom, TryInto};
use std::sync::{Arc, Mutex};
use futures_locks::RwLock;
-use js_int::UInt;
use linked_hash_set::LinkedHashSet;
use log::*;
use matrix_sdk::{
api::r0::{filter::RoomEventFilter, message::get_message_events::Direction},
events::collections::all::RoomEvent,
- events::room::message::{MessageEvent, MessageEventContent, TextMessageEventContent},
+ events::room::message::MessageEventContent,
identifiers::RoomId,
+ js_int::UInt,
Client, ClientConfig, MessagesRequestBuilder, Room, Session,
};
use serde::{Deserialize, Serialize};
@@ -64,6 +64,7 @@ pub enum Request {
GetOldMessages((RoomId, Option<String>)),
StartSync,
GetJoinedRooms,
+ GetJoinedRoom(RoomId),
}
#[derive(Serialize, Deserialize, Debug, Clone)]
@@ -76,11 +77,17 @@ pub enum Response {
JoinedRoomList(HashMap<RoomId, SmallRoom>),
Userdata(),
OldMessages(LinkedHashSet<MessageWrapper>),
+ JoinedRoom((RoomId, SmallRoom)),
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub enum Msg {
+ OnSyncResponse(Response),
}
impl Agent for MatrixAgent {
type Reach = Context<MatrixAgent>;
- type Message = ();
+ type Message = Msg;
type Input = Request;
type Output = Response;
@@ -105,7 +112,15 @@ impl Agent for MatrixAgent {
}
}
- fn update(&mut self, _: Self::Message) {}
+ fn update(&mut self, msg: Self::Message) {
+ match msg {
+ Msg::OnSyncResponse(resp) => {
+ for sub in self.subscribers.iter() {
+ self.link.respond(*sub, resp.clone());
+ }
+ }
+ }
+ }
fn connected(&mut self, id: HandlerId) {
self.subscribers.insert(id);
@@ -267,42 +282,29 @@ impl Agent for MatrixAgent {
let mut wrapped_messages: LinkedHashSet<MessageWrapper> = LinkedHashSet::new();
for event in messsages.chunk.iter().rev() {
if let Ok(event) = event.deserialize() {
- if let RoomEvent::RoomMessage(MessageEvent {
- content:
- MessageEventContent::Text(TextMessageEventContent {
- body: msg_body,
- ..
- }),
- sender,
- ..
- }) = event
- {
- let name = {
- let room: Arc<RwLock<Room>> = client
- .clone()
- .get_joined_room(&room_id.clone())
- .await
- .unwrap();
- let room = room.read().await;
- match room.members.get(&sender) {
- Some(member) => member
- .display_name
- .as_ref()
- .map(ToString::to_string)
- .unwrap_or(sender.to_string()),
- None => sender.to_string(),
+ match event {
+ RoomEvent::RoomMessage(event) => match event.content {
+ MessageEventContent::Text(_) => {
+ let mut wrapped_event: MessageWrapper =
+ event.try_into().expect("m.room.message");
+
+ if wrapped_event.room_id.is_none() {
+ wrapped_event.room_id = Some(room_id.clone());
+ }
+
+ wrapped_event.sender_displayname = Some(
+ wrapped_event.get_displayname(client.clone()).await,
+ );
+ wrapped_messages.insert(wrapped_event);
}
- };
-
- let wrapper = MessageWrapper {
- sender_displayname: name.clone(),
- room_id: room_id.clone(),
- content: msg_body.clone(),
- };
- wrapped_messages.insert(wrapper);
- } else {
- continue;
- };
+ _ => {
+ return;
+ }
+ },
+ _ => {
+ continue;
+ }
+ }
}
}
@@ -312,6 +314,24 @@ impl Agent for MatrixAgent {
}
});
}
+ Request::GetJoinedRoom(room_id) => {
+ let agent = self.clone();
+ let client = self.matrix_client.clone().unwrap();
+ spawn_local(async move {
+ let room: Arc<RwLock<Room>> =
+ client.get_joined_room(&room_id.clone()).await.unwrap();
+ let small_room = SmallRoom {
+ name: room.read().await.display_name(),
+ unread_notifications: room.read().await.unread_notifications.clone(),
+ unread_highlight: room.read().await.unread_highlight.clone(),
+ id: room_id.clone(),
+ };
+ for sub in agent.subscribers.iter() {
+ let resp = Response::JoinedRoom((room_id.clone(), small_room.clone()));
+ agent.link.respond(*sub, resp);
+ }
+ });
+ }
}
}
@@ -328,11 +348,7 @@ impl MatrixAgent {
async fn start_sync(&self) {
let sync = sync::Sync {
matrix_client: self.matrix_client.clone().unwrap(),
- callback: |x: Response| {
- for sub in self.subscribers.iter() {
- self.link.respond(*sub, x.clone());
- }
- },
+ callback: self.link.callback(Msg::OnSyncResponse),
};
sync.start_sync().await;
}
diff --git a/src/app/matrix/sync.rs b/src/app/matrix/sync.rs
@@ -1,35 +1,28 @@
-use crate::app::matrix::types::MessageWrapper;
-use crate::app::matrix::Response;
-use futures_locks::RwLock;
+use std::convert::TryInto;
+
use log::*;
use matrix_sdk::{
- api::r0::sync::sync_events::Response as SyncResponse,
- events::collections::all::RoomEvent,
- events::room::message::{MessageEvent, MessageEventContent, TextMessageEventContent},
- identifiers::RoomId,
- Client, Room, SyncSettings,
+ api::r0::sync::sync_events::Response as SyncResponse, events::collections::all::RoomEvent,
+ events::room::message::MessageEventContent, identifiers::RoomId, Client, SyncSettings,
};
-use std::sync::Arc;
-pub struct Sync<F>
-where
- F: Fn(Response) + std::marker::Sync,
-{
+use crate::app::matrix::types::MessageWrapper;
+use crate::app::matrix::Response;
+use yew::Callback;
+
+pub struct Sync {
pub(crate) matrix_client: Client,
- pub(crate) callback: F,
+ pub(crate) callback: Callback<Response>,
}
-impl<F> Sync<F>
-where
- F: Fn(Response) + std::marker::Sync,
-{
+impl Sync {
pub async fn start_sync(&self) {
let client = self.matrix_client.clone();
let resp = client.clone().sync(SyncSettings::default()).await;
match resp {
Ok(_) => {
let resp = Response::FinishedFirstSync;
- (self.callback)(resp);
+ self.callback.emit(resp);
}
_ => {}
}
@@ -53,34 +46,32 @@ where
async fn on_room_message(&self, room_id: &RoomId, event: RoomEvent) {
// TODO handle all messages...
- if let RoomEvent::RoomMessage(MessageEvent {
- content: MessageEventContent::Text(TextMessageEventContent { body: msg_body, .. }),
- sender,
- ..
- }) = event
- {
- let name = {
- let room: Arc<RwLock<Room>> =
- self.matrix_client.get_joined_room(room_id).await.unwrap();
- let room = room.read().await;
- let member = room.members.get(&sender).unwrap();
- member
- .display_name
- .as_ref()
- .map(ToString::to_string)
- .unwrap_or(sender.to_string())
- };
- let wrapper = MessageWrapper {
- sender_displayname: name.clone(),
- room_id: room_id.clone(),
- content: msg_body.clone(),
- };
+ match event {
+ RoomEvent::RoomMessage(event) => match event.content {
+ MessageEventContent::Text(_) => {
+ let mut wrapped_event: MessageWrapper =
+ event.try_into().expect("m.room.message");
- let resp = Response::Sync(wrapper);
- (self.callback)(resp);
- } else {
- return;
- };
+ if wrapped_event.room_id.is_none() {
+ wrapped_event.room_id = Some(room_id.clone());
+ }
+
+ wrapped_event.sender_displayname = Some(
+ wrapped_event
+ .get_displayname(self.matrix_client.clone())
+ .await,
+ );
+ let resp = Response::Sync(wrapped_event);
+ self.callback.emit(resp);
+ }
+ _ => {
+ return;
+ }
+ },
+ _ => {
+ return;
+ }
+ }
}
}
diff --git a/src/app/matrix/types.rs b/src/app/matrix/types.rs
@@ -1,7 +1,16 @@
-use js_int::UInt;
-use matrix_sdk::identifiers::RoomId;
+use std::convert::TryFrom;
+use std::sync::Arc;
+
+use futures_locks::RwLock;
+use matrix_sdk::{
+ events::room::message::{MessageEvent, MessageEventContent, TextMessageEventContent},
+ identifiers::{RoomId, UserId},
+ js_int::UInt,
+ Client, Room,
+};
use serde::{Deserialize, Serialize};
+// TODO: Add Into trait
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SmallRoom {
pub(crate) name: String,
@@ -12,8 +21,47 @@ pub struct SmallRoom {
#[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq)]
pub struct MessageWrapper {
- pub(crate) sender_displayname: String,
- pub(crate) room_id: RoomId,
+ pub(crate) sender_displayname: Option<String>,
+ pub(crate) room_id: Option<RoomId>,
+ pub(crate) sender: UserId,
// TODO use ruma structs
pub(crate) content: String,
}
+
+impl MessageWrapper {
+ pub async fn get_displayname(&self, client: Client) -> String {
+ let room: Arc<RwLock<Room>> = client
+ .get_joined_room(&self.room_id.clone().unwrap())
+ .await
+ .unwrap();
+ let room = room.read().await;
+ let member = room.members.get(&self.sender.clone()).unwrap();
+ member
+ .display_name
+ .as_ref()
+ .map(ToString::to_string)
+ .unwrap_or(self.sender.clone().to_string())
+ }
+}
+
+impl TryFrom<MessageEvent> for MessageWrapper {
+ type Error = ();
+
+ fn try_from(event: MessageEvent) -> Result<Self, Self::Error> {
+ return if let MessageEvent {
+ content: MessageEventContent::Text(TextMessageEventContent { body: msg_body, .. }),
+ sender,
+ ..
+ } = event
+ {
+ Ok(MessageWrapper {
+ sender_displayname: None, // We cant get it without a Client and therefor cant calculate it here
+ room_id: event.room_id,
+ sender,
+ content: msg_body,
+ })
+ } else {
+ Err(())
+ };
+ }
+}
diff --git a/src/app/views/main_view.rs b/src/app/views/main_view.rs
@@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use yew::prelude::*;
use yew::ComponentLink;
-use crate::app::components::{room_list::RoomList, event_list::EventList};
+use crate::app::components::{event_list::EventList, room_list::RoomList};
use crate::app::matrix::types::MessageWrapper;
use crate::app::matrix::{MatrixAgent, Request, Response};
@@ -41,7 +41,7 @@ impl Component for MainView {
let state = State {
events: Default::default(),
current_room: None,
- current_room_displayname: Default::default()
+ current_room_displayname: Default::default(),
};
MainView {
@@ -53,27 +53,15 @@ impl Component for MainView {
fn update(&mut self, msg: Self::Message) -> bool {
match msg {
- Msg::NewMessage(response) => {
- match response {
- Response::FinishedFirstSync => {
- self.matrix_agent.send(Request::GetJoinedRooms);
- }
- _ => {}
+ Msg::NewMessage(response) => match response {
+ Response::FinishedFirstSync => {
+ self.matrix_agent.send(Request::GetJoinedRooms);
}
- }
+ _ => {}
+ },
Msg::ChangeRoom((displayname, room)) => {
let room_id = RoomId::try_from(room).unwrap();
- if self
- .state
- .events
- .iter()
- .filter(|x| x.room_id == room_id)
- .collect::<LinkedHashSet<&MessageWrapper>>()
- .is_empty()
- {
- self.matrix_agent
- .send(Request::GetOldMessages((room_id.clone(), None)));
- }
+
self.state.current_room = Some(room_id.clone());
self.state.current_room_displayname = displayname;
}