Trigger re-render when pushing to the log

This commit is contained in:
Val Lorentz 2023-11-04 16:38:46 +01:00
parent 0d24d659c5
commit 6f8c3a19b2
4 changed files with 42 additions and 39 deletions

View File

@ -17,7 +17,6 @@
use std::cell::RefCell;
use std::collections::VecDeque;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::RwLock;
use color_eyre::eyre::{eyre, Result, WrapErr};
use crossterm::event::KeyEvent;
@ -56,7 +55,7 @@ impl App {
pub async fn new(
tick_rate: f64,
frame_rate: f64,
mem_log: &'static RwLock<VecDeque<String>>,
log_receiver: mpsc::UnboundedReceiver<String>,
) -> Result<Self> {
let home = Home::new();
let fps = FpsCounter::default();
@ -132,7 +131,7 @@ impl App {
components: vec![Box::new(home), Box::new(fps)],
should_quit: AtomicBool::new(false),
should_suspend: false,
buffers: Buffers::new(Box::new(LogBuffer::new(mem_log))),
buffers: Buffers::new(Box::new(LogBuffer::new(log_receiver))),
clients,
config,
commands: RataCommands::new(),

View File

@ -18,34 +18,52 @@ use std::collections::VecDeque;
use std::sync::Arc;
use std::sync::RwLock;
use matrix_sdk::async_trait;
use ratatui::text::Text;
use tokio::sync::mpsc::UnboundedReceiver;
use tracing_error::ErrorLayer;
use tracing_subscriber::prelude::*;
use super::Buffer;
/// Maximum number of log lines to be stored in memory
const MAX_MEM_LOG_LINES: usize = 100;
pub struct LogBuffer {
lines: &'static RwLock<VecDeque<String>>,
lines: VecDeque<String>,
receiver: UnboundedReceiver<String>,
}
impl LogBuffer {
pub fn new(lines: &'static RwLock<VecDeque<String>>) -> Self {
LogBuffer { lines }
pub fn new(receiver: UnboundedReceiver<String>) -> Self {
LogBuffer {
lines: VecDeque::new(),
receiver,
}
}
}
#[async_trait]
impl Buffer for LogBuffer {
fn short_name(&self) -> String {
"ratatrix".to_owned()
}
async fn poll_updates(&mut self) {
let line = self
.receiver
.recv()
.await
.expect("LogBuffer's channel was closed");
if self.lines.len() >= MAX_MEM_LOG_LINES {
self.lines.pop_front();
}
self.lines.push_back(line);
}
fn content(&self) -> Vec<Text> {
use ansi_to_tui::IntoText;
let lines = self
.lines
.read()
.expect("LogBuffer could not get log's RwLock as it is poisoned");
let (slice1, slice2) = lines.as_slices();
let (slice1, slice2) = self.lines.as_slices();
slice1
.into_iter()
.chain(slice2.into_iter())

View File

@ -29,9 +29,7 @@ pub trait Buffer: Send + Sync {
/// A short human-readable name for the room, eg. to show in compact buflist
fn short_name(&self) -> String;
/// Returns if there are any updates to apply.
async fn poll_updates(&mut self) {
std::future::pending().await
}
async fn poll_updates(&mut self);
fn content(&self) -> Vec<ratatui::text::Text>; // TODO: make this lazy, only the last few are used
/// Called when the user is being showned the oldest items this buffer returned.
///

View File

@ -18,23 +18,21 @@ use std::collections::VecDeque;
use std::sync::RwLock;
use color_eyre::eyre::Result;
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
use tracing_error::ErrorLayer;
use tracing_subscriber::prelude::*;
use crate::utils::{get_data_dir, LOG_ENV, LOG_FILE};
/// Maximum number of log lines to be stored in memory
const MAX_MEM_LOG_LINES: usize = 100;
pub struct LogWriter {
lines: &'static RwLock<VecDeque<String>>,
sender: UnboundedSender<String>,
last_line: Vec<u8>,
}
impl LogWriter {
fn new(lines: &'static RwLock<VecDeque<String>>) -> Self {
fn new(sender: UnboundedSender<String>) -> Self {
LogWriter {
lines,
sender,
last_line: Vec::new(),
}
}
@ -55,20 +53,12 @@ impl std::io::Write for LogWriter {
// No new line, nothing to do
} else {
let last_line = new_lines.pop().expect("Split returned empty vec").to_vec();
let mut lines = self.lines.write().map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!(
"LogWriter could not get log's RwLock as it is poisoned: {}",
e
),
)
})?;
for new_line in new_lines.into_iter() {
if lines.len() >= MAX_MEM_LOG_LINES {
lines.pop_front();
}
lines.push_back(String::from_utf8_lossy(new_line).to_string());
let new_line = String::from_utf8_lossy(new_line).to_string();
self
.sender
.send(new_line)
.unwrap_or_else(|e| panic!("Could not push log line: {:?}", e));
}
self.last_line.clear();
self.last_line.extend(&last_line[..]);
@ -78,7 +68,7 @@ impl std::io::Write for LogWriter {
}
}
pub fn initialize_logging() -> Result<&'static RwLock<VecDeque<String>>> {
pub fn initialize_logging() -> Result<UnboundedReceiver<String>> {
let directory = get_data_dir();
std::fs::create_dir_all(directory.clone())?;
let log_path = directory.join(LOG_FILE.clone());
@ -98,15 +88,13 @@ pub fn initialize_logging() -> Result<&'static RwLock<VecDeque<String>>> {
.with_filter(tracing_subscriber::filter::EnvFilter::from_default_env());
// We keep the log until the application stops, so we might as well return it as &'static
let lines = Box::leak(Box::new(RwLock::new(VecDeque::with_capacity(
MAX_MEM_LOG_LINES,
))));
let (sender, receiver) = unbounded_channel();
let mem_subscriber = tracing_subscriber::fmt::layer()
.with_ansi(true)
.with_file(true)
.with_line_number(true)
.with_target(false)
.with_writer(|| LogWriter::new(lines))
.with_writer(move || LogWriter::new(sender.clone()))
.with_filter(tracing_subscriber::filter::EnvFilter::from_default_env());
tracing_subscriber::registry()
@ -114,5 +102,5 @@ pub fn initialize_logging() -> Result<&'static RwLock<VecDeque<String>>> {
.with(file_subscriber)
.with(ErrorLayer::default())
.init();
Ok(lines)
Ok(receiver)
}