Starting to build a UI

This commit is contained in:
John Doty 2022-10-10 02:51:43 +00:00
parent e50d4ba943
commit 119af02dfa
4 changed files with 133 additions and 33 deletions

47
Cargo.lock generated
View file

@ -95,6 +95,31 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "crossterm"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
dependencies = [
"bitflags",
"crossterm_winapi",
"libc",
"mio",
"parking_lot",
"signal-hook",
"signal-hook-mio",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.2.8" version = "0.2.8"
@ -132,6 +157,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
"crossterm",
"procfs", "procfs",
"thiserror", "thiserror",
"tokio", "tokio",
@ -370,6 +396,27 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "signal-hook"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-mio"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
dependencies = [
"libc",
"mio",
"signal-hook",
]
[[package]] [[package]]
name = "signal-hook-registry" name = "signal-hook-registry"
version = "1.4.0" version = "1.4.0"

View file

@ -10,6 +10,7 @@ anyhow = "1.0"
bytes = "1" bytes = "1"
thiserror = "1.0" thiserror = "1.0"
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
crossterm = "0.25"
[target.'cfg(target_os="linux")'.dependencies] [target.'cfg(target_os="linux")'.dependencies]
procfs = "0.14.1" procfs = "0.14.1"

View file

@ -12,6 +12,7 @@ use tokio::sync::oneshot;
mod connection; mod connection;
mod message; mod message;
mod refresh; mod refresh;
mod ui;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Write Management // Write Management
@ -60,7 +61,7 @@ async fn server_handle_connection(
let mut writer = writer.clone(); let mut writer = writer.clone();
connection::process(channel, &mut stream, &mut data, &mut writer).await; connection::process(channel, &mut stream, &mut data, &mut writer).await;
eprintln!("< Done server!"); // eprintln!("< Done server!");
} }
} }
} }
@ -70,7 +71,7 @@ async fn server_read<T: AsyncRead + Unpin>(
writer: mpsc::Sender<Message>, writer: mpsc::Sender<Message>,
connections: ConnectionTable, connections: ConnectionTable,
) -> Result<()> { ) -> Result<()> {
eprintln!("< Processing packets..."); // eprintln!("< Processing packets...");
loop { loop {
let message = reader.read().await?; let message = reader.read().await?;
@ -104,14 +105,14 @@ async fn server_read<T: AsyncRead + Unpin>(
tokio::spawn(async move { tokio::spawn(async move {
let ports = match refresh::get_entries() { let ports = match refresh::get_entries() {
Ok(ports) => ports, Ok(ports) => ports,
Err(e) => { Err(_) => {
eprintln!("< Error scanning: {:?}", e); // eprintln!("< Error scanning: {:?}", e);
vec![] vec![]
} }
}; };
if let Err(e) = writer.send(Message::Ports(ports)).await { if let Err(_) = writer.send(Message::Ports(ports)).await {
// Writer has been closed for some reason, we can just quit.... I hope everything is OK? // Writer has been closed for some reason, we can just quit.... I hope everything is OK?
eprintln!("< Warning: Error sending: {:?}", e); // eprintln!("< Warning: Error sending: {:?}", e);
} }
}); });
} }
@ -165,7 +166,7 @@ async fn client_sync<Read: AsyncRead + Unpin, Write: AsyncWrite + Unpin>(
reader: &mut Read, reader: &mut Read,
writer: &mut Write, writer: &mut Write,
) -> Result<(), tokio::io::Error> { ) -> Result<(), tokio::io::Error> {
eprintln!("> Waiting for synchronization marker..."); // eprintln!("> Waiting for synchronization marker...");
// Run these two loops in parallel; the copy of stdin should stop when // Run these two loops in parallel; the copy of stdin should stop when
// we've seen the marker from the client. If the pipe closes for whatever // we've seen the marker from the client. If the pipe closes for whatever
@ -211,9 +212,9 @@ async fn client_handle_connection(
let mut writer = writer.clone(); let mut writer = writer.clone();
connection::process(channel, socket, &mut data, &mut writer).await; connection::process(channel, socket, &mut data, &mut writer).await;
eprintln!("> Done client!"); // eprintln!("> Done client!");
} else { } else {
eprintln!("> Failed to connect to remote"); // eprintln!("> Failed to connect to remote");
} }
} }
} }
@ -242,10 +243,11 @@ async fn client_read<T: AsyncRead + Unpin>(
reader: &mut MessageReader<T>, reader: &mut MessageReader<T>,
writer: mpsc::Sender<Message>, writer: mpsc::Sender<Message>,
connections: ConnectionTable, connections: ConnectionTable,
port_sender: mpsc::Sender<Vec<message::PortDesc>>,
) -> Result<()> { ) -> Result<()> {
let mut listeners: HashMap<u16, oneshot::Sender<()>> = HashMap::new(); let mut listeners: HashMap<u16, oneshot::Sender<()>> = HashMap::new();
eprintln!("> Processing packets..."); // eprintln!("> Processing packets...");
loop { loop {
let message = reader.read().await?; let message = reader.read().await?;
@ -272,11 +274,7 @@ async fn client_read<T: AsyncRead + Unpin>(
} }
Ports(ports) => { Ports(ports) => {
let mut new_listeners = HashMap::new(); let mut new_listeners = HashMap::new();
for port in &ports {
println!("The following ports are available:");
for port in ports {
println!(" {}: {}", port.port, port.desc);
let port = port.port; let port = port.port;
if let Some(l) = listeners.remove(&port) { if let Some(l) = listeners.remove(&port) {
if !l.is_closed() { if !l.is_closed() {
@ -300,14 +298,17 @@ async fn client_read<T: AsyncRead + Unpin>(
r = client_listen(port, writer, connections) => r, r = client_listen(port, writer, connections) => r,
_ = stop => Ok(()), _ = stop => Ok(()),
}; };
if let Err(e) = result { if let Err(_) = result {
eprintln!("> Error listening on port {}: {:?}", port, e); // eprintln!("> Error listening on port {}: {:?}", port, e);
} }
}); });
} }
} }
listeners = new_listeners; listeners = new_listeners;
if let Err(_) = port_sender.send(ports).await {
// TODO: Log
}
} }
_ => panic!("Unsupported: {:?}", message), _ => panic!("Unsupported: {:?}", message),
}; };
@ -328,41 +329,58 @@ async fn client_main<Reader: AsyncRead + Unpin, Writer: AsyncWrite + Unpin>(
} }
// Kick things off with a listing of the ports... // Kick things off with a listing of the ports...
eprintln!("> Sending initial list command..."); // eprintln!("> Sending initial list command...");
writer.write(Message::Refresh).await?; // writer.write(Message::Refresh).await?;
let (port_sender, mut port_receiver) = mpsc::channel(2);
let connections = ConnectionTable::new(); let connections = ConnectionTable::new();
let ui = tokio::spawn(async move { ui::run_ui(&mut port_receiver).await });
// And now really get into it... // And now really get into it...
let (msg_sender, mut msg_receiver) = mpsc::channel(32); let (msg_sender, mut msg_receiver) = mpsc::channel(32);
let refresher = msg_sender.clone(); // Special for loop.
let writing = pump_write(&mut msg_receiver, writer); let writing = pump_write(&mut msg_receiver, writer);
let reading = client_read(reader, msg_sender, connections); let reading = client_read(reader, msg_sender, connections, port_sender);
tokio::pin!(reading); tokio::pin!(reading);
tokio::pin!(writing); tokio::pin!(writing);
let (mut done_writing, mut done_reading) = (false, false); let (mut done_writing, mut done_reading) = (false, false);
loop { while !(done_reading && done_writing) {
tokio::select! { tokio::select! {
result = async {
loop {
use tokio::time::{sleep, Duration};
if let Err(e) = refresher.send(Message::Refresh).await {
break Err::<(), _>(e);
}
sleep(Duration::from_millis(100)).await;
}
}, if !done_writing => {
if let Err(e) = result {
return Err(e.into());
}
},
result = &mut writing, if !done_writing => { result = &mut writing, if !done_writing => {
done_writing = true; done_writing = true;
if let Err(e) = result { if let Err(e) = result {
return Err(e); return Err(e);
} }
if done_reading && done_writing {
return Ok(());
}
}, },
result = &mut reading, if !done_reading => { result = &mut reading, if !done_reading => {
done_reading = true; done_reading = true;
if let Err(e) = result { if let Err(e) = result {
return Err(e); return Err(e);
} }
if done_reading && done_writing {
return Ok(());
}
}, },
} }
} }
if let Err(_) = ui.await {
//TODO
}
Ok(())
} }
///// /////
@ -372,22 +390,22 @@ pub async fn run_server() {
let mut writer = BufWriter::new(tokio::io::stdout()); let mut writer = BufWriter::new(tokio::io::stdout());
// Write the 8-byte synchronization marker. // Write the 8-byte synchronization marker.
eprintln!("< Writing marker..."); // eprintln!("< Writing marker...");
writer writer
.write_u64(0x00_00_00_00_00_00_00_00) .write_u64(0x00_00_00_00_00_00_00_00)
.await .await
.expect("Error writing marker"); .expect("Error writing marker");
if let Err(e) = writer.flush().await { if let Err(_) = writer.flush().await {
eprintln!("Error writing sync marker: {:?}", e); // eprintln!("Error writing sync marker: {:?}", e);
return; return;
} }
eprintln!("< Done!"); // eprintln!("< Done!");
let mut writer = MessageWriter::new(writer); let mut writer = MessageWriter::new(writer);
let mut reader = MessageReader::new(reader); let mut reader = MessageReader::new(reader);
if let Err(e) = server_main(&mut reader, &mut writer).await { if let Err(_) = server_main(&mut reader, &mut writer).await {
eprintln!("Error: {:?}", e); // eprintln!("Error: {:?}", e);
} }
} }

34
src/ui.rs Normal file
View file

@ -0,0 +1,34 @@
use crate::message::PortDesc;
use anyhow::Result;
use crossterm::{
cursor::MoveTo,
execute,
terminal::{
Clear, ClearType, DisableLineWrap, EnableLineWrap, EnterAlternateScreen,
LeaveAlternateScreen,
},
};
use std::io::stdout;
use tokio::sync::mpsc;
pub async fn run_ui(port_receiver: &mut mpsc::Receiver<Vec<PortDesc>>) -> Result<()> {
let mut stdout = stdout();
execute!(stdout, EnterAlternateScreen, DisableLineWrap)?;
while let Some(mut ports) = port_receiver.recv().await {
ports.sort_by(|a, b| a.port.partial_cmp(&b.port).unwrap());
execute!(stdout, Clear(ClearType::All), MoveTo(0, 0))?;
println!("Port Url Description");
println!("----- ------------------------ -----------");
for port in ports {
println!(
"{:5} {:24} {}",
port.port,
format!("http://locahost:{}/", port.port),
port.desc
);
}
}
execute!(stdout, EnableLineWrap, LeaveAlternateScreen)?;
Ok(())
}