From e0db158ece6545dcc8578c4ceb553f01e8e29a76 Mon Sep 17 00:00:00 2001 From: Joscha Date: Thu, 23 Jun 2022 22:15:36 +0200 Subject: [PATCH] Redraw whenever a message is logged --- Cargo.toml | 2 +- src/logger.rs | 30 ++++++++++++++++++++---------- src/main.rs | 4 ++-- src/ui.rs | 32 +++++++++++++++++++++++++------- 4 files changed, 48 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6ec330c..395941f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ crossterm = "0.23.2" directories = "4.0.1" edit = "0.1.4" futures = "0.3.21" -log = "0.4.17" +log = { version = "0.4.17", features = ["std"] } parking_lot = "0.12.1" rand = "0.8.5" rusqlite = { version = "0.27.0", features = ["chrono"] } diff --git a/src/logger.rs b/src/logger.rs index a6e0220..1bb553a 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -5,6 +5,7 @@ use async_trait::async_trait; use chrono::{DateTime, Utc}; use log::{Level, Log}; use parking_lot::Mutex; +use tokio::sync::mpsc; use crate::store::{Msg, MsgStore, Path, Tree}; @@ -41,7 +42,10 @@ impl Msg for LogMsg { } #[derive(Debug, Clone)] -pub struct Logger(Arc>>); +pub struct Logger { + event_tx: mpsc::UnboundedSender<()>, + messages: Arc>>, +} #[async_trait] impl MsgStore for Logger { @@ -51,7 +55,7 @@ impl MsgStore for Logger { async fn tree(&self, root: &usize) -> Tree { let msgs = self - .0 + .messages .lock() .get(*root) .map(|msg| vec![msg.clone()]) @@ -64,17 +68,17 @@ impl MsgStore for Logger { } async fn next_tree(&self, tree: &usize) -> Option { - let len = self.0.lock().len(); + let len = self.messages.lock().len(); tree.checked_add(1).filter(|t| *t < len) } async fn first_tree(&self) -> Option { - let empty = self.0.lock().is_empty(); + let empty = self.messages.lock().is_empty(); Some(0).filter(|_| !empty) } async fn last_tree(&self) -> Option { - self.0.lock().len().checked_sub(1) + self.messages.lock().len().checked_sub(1) } } @@ -88,7 +92,7 @@ impl Log for Logger { return; } - let mut guard = self.0.lock(); + let mut guard = self.messages.lock(); let msg = LogMsg { id: guard.len(), time: Utc::now(), @@ -96,18 +100,24 @@ impl Log for Logger { content: format!("<{}> {}", record.target(), record.args()), }; guard.push(msg); + + let _ = self.event_tx.send(()); } fn flush(&self) {} } impl Logger { - pub fn init(level: Level) -> &'static Self { - let logger = Box::leak(Box::new(Self(Arc::new(Mutex::new(Vec::new()))))); + pub fn init(level: Level) -> (Self, mpsc::UnboundedReceiver<()>) { + let (event_tx, event_rx) = mpsc::unbounded_channel(); + let logger = Self { + event_tx, + messages: Arc::new(Mutex::new(Vec::new())), + }; - log::set_logger(logger).expect("logger already set"); + log::set_boxed_logger(Box::new(logger.clone())).expect("logger already set"); log::set_max_level(level.to_level_filter()); - logger + (logger, event_rx) } } diff --git a/src/main.rs b/src/main.rs index 27bd993..3869b59 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ use crate::logger::Logger; #[tokio::main] async fn main() -> anyhow::Result<()> { - let logger = Logger::init(log::Level::Debug); + let (logger, logger_rx) = Logger::init(log::Level::Debug); info!( "Welcome to {} {}", env!("CARGO_PKG_NAME"), @@ -31,7 +31,7 @@ async fn main() -> anyhow::Result<()> { let mut terminal = Terminal::new()?; // terminal.set_measuring(true); - Ui::run(&mut terminal, logger.clone()).await?; + Ui::run(&mut terminal, logger, logger_rx).await?; drop(terminal); // So the vault can print again vault.close().await; diff --git a/src/ui.rs b/src/ui.rs index db6c5a3..2d4a930 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -11,6 +11,7 @@ use toss::frame::{Frame, Pos, Size}; use toss::terminal::Terminal; use crate::chat::Chat; +use crate::euph; use crate::logger::{LogMsg, Logger}; use crate::store::dummy::{DummyMsg, DummyStore}; @@ -34,6 +35,7 @@ pub struct Ui { event_tx: UnboundedSender, visible: Visible, + room: euph::Room, chat: Chat, log_chat: Chat, } @@ -41,7 +43,11 @@ pub struct Ui { impl Ui { const POLL_DURATION: Duration = Duration::from_millis(100); - pub async fn run(terminal: &mut Terminal, logger: Logger) -> anyhow::Result<()> { + pub async fn run( + terminal: &mut Terminal, + logger: Logger, + logger_rx: mpsc::UnboundedReceiver<()>, + ) -> anyhow::Result<()> { let (event_tx, event_rx) = mpsc::unbounded_channel(); let crossterm_lock = Arc::new(FairMutex::new(())); @@ -77,16 +83,17 @@ impl Ui { // On the other hand, if the crossterm_event_task stops for any reason, // the rest of the UI is also shut down and the client stops. let mut ui = Self { - event_tx, + event_tx: event_tx.clone(), visible: Visible::Log, + room: euph::Room::new("test".to_string()), chat, log_chat: Chat::new(logger), }; - let result = tokio::select! { - e = ui.run_main(terminal, event_rx, crossterm_lock) => e, - Ok(e) = crossterm_event_task => e, - }; - result + tokio::select! { + e = ui.run_main(terminal, event_rx, crossterm_lock) => Ok(e), + _ = Self::update_on_log_event(logger_rx, &event_tx) => Ok(Ok(())), + e = crossterm_event_task => e, + }? } fn poll_crossterm_events( @@ -103,6 +110,17 @@ impl Ui { Ok(()) } + async fn update_on_log_event( + mut logger_rx: mpsc::UnboundedReceiver<()>, + event_tx: &mpsc::UnboundedSender, + ) { + while let Some(()) = logger_rx.recv().await { + if event_tx.send(UiEvent::Redraw).is_err() { + break; + } + } + } + async fn run_main( &mut self, terminal: &mut Terminal,