From f8bf6ee07d0ad4d2f707b334f9751b2eb548247a Mon Sep 17 00:00:00 2001 From: antifallobst Date: Fri, 7 Jul 2023 00:52:16 +0200 Subject: [PATCH] feature (status - rooms): Implemented a timeline event caching layer --- src/app/mod.rs | 7 +++++ src/app/status.rs | 72 +++++++++++++++++++++++++++++++++++++++++++---- src/ui/mod.rs | 68 +++++++++++++++++++------------------------- 3 files changed, 103 insertions(+), 44 deletions(-) diff --git a/src/app/mod.rs b/src/app/mod.rs index 478db4f..8037ada 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -139,6 +139,13 @@ impl App<'_> { self.status.set_account_name(name); self.status.set_account_user_id(user_id); + + for room in self.status.rooms_mut() { + room.poll_old_timeline().await?; + room.poll_old_timeline().await?; + room.poll_old_timeline().await?; + } + info!("Initializing client for the current account"); Ok(()) diff --git a/src/app/status.rs b/src/app/status.rs index a2fbdda..d916645 100644 --- a/src/app/status.rs +++ b/src/app/status.rs @@ -1,5 +1,9 @@ -use matrix_sdk::Client; -use matrix_sdk::ruma::{room_id, RoomId, ServerName}; +use matrix_sdk::{Client, + ruma::{events::{AnyTimelineEvent}}, + deserialized_responses::TimelineEvent, + room::MessagesOptions}; +use anyhow::{Result, Error}; +use cli_log::{error, warn, info}; pub enum State { None, @@ -7,20 +11,70 @@ pub enum State { Setup, } +pub struct Room { + matrix_room: matrix_sdk::room::Joined, + timeline: Vec, + timeline_end: Option, +} + pub struct Status { state: State, account_name: String, account_user_id: String, client: Option, - rooms: Vec, + rooms: Vec, current_room_id: Option, } +impl Room { + pub fn new (matrix_room: matrix_sdk::room::Joined) -> Self { + Self { + matrix_room, + timeline: Vec::new(), + timeline_end: None, + } + } + + pub async fn poll_old_timeline(&mut self) -> Result<()> { + let mut messages_options = MessagesOptions::backward(); + messages_options = match &self.timeline_end { + Some(end) => messages_options.from(end.as_str()), + None => messages_options + }; + let events = self.matrix_room.messages(messages_options).await?; + self.timeline_end = events.end; + + for event in events.chunk.iter() { + self.timeline.insert(0, match event.event.deserialize() { + Ok(ev) => ev, + Err(err) => { + warn!("Failed to deserialize timeline event - {err}"); + continue; + } + }); + } + Ok(()) + } + + pub fn timeline_add(&mut self, event: AnyTimelineEvent) { + self.timeline.push(event); + } + + pub fn timeline(&self) -> &Vec { &self.timeline } +} + impl Status { pub fn new(client: Option) -> Self { let rooms = match &client { - Some(c) => c.joined_rooms(), + Some(c) => { + c.joined_rooms() + .iter() + .map(|r| { + Room::new(r.clone()) + }) + .collect::>() + }, None => Vec::new(), }; @@ -50,9 +104,17 @@ impl Status { self.account_user_id = user_id; } - pub fn room(&self) -> Option<&matrix_sdk::room::Joined> { + pub fn room(&self) -> Option<&Room> { self.rooms.get(self.current_room_id? as usize) } + + pub fn rooms(&self) -> &Vec { + &self.rooms + } + + pub fn rooms_mut(&mut self) -> &mut Vec { + &mut self.rooms + } pub fn state(&self) -> &State { &self.state diff --git a/src/ui/mod.rs b/src/ui/mod.rs index aad617f..565f208 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -276,52 +276,42 @@ impl UI<'_> { status_content.extend(Text::styled(status.account_user_id(), Style::default())); status_content.extend(Text::styled("settings", Style::default().fg(Color::LightMagenta).add_modifier(Modifier::ITALIC | Modifier::UNDERLINED))); - let messages_config = MessagesOptions::backward(); - let messages_content = match status.room() { Some(r) => { - r.messages(messages_config) - .await? - .chunk + r.timeline() .iter() - .rev() .map(|event| { - match event.event.deserialize() { - Ok(timeline_event) => match timeline_event { + match event { - // Message Like Events - AnyTimelineEvent::MessageLike(message_like_event) => { - let (content, color) = match &message_like_event { - AnyMessageLikeEvent::RoomMessage(room_message_event) => { - let message_content = &room_message_event - .as_original() - .unwrap() - .content - .body(); + // Message Like Events + AnyTimelineEvent::MessageLike(message_like_event) => { + let (content, color) = match &message_like_event { + AnyMessageLikeEvent::RoomMessage(room_message_event) => { + let message_content = &room_message_event + .as_original() + .unwrap() + .content + .body(); - (message_content.to_string(), Color::White) - }, - _ => ("~~~ not supported message like event ~~~".to_string(), Color::Red) - }; - Spans::from(vec![ - Span::styled(message_like_event.sender().to_string(), Style::default().fg(Color::Cyan)), - Span::styled(": ", Style::default().fg(Color::Cyan)), - Span::styled(content, Style::default().fg(color)), - ]) - }, - - // State Events - AnyTimelineEvent::State(state) => { - Spans::from(vec![ - Span::styled(state.sender().to_string(), Style::default().fg(Color::DarkGray)), - Span::styled(": ", Style::default().fg(Color::DarkGray)), - Span::styled(state.event_type().to_string(), Style::default().fg(Color::DarkGray)) - ]) - } + (message_content.to_string(), Color::White) + }, + _ => ("~~~ not supported message like event ~~~".to_string(), Color::Red) + }; + Spans::from(vec![ + Span::styled(message_like_event.sender().to_string(), Style::default().fg(Color::Cyan)), + Span::styled(": ", Style::default().fg(Color::Cyan)), + Span::styled(content, Style::default().fg(color)), + ]) }, - Err(_) => Spans::from( - Span::styled("Failed to deserialize event", Style::default().fg(Color::Red)) - ) + + // State Events + AnyTimelineEvent::State(state) => { + Spans::from(vec![ + Span::styled(state.sender().to_string(), Style::default().fg(Color::DarkGray)), + Span::styled(": ", Style::default().fg(Color::DarkGray)), + Span::styled(state.event_type().to_string(), Style::default().fg(Color::DarkGray)) + ]) + } } }) .collect::>()