add logging screen, clean up widget rendering

This commit is contained in:
Joe Ardent 2025-07-29 16:27:49 -07:00
parent 1e64c5b1e8
commit 9b2172aa3a
2 changed files with 84 additions and 64 deletions

View file

@ -8,7 +8,7 @@ use axum::{
Json, Json,
extract::{ConnectInfo, State}, extract::{ConnectInfo, State},
}; };
use log::{error, warn}; use log::{debug, error, warn};
use tokio::net::UdpSocket; use tokio::net::UdpSocket;
use crate::{Config, JoecalState, RunningState, models::Device}; use crate::{Config, JoecalState, RunningState, models::Device};
@ -19,6 +19,7 @@ impl JoecalState {
socket: Option<SocketAddr>, socket: Option<SocketAddr>,
config: &Config, config: &Config,
) -> crate::error::Result<()> { ) -> crate::error::Result<()> {
debug!("announcing");
announce_http(&self.device, socket, self.client.clone()).await?; announce_http(&self.device, socket, self.client.clone()).await?;
announce_multicast(&self.device, config.multicast_addr, self.socket.clone()).await?; announce_multicast(&self.device, config.multicast_addr, self.socket.clone()).await?;
Ok(()) Ok(())
@ -38,10 +39,12 @@ impl JoecalState {
}; };
if rstate == RunningState::Stopping if rstate == RunningState::Stopping
{ {
debug!("stopping multicast listen");
break; break;
} }
}, },
r = self.socket.recv_from(&mut buf) => { r = self.socket.recv_from(&mut buf) => {
debug!("received multicast datagram");
match r { match r {
Ok((size, src)) => { Ok((size, src)) => {
let received_msg = String::from_utf8_lossy(&buf[..size]); let received_msg = String::from_utf8_lossy(&buf[..size]);

View file

@ -46,6 +46,7 @@ pub enum CurrentScreen {
Sending, Sending,
Receiving, Receiving,
Stopping, Stopping,
Logging,
} }
impl Default for App { impl Default for App {
@ -165,6 +166,7 @@ impl App {
KeyCode::Char('q') => self.exit(), KeyCode::Char('q') => self.exit(),
KeyCode::Char('s') => self.send(), KeyCode::Char('s') => self.send(),
KeyCode::Char('r') => self.recv(), KeyCode::Char('r') => self.recv(),
KeyCode::Char('l') => self.logs(),
KeyCode::Esc => self.pop(), KeyCode::Esc => self.pop(),
_ => {} _ => {}
} }
@ -194,6 +196,14 @@ impl App {
} }
} }
fn logs(&mut self) {
let last = self.screen.last();
match last {
Some(CurrentScreen::Logging) => {}
_ => self.screen.push(CurrentScreen::Logging),
}
}
fn pop(&mut self) { fn pop(&mut self) {
self.screen.pop(); self.screen.pop();
if self.screen.last().is_none() { if self.screen.last().is_none() {
@ -204,50 +214,73 @@ impl App {
impl Widget for &App { impl Widget for &App {
fn render(self, area: Rect, buf: &mut Buffer) { fn render(self, area: Rect, buf: &mut Buffer) {
let [top, middle, bottom] = Layout::default() let [top, middle, bottom] =
.direction(Direction::Vertical) Layout::vertical([Constraint::Min(5), Constraint::Min(10), Constraint::Min(3)])
.constraints([Constraint::Min(10), Constraint::Min(10), Constraint::Min(3)])
.split(area) .split(area)
.as_array() .as_array()
.cloned() .cloned()
.unwrap(); .unwrap();
let [footer_left, footer_right] = Layout::default() let [footer_left, footer_right] =
.direction(Direction::Horizontal) Layout::horizontal([Constraint::Percentage(30), Constraint::Percentage(70)])
.constraints([Constraint::Percentage(30), Constraint::Percentage(70)])
.split(bottom) .split(bottom)
.as_array() .as_array()
.cloned() .cloned()
.unwrap(); .unwrap();
let [header_left, header_right] = Layout::default() let [header_left, header_right] =
.direction(Direction::Horizontal) Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)])
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
.split(top) .split(top)
.as_array() .as_array()
.cloned() .cloned()
.unwrap(); .unwrap();
let mode = self.screen.last().unwrap();
match mode {
CurrentScreen::Main => {
main_page(*mode, area, buf);
logger(header_right.inner(Margin::new(1, 2)), buf);
let peers = PeersWidget { peers: &self.peers };
peers.render(footer_right.inner(Margin::new(1, 1)), buf);
NetworkInfoWidget.render(footer_left.inner(Margin::new(1, 1)), buf);
}
CurrentScreen::Receiving => {
main_page(*mode, area, buf);
}
CurrentScreen::Logging => {
main_page(*mode, area, buf);
logger(area.inner(Margin::new(2, 4)), buf);
}
_ => {
main_page(*mode, area, buf);
}
}
}
}
fn logger(area: Rect, buf: &mut Buffer) {
let logger = TuiLoggerWidget::default() let logger = TuiLoggerWidget::default()
.output_separator('|') .output_separator('|')
.output_timestamp(Some("%F %H:%M:%S%.3f".to_string())) .output_timestamp(Some("%H:%M:%S%.3f".to_string()))
.output_level(Some(TuiLoggerLevelOutput::Abbreviated)) .output_level(Some(TuiLoggerLevelOutput::Abbreviated))
.output_target(false) .output_target(true)
.output_file(false) .output_file(false)
.output_line(false) .output_line(false)
.block(Block::bordered().border_set(border::THICK)) .block(Block::bordered().border_set(border::THICK))
.style(Style::default()) .style(Style::default())
.state(&TuiWidgetState::new().set_default_display_level(LevelFilter::Debug)); .state(&TuiWidgetState::new().set_default_display_level(LevelFilter::Debug));
logger.render(area, buf);
}
{ fn main_page(screen: CurrentScreen, area: Rect, buf: &mut Buffer) {
let title = Line::from(" Joecalsend ".bold()); let title = Line::from(" Joecalsend ".bold());
let instructions = Line::from(vec![ let instructions = Line::from(vec![
" Send ".into(), " Send ".into(),
"<S>".blue().bold(), "<S>".blue().bold(),
" Receive ".into(), " Receive ".into(),
"<R>".blue().bold(), "<R>".blue().bold(),
" Discover ".into(), " Logs ".into(),
"<D>".blue().bold(), "<L>".blue().bold(),
" Quit ".into(), " Quit ".into(),
"<Q> ".blue().bold(), "<Q> ".blue().bold(),
]); ]);
@ -256,29 +289,13 @@ impl Widget for &App {
.title_bottom(instructions.centered()) .title_bottom(instructions.centered())
.border_set(border::THICK); .border_set(border::THICK);
let current_screen = format!( let current_screen = format!("{screen:?}",);
"{:?}",
self.screen.last().copied().unwrap_or(CurrentScreen::Main)
);
let text = Text::from(Line::from(current_screen.yellow())); let text = Text::from(Line::from(current_screen.yellow()));
Paragraph::new(text) Paragraph::new(text)
.centered() .centered()
.block(block) .block(block)
.render(area, buf); .render(area, buf);
}
let mode = self.screen.last().unwrap();
match mode {
CurrentScreen::Main => {
let peers = PeersWidget { peers: &self.peers };
peers.render(footer_right.inner(Margin::new(1, 1)), buf);
NetworkInfoWidget.render(footer_left.inner(Margin::new(1, 1)), buf);
logger.render(header_right.inner(Margin::new(1, 2)), buf);
}
CurrentScreen::Receiving => {}
_ => {}
}
}
} }
async fn shutdown(handles: &mut JoinSet<Listeners>) { async fn shutdown(handles: &mut JoinSet<Listeners>) {