Starting to build a UI
This commit is contained in:
parent
e50d4ba943
commit
119af02dfa
4 changed files with 133 additions and 33 deletions
47
Cargo.lock
generated
47
Cargo.lock
generated
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
84
src/lib.rs
84
src/lib.rs
|
|
@ -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
34
src/ui.rs
Normal 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(())
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue