feat: Show errored ports as an error state
This commit is contained in:
parent
6335944591
commit
66da323481
1 changed files with 53 additions and 15 deletions
|
|
@ -10,16 +10,19 @@ use crossterm::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use log::{error, info, Level, Metadata, Record};
|
use log::{error, info, Level, Metadata, Record};
|
||||||
use std::collections::vec_deque::VecDeque;
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::io::stdout;
|
use std::io::stdout;
|
||||||
|
use std::{
|
||||||
|
collections::vec_deque::VecDeque,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
use tui::{
|
use tui::{
|
||||||
backend::{Backend, CrosstermBackend},
|
backend::{Backend, CrosstermBackend},
|
||||||
layout::{Constraint, Direction, Layout, Margin, Rect},
|
layout::{Constraint, Direction, Layout, Margin, Rect},
|
||||||
style::{Color, Style},
|
style::{Color, Modifier, Style},
|
||||||
widgets::{
|
widgets::{
|
||||||
Block, Borders, List, ListItem, ListState, Row, Table, TableState,
|
Block, Borders, List, ListItem, ListState, Row, Table, TableState,
|
||||||
},
|
},
|
||||||
|
|
@ -67,9 +70,22 @@ impl log::Log for Logger {
|
||||||
fn flush(&self) {}
|
fn flush(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum State {
|
||||||
|
Enabled,
|
||||||
|
Broken,
|
||||||
|
Disabled,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
fn boxed(self) -> Arc<Mutex<State>> {
|
||||||
|
Arc::new(Mutex::new(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Listener {
|
struct Listener {
|
||||||
enabled: bool,
|
state: std::sync::Arc<std::sync::Mutex<State>>,
|
||||||
stop: Option<oneshot::Sender<()>>,
|
stop: Option<oneshot::Sender<()>>,
|
||||||
desc: Option<PortDesc>,
|
desc: Option<PortDesc>,
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +96,15 @@ impl Listener {
|
||||||
desc: PortDesc,
|
desc: PortDesc,
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
) -> Listener {
|
) -> Listener {
|
||||||
let mut listener = Listener { enabled, stop: None, desc: Some(desc) };
|
let mut listener = Listener {
|
||||||
|
state: if enabled {
|
||||||
|
State::Enabled.boxed()
|
||||||
|
} else {
|
||||||
|
State::Disabled.boxed()
|
||||||
|
},
|
||||||
|
stop: None,
|
||||||
|
desc: Some(desc),
|
||||||
|
};
|
||||||
if enabled {
|
if enabled {
|
||||||
listener.start(socks_port);
|
listener.start(socks_port);
|
||||||
}
|
}
|
||||||
|
|
@ -88,15 +112,19 @@ impl Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enabled(&self) -> bool {
|
pub fn enabled(&self) -> bool {
|
||||||
self.enabled
|
*self.state.lock().unwrap() == State::Enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state(&self) -> State {
|
||||||
|
*self.state.lock().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_enabled(&mut self, socks_port: Option<u16>, enabled: bool) {
|
pub fn set_enabled(&mut self, socks_port: Option<u16>, enabled: bool) {
|
||||||
if enabled {
|
if enabled {
|
||||||
self.enabled = true;
|
self.state = State::Enabled.boxed();
|
||||||
self.start(socks_port);
|
self.start(socks_port);
|
||||||
} else {
|
} else {
|
||||||
self.enabled = false;
|
self.state = State::Enabled.boxed();
|
||||||
self.stop = None;
|
self.stop = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -112,19 +140,22 @@ impl Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(&mut self, socks_port: Option<u16>) {
|
pub fn start(&mut self, socks_port: Option<u16>) {
|
||||||
if self.enabled {
|
if self.enabled() {
|
||||||
if let (Some(desc), Some(socks_port), None) =
|
if let (Some(desc), Some(socks_port), None) =
|
||||||
(&self.desc, socks_port, &self.stop)
|
(&self.desc, socks_port, &self.stop)
|
||||||
{
|
{
|
||||||
info!("Starting port {port} to {socks_port}", port = desc.port);
|
info!("Starting port {port} to {socks_port}", port = desc.port);
|
||||||
let (l, stop) = oneshot::channel();
|
let (l, stop) = oneshot::channel();
|
||||||
let port = desc.port;
|
let port = desc.port;
|
||||||
|
let state = self.state.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let result = tokio::select! {
|
let result = tokio::select! {
|
||||||
r = client_listen(port, socks_port) => r,
|
r = client_listen(port, socks_port) => r,
|
||||||
_ = stop => Ok(()),
|
_ = stop => Ok(()),
|
||||||
};
|
};
|
||||||
if let Err(e) = result {
|
if let Err(e) = result {
|
||||||
|
let mut sg = state.lock().unwrap();
|
||||||
|
*sg = State::Broken;
|
||||||
error!("Error listening on port {port}: {e:?}");
|
error!("Error listening on port {port}: {e:?}");
|
||||||
} else {
|
} else {
|
||||||
info!("Stopped listening on port {port}");
|
info!("Stopped listening on port {port}");
|
||||||
|
|
@ -243,6 +274,8 @@ impl UI {
|
||||||
fn render_ports<B: Backend>(&mut self, frame: &mut Frame<B>, size: Rect) {
|
fn render_ports<B: Backend>(&mut self, frame: &mut Frame<B>, size: Rect) {
|
||||||
let enabled_port_style = Style::default();
|
let enabled_port_style = Style::default();
|
||||||
let disabled_port_style = Style::default().fg(Color::DarkGray);
|
let disabled_port_style = Style::default().fg(Color::DarkGray);
|
||||||
|
let broken_port_style =
|
||||||
|
Style::default().fg(Color::Red).add_modifier(Modifier::DIM);
|
||||||
|
|
||||||
let mut rows = Vec::new();
|
let mut rows = Vec::new();
|
||||||
let ports = self.get_ui_ports();
|
let ports = self.get_ui_ports();
|
||||||
|
|
@ -250,20 +283,21 @@ impl UI {
|
||||||
ports.iter().map(|p| format!("{p}")).collect();
|
ports.iter().map(|p| format!("{p}")).collect();
|
||||||
for (index, port) in ports.into_iter().enumerate() {
|
for (index, port) in ports.into_iter().enumerate() {
|
||||||
let listener = self.ports.get(&port).unwrap();
|
let listener = self.ports.get(&port).unwrap();
|
||||||
|
let (symbol, style) = match listener.state() {
|
||||||
|
State::Enabled => (" ✓ ", enabled_port_style),
|
||||||
|
State::Broken => (" ✗ ", broken_port_style),
|
||||||
|
State::Disabled => ("", disabled_port_style),
|
||||||
|
};
|
||||||
rows.push(
|
rows.push(
|
||||||
Row::new(vec![
|
Row::new(vec![
|
||||||
if listener.enabled { " ✓ " } else { "" },
|
symbol,
|
||||||
&port_strings[index][..],
|
&port_strings[index][..],
|
||||||
match &listener.desc {
|
match &listener.desc {
|
||||||
Some(port_desc) => &port_desc.desc,
|
Some(port_desc) => &port_desc.desc,
|
||||||
None => "",
|
None => "",
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
.style(if listener.enabled {
|
.style(style),
|
||||||
enabled_port_style
|
|
||||||
} else {
|
|
||||||
disabled_port_style
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -357,7 +391,11 @@ impl UI {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enable_disable_port(&mut self, port: u16) {
|
fn enable_disable_port(&mut self, port: u16) {
|
||||||
if let Some(listener) = self.ports.get_mut(&port) {
|
let state = self.ports.get(&port).map(Listener::state);
|
||||||
|
if state == Some(State::Broken) {
|
||||||
|
// try turning it off and on again, it will at least get logs visible
|
||||||
|
self.ports.remove(&port);
|
||||||
|
} else if let Some(listener) = self.ports.get_mut(&port) {
|
||||||
listener.set_enabled(self.socks_port, !listener.enabled());
|
listener.set_enabled(self.socks_port, !listener.enabled());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue