daydream

A small matrix web client written in rust
git clone git://archive.git.mtrnord.blog/daydream-mx/daydream.git
Log | Files | Refs | README | LICENSE

commit 6c68df0a3b17e7e4b38b9543cacd6a91902f7ccd
parent b0fc038f3750fb6e979f7df9368f1bcafbed11d9
Author: Marcel <mtrnord1@gmail.com>
Date:   Wed, 27 May 2020 17:52:23 +0200

Add basic backfilling

Took 55 minutes

Diffstat:
Msrc/app/matrix.rs | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/app/matrix/sync.rs | 6+++---
Msrc/app/views/main_view.rs | 24++++++++++++++++++++----
3 files changed, 109 insertions(+), 9 deletions(-)

diff --git a/src/app/matrix.rs b/src/app/matrix.rs @@ -2,8 +2,17 @@ use std::collections::{HashMap, HashSet}; use std::convert::TryFrom; use std::sync::{Arc, Mutex}; +use futures_locks::RwLock; +use js_int::UInt; +use linked_hash_set::LinkedHashSet; use log::*; -use matrix_sdk::{identifiers::RoomId, Client, ClientConfig, Room, Session}; +use matrix_sdk::{ + api::r0::{filter::RoomEventFilter, message::get_message_events::Direction}, + events::collections::all::RoomEvent, + events::room::message::{MessageEvent, MessageEventContent, TextMessageEventContent}, + identifiers::RoomId, + Client, ClientConfig, MessagesRequestBuilder, Room, Session, +}; use serde::{Deserialize, Serialize}; use url::Url; use wasm_bindgen_futures::spawn_local; @@ -14,7 +23,6 @@ use yew::worker::*; use crate::app::matrix::types::{MessageWrapper, SmallRoom}; use crate::constants::AUTH_KEY; use crate::errors::MatrixError; -use futures_locks::RwLock; mod sync; pub mod types; @@ -52,6 +60,8 @@ pub enum Request { SetPassword(String), Login(), GetLoggedIn, + GetUserdata, + GetOldMessages((RoomId, Option<String>)), StartSync, GetJoinedRooms, } @@ -64,6 +74,8 @@ pub enum Response { Sync(MessageWrapper), FinishedFirstSync, JoinedRoomList(HashMap<RoomId, SmallRoom>), + Userdata(), + OldMessages(LinkedHashSet<MessageWrapper>), } impl Agent for MatrixAgent { @@ -226,6 +238,78 @@ impl Agent for MatrixAgent { } }); } + Request::GetUserdata => { + // Noop + } + Request::GetOldMessages((room_id, from)) => { + let agent = self.clone(); + let client = self.matrix_client.clone().unwrap(); + spawn_local(async move { + let mut builder = &mut MessagesRequestBuilder::new(); + builder = builder.room_id(room_id.clone()); + if from.is_some() { + builder = builder.from(from.unwrap()); + } else { + builder = builder.from(client.clone().sync_token().await.unwrap()); + } + let filter = RoomEventFilter { + types: Some(vec!["m.room.message".to_string()]), + ..Default::default() + }; + builder = builder + .filter(filter) + .direction(Direction::Backward) + .limit(UInt::new(30).unwrap()); + + let messsages = client.room_messages(builder.clone()).await.unwrap(); + // TODO save end point for future loading + + 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; + 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(), + }; + wrapped_messages.insert(wrapper); + } else { + continue; + }; + } + } + + for sub in agent.subscribers.iter() { + let resp = Response::OldMessages(wrapped_messages.clone()); + agent.link.respond(*sub, resp); + } + }); + } } } diff --git a/src/app/matrix/sync.rs b/src/app/matrix/sync.rs @@ -1,5 +1,6 @@ use crate::app::matrix::types::MessageWrapper; use crate::app::matrix::Response; +use futures_locks::RwLock; use log::*; use matrix_sdk::{ api::r0::sync::sync_events::Response as SyncResponse, @@ -8,9 +9,7 @@ use matrix_sdk::{ identifiers::RoomId, Client, Room, SyncSettings, }; -use futures::AsyncReadExt; use std::sync::Arc; -use futures_locks::RwLock; pub struct Sync<F> where @@ -61,7 +60,8 @@ where }) = event { let name = { - let room: Arc<RwLock<Room>> = self.matrix_client.get_joined_room(room_id).await.unwrap(); + 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 diff --git a/src/app/views/main_view.rs b/src/app/views/main_view.rs @@ -1,4 +1,4 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::{HashMap}; use std::convert::TryFrom; use js_int::UInt; @@ -64,11 +64,27 @@ impl Component for MainView { self.state.events.insert(msg); } Response::JoinedRoomList(rooms) => self.state.rooms = rooms, + Response::OldMessages(messages) => { + // TODO this doesn't seem smart + let mut new_events_map = LinkedHashSet::new(); + for event in messages.into_iter() { + new_events_map.insert(event); + } + for event in self.state.events.clone().into_iter() { + new_events_map.insert(event); + } + self.state.events = new_events_map; + } _ => {} } } Msg::ChangeRoom(room) => { - self.state.current_room = Some(RoomId::try_from(room).unwrap()); + 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()); } } true @@ -91,7 +107,7 @@ impl Component for MainView { </div> <div class="container uk-height-1-1 uk-width-5-6 uk-padding"> - <div class="scrollable uk-height-1-1"> + <div class="scrollable" uk-height-viewport="expand: true"> // TODO add some content to the empty page </div> </div> @@ -109,7 +125,7 @@ impl Component for MainView { <div class="container uk-height-1-1 uk-width-5-6 uk-padding"> <h1>{ self.state.rooms.iter().filter(|(id, _)| **id == self.state.current_room.clone().unwrap()).map(|(_, room)| room.name.clone()).collect::<String>() }</h1> - <div class="scrollable uk-height-1-1"> + <div class="scrollable" uk-height-viewport="expand: true"> { self.state.events.iter().filter(|x| x.room_id == self.state.current_room.clone().unwrap()).map(|event| self.get_event(event.clone())).collect::<Html>() } </div> </div>