From 00dcf6d3f86d42b73ad1dd1717993ca79a2df50d Mon Sep 17 00:00:00 2001 From: Parker TenBroeck <51721964+ParkerTenBroeck@users.noreply.github.com> Date: Wed, 11 Mar 2026 13:23:28 -0400 Subject: [PATCH] added cli options --- relay.nix | 21 ++++++++++ relay/src/local.rs | 8 ++-- relay/src/main.rs | 95 +++++++++++++++++++++++++++++++++++++++++++-- relay/src/remote.rs | 6 +-- 4 files changed, 119 insertions(+), 11 deletions(-) create mode 100644 relay.nix diff --git a/relay.nix b/relay.nix new file mode 100644 index 0000000..6d42a82 --- /dev/null +++ b/relay.nix @@ -0,0 +1,21 @@ +{ pkgs ? import {} }: + +pkgs.rustPlatform.buildRustPackage { + pname = "relay"; + version = "0.1.0"; + src = ./.; + + cargoLock = { + lockFile = ./Cargo.lock; + }; + + cargoBuildFlags = [ "-p" "relay" ]; + + nativeBuildInputs = [ pkgs.makeWrapper ]; + buildInputs = [ pkgs.ghdl-llvm ]; + + postFixup = '' + wrapProgram $out/bin/relay \ + --prefix PATH : ${pkgs.lib.makeBinPath [ pkgs.ghdl-llvm ]} + ''; +} diff --git a/relay/src/local.rs b/relay/src/local.rs index 5311190..f5950cd 100644 --- a/relay/src/local.rs +++ b/relay/src/local.rs @@ -37,7 +37,7 @@ struct Handler { impl Handler { - fn local(socket: WebSocket, build: PathBuf, src: PathBuf) -> Self { + fn local(socket: WebSocket, build: PathBuf, src: PathBuf, refresh_time: Duration) -> Self { let (sender, receiver) = socket.split(); Self { sender, @@ -45,7 +45,7 @@ impl Handler { build_dir: build, src_dir: src, process: None, - refresh_time: Duration::from_millis(30), + refresh_time, } } @@ -207,6 +207,6 @@ impl Handler { } } -pub async fn ws_handler(socket: WebSocket) { - Handler::local(socket, "../target".into(), "../src".into()).run().await; +pub async fn ws_handler(socket: WebSocket, refresh_time: Duration) { + Handler::local(socket, "../target".into(), "../src".into(), refresh_time).run().await; } diff --git a/relay/src/main.rs b/relay/src/main.rs index 6173288..7ccb5ec 100644 --- a/relay/src/main.rs +++ b/relay/src/main.rs @@ -6,7 +6,10 @@ use axum::{ routing::get, }; use serde::{Deserialize, Serialize}; -use std::net::SocketAddr; +use std::{ + net::{IpAddr, SocketAddr}, + time::Duration, +}; pub mod build; pub mod run; @@ -39,8 +42,73 @@ async fn not_found() -> impl IntoResponse { (StatusCode::NOT_FOUND, "not found") } +#[derive(Clone, Copy, Debug)] +struct Config { + ip: IpAddr, + port: u16, + update_ms: u64, +} + +impl Default for Config { + fn default() -> Self { + Self { + ip: IpAddr::from([127, 0, 0, 1]), + port: 8080, + update_ms: 30, + } + } +} + +fn parse_config_from_args() -> Result { + let mut cfg = Config::default(); + let mut args = std::env::args().skip(1); + + while let Some(arg) = args.next() { + match arg.as_str() { + "--" => break, + "--ip" => { + let value = args.next().ok_or("missing value for --ip")?; + cfg.ip = value + .parse::() + .map_err(|err| format!("invalid --ip `{value}`: {err}"))?; + } + "--port" => { + let value = args.next().ok_or("missing value for --port")?; + cfg.port = value + .parse::() + .map_err(|err| format!("invalid --port `{value}`: {err}"))?; + } + "--update-ms" => { + let value = args.next().ok_or("missing value for --update-ms")?; + cfg.update_ms = value + .parse::() + .map_err(|err| format!("invalid --update-ms `{value}`: {err}"))?; + } + "--help" | "-h" => { + return Err("usage: relay [--ip ] [--port ] [--update-ms ]".into()); + } + _ => { + return Err(format!( + "unknown argument `{arg}`\nusage: relay [--ip ] [--port ] [--update-ms ]" + )); + } + } + } + + Ok(cfg) +} + #[tokio::main] async fn main() { + let cfg = match parse_config_from_args() { + Ok(cfg) => cfg, + Err(msg) => { + eprintln!("{msg}"); + std::process::exit(2); + } + }; + + let update_interval = Duration::from_millis(cfg.update_ms); let app = Router::new() .route("/", get(serve_index)) .route("/index.html", get(serve_index)) @@ -48,15 +116,34 @@ async fn main() { .route("/app.js", get(serve_app_js)) .route( "/ws/remote", - get(|ws: WebSocketUpgrade| async move { ws.on_upgrade(local::ws_handler) }), + get(move |ws: WebSocketUpgrade| { + let update_interval = update_interval; + async move { + ws.on_upgrade(move |socket| remote::ws_handler(socket, update_interval)) + } + }), ) .route( "/ws/local", - get(|ws: WebSocketUpgrade| async move { ws.on_upgrade(remote::ws_handler) }), + get(move |ws: WebSocketUpgrade| { + let update_interval = update_interval; + async move { + ws.on_upgrade(move |socket| local::ws_handler(socket, update_interval)) + } + }), + ) + .route( + "/ws", + get(move |ws: WebSocketUpgrade| { + let update_interval = update_interval; + async move { + ws.on_upgrade(move |socket| remote::ws_handler(socket, update_interval)) + } + }), ) .fallback(get(not_found)); - let addr = SocketAddr::from(([127, 0, 0, 1], 8080)); + let addr = SocketAddr::new(cfg.ip, cfg.port); println!("Open UI: http://{}/", addr); axum::serve(tokio::net::TcpListener::bind(addr).await.unwrap(), app) diff --git a/relay/src/remote.rs b/relay/src/remote.rs index 14efff2..4d12871 100644 --- a/relay/src/remote.rs +++ b/relay/src/remote.rs @@ -11,7 +11,7 @@ use tokio::{ use crate::{ClientMsg, HResult, ServerMsg, build, run}; -pub async fn ws_handler(socket: WebSocket) { +pub async fn ws_handler(socket: WebSocket, refresh_time: Duration) { let (mut sender, mut receiver) = socket.split(); let files = if let Some(Ok(Message::Text(msg))) = receiver.next().await @@ -113,7 +113,7 @@ pub async fn ws_handler(socket: WebSocket) { } _ = tokio::time::sleep_until(print_deadline) => { use tokio::io::AsyncWriteExt; - print_deadline += Duration::from_millis(30); + print_deadline += refresh_time; process.stdin.write_all("\n".as_bytes()).await?; } } @@ -127,4 +127,4 @@ pub async fn ws_handler(socket: WebSocket) { _ = sender.send(Message::Text(format!("{err}").into())).await; }, } -} \ No newline at end of file +}