add logging screen, clean up widget rendering
This commit is contained in:
parent
1e64c5b1e8
commit
9b2172aa3a
2 changed files with 84 additions and 64 deletions
|
@ -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]);
|
||||||
|
|
|
@ -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,83 +214,90 @@ 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 logger = TuiLoggerWidget::default()
|
|
||||||
.output_separator('|')
|
|
||||||
.output_timestamp(Some("%F %H:%M:%S%.3f".to_string()))
|
|
||||||
.output_level(Some(TuiLoggerLevelOutput::Abbreviated))
|
|
||||||
.output_target(false)
|
|
||||||
.output_file(false)
|
|
||||||
.output_line(false)
|
|
||||||
.block(Block::bordered().border_set(border::THICK))
|
|
||||||
.style(Style::default())
|
|
||||||
.state(&TuiWidgetState::new().set_default_display_level(LevelFilter::Debug));
|
|
||||||
|
|
||||||
{
|
|
||||||
let title = Line::from(" Joecalsend ".bold());
|
|
||||||
let instructions = Line::from(vec![
|
|
||||||
" Send ".into(),
|
|
||||||
"<S>".blue().bold(),
|
|
||||||
" Receive ".into(),
|
|
||||||
"<R>".blue().bold(),
|
|
||||||
" Discover ".into(),
|
|
||||||
"<D>".blue().bold(),
|
|
||||||
" Quit ".into(),
|
|
||||||
"<Q> ".blue().bold(),
|
|
||||||
]);
|
|
||||||
let block = Block::bordered()
|
|
||||||
.title(title.centered())
|
|
||||||
.title_bottom(instructions.centered())
|
|
||||||
.border_set(border::THICK);
|
|
||||||
|
|
||||||
let current_screen = format!(
|
|
||||||
"{:?}",
|
|
||||||
self.screen.last().copied().unwrap_or(CurrentScreen::Main)
|
|
||||||
);
|
|
||||||
let text = Text::from(Line::from(current_screen.yellow()));
|
|
||||||
|
|
||||||
Paragraph::new(text)
|
|
||||||
.centered()
|
|
||||||
.block(block)
|
|
||||||
.render(area, buf);
|
|
||||||
}
|
|
||||||
let mode = self.screen.last().unwrap();
|
let mode = self.screen.last().unwrap();
|
||||||
match mode {
|
match mode {
|
||||||
CurrentScreen::Main => {
|
CurrentScreen::Main => {
|
||||||
|
main_page(*mode, area, buf);
|
||||||
|
logger(header_right.inner(Margin::new(1, 2)), buf);
|
||||||
let peers = PeersWidget { peers: &self.peers };
|
let peers = PeersWidget { peers: &self.peers };
|
||||||
peers.render(footer_right.inner(Margin::new(1, 1)), buf);
|
peers.render(footer_right.inner(Margin::new(1, 1)), buf);
|
||||||
NetworkInfoWidget.render(footer_left.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 => {}
|
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()
|
||||||
|
.output_separator('|')
|
||||||
|
.output_timestamp(Some("%H:%M:%S%.3f".to_string()))
|
||||||
|
.output_level(Some(TuiLoggerLevelOutput::Abbreviated))
|
||||||
|
.output_target(true)
|
||||||
|
.output_file(false)
|
||||||
|
.output_line(false)
|
||||||
|
.block(Block::bordered().border_set(border::THICK))
|
||||||
|
.style(Style::default())
|
||||||
|
.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 instructions = Line::from(vec![
|
||||||
|
" Send ".into(),
|
||||||
|
"<S>".blue().bold(),
|
||||||
|
" Receive ".into(),
|
||||||
|
"<R>".blue().bold(),
|
||||||
|
" Logs ".into(),
|
||||||
|
"<L>".blue().bold(),
|
||||||
|
" Quit ".into(),
|
||||||
|
"<Q> ".blue().bold(),
|
||||||
|
]);
|
||||||
|
let block = Block::bordered()
|
||||||
|
.title(title.centered())
|
||||||
|
.title_bottom(instructions.centered())
|
||||||
|
.border_set(border::THICK);
|
||||||
|
|
||||||
|
let current_screen = format!("{screen:?}",);
|
||||||
|
let text = Text::from(Line::from(current_screen.yellow()));
|
||||||
|
|
||||||
|
Paragraph::new(text)
|
||||||
|
.centered()
|
||||||
|
.block(block)
|
||||||
|
.render(area, buf);
|
||||||
|
}
|
||||||
|
|
||||||
async fn shutdown(handles: &mut JoinSet<Listeners>) {
|
async fn shutdown(handles: &mut JoinSet<Listeners>) {
|
||||||
let mut alarm = tokio::time::interval(tokio::time::Duration::from_secs(5));
|
let mut alarm = tokio::time::interval(tokio::time::Duration::from_secs(5));
|
||||||
alarm.tick().await;
|
alarm.tick().await;
|
||||||
|
|
Loading…
Reference in a new issue