From 9c7dc45e8db8ba590daae8b2696e6087f6e795de Mon Sep 17 00:00:00 2001 From: Reboot-Codes Date: Fri, 22 May 2026 11:25:36 -0700 Subject: [PATCH] Setup process-compose and begin moving to zenoh. --- .direnv/flake-profile | 2 +- Cargo.lock | 20 +-- Cargo.toml | 3 + clover-hub/Cargo.toml | 4 +- clover-hub/src/lib.rs | 336 ++++++++++++++++++++++++++++++++++++++ clover-hub/src/main.rs | 357 +++-------------------------------------- dev.sh | 1 - flake.nix | 51 ++++-- process-compose.yaml | 17 ++ todo.md | 3 +- 10 files changed, 429 insertions(+), 365 deletions(-) create mode 100644 clover-hub/src/lib.rs delete mode 100755 dev.sh create mode 100644 process-compose.yaml diff --git a/.direnv/flake-profile b/.direnv/flake-profile index d91a070..50b5a40 120000 --- a/.direnv/flake-profile +++ b/.direnv/flake-profile @@ -1 +1 @@ -flake-profile-29-link \ No newline at end of file +flake-profile-38-link \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 17df933..966621b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2162,7 +2162,6 @@ dependencies = [ "console-subscriber", "crossterm 0.28.1", "decorum", - "env_logger", "futures", "git2", "i2c", @@ -2191,6 +2190,9 @@ dependencies = [ "tokio-serial", "tokio-stream", "tokio-util", + "tracing", + "tracing-log", + "tracing-subscriber", "tui", "url", "uuid", @@ -8999,9 +9001,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -9011,9 +9013,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", @@ -9022,9 +9024,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -9058,9 +9060,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.20" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "matchers", "nu-ansi-term", diff --git a/Cargo.toml b/Cargo.toml index e5f28ff..75804c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,3 +42,6 @@ sea-orm = { version = "1.1.1", features = [ "runtime-tokio-rustls", "sqlx-sqlite", ] } +tracing = "0.1.44" +tracing-subscriber = "0.3.23" +tracing-log = "0.2.0" diff --git a/clover-hub/Cargo.toml b/clover-hub/Cargo.toml index 11d59c6..c66095f 100644 --- a/clover-hub/Cargo.toml +++ b/clover-hub/Cargo.toml @@ -45,7 +45,9 @@ clap = { version = "4.5.4", features = ["derive"] } # Debugging Tools log = "^0.4.26" -env_logger = "0.11.3" +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +tracing-log = { workspace = true } console-subscriber = "0.5.0" # Utils that we had to write diff --git a/clover-hub/src/lib.rs b/clover-hub/src/lib.rs new file mode 100644 index 0000000..311972f --- /dev/null +++ b/clover-hub/src/lib.rs @@ -0,0 +1,336 @@ +#![feature(stmt_expr_attributes)] +#![feature(ascii_char)] +#![feature(trivial_bounds)] + +pub mod server; +pub mod tui; +pub mod utils; + +use clap::{ + Arg, + Command, +}; +use log::{ + info, + warn, +}; +use std::ffi::OsString; +use std::num::ParseIntError; +use std::process::exit; +use std::sync::Arc; +use std::time::Duration; +use tokio::time; +use tokio_util::sync::CancellationToken; + +use crate::server::server_main; +use crate::tui::tui_main; + +pub struct Empty {} + +pub const DEFAULT_PORT_STR: &str = "6698"; +pub const DEFAULT_PORT: u16 = 6698; + +pub fn cli() -> Command { + Command::new("clover") + .about("Central command and control for the Clover system.") + .subcommand_required(true) + .arg_required_else_help(true) + .allow_external_subcommands(true) + .subcommand( + Command::new("run") + .args_conflicts_with_subcommands(true) + .flatten_help(true) + .args(aio_args()) + .subcommand(Command::new("aio").args(aio_args())) + .subcommand( + Command::new("server") + .arg( + Arg::new("data_dir") + .short('d') + .long("data-dir") + .required(false) + .default_value("/opt/clover") + .help("The data directory to use other than `/opt/clover`"), + ) + .arg(port_arg()), + ) + .subcommand( + Command::new("tui") + .arg( + Arg::new("host") + .short('H') + .long("host") + .required(false) + .default_value("localhost") + .help("The host to connect to other than `localhost`"), + ) + .arg(port_arg()), + ), + ) +} + +pub fn port_arg() -> Arg { + Arg::new("port") + .short('p') + .long("port") + .required(false) + .default_value(DEFAULT_PORT_STR) + .help(format!( + "The port on the host to connect to if not on {}.", + DEFAULT_PORT_STR + )) +} + +pub fn aio_args() -> Vec { + vec![port_arg()] +} + +pub fn unwrap_port_arg(arg: Result) -> u16 { + match arg { + Ok(val) => val, + Err(e) => { + warn!( + "User-provided port did not parse correctly, using default, due to:\n{}", + e + ); + DEFAULT_PORT + } + } +} + +pub fn get_signal_handle( + big_boy_token: CancellationToken, + cancellation_token: CancellationToken, + server_token: Option, +) -> tokio::task::JoinHandle<()> { + tokio::task::spawn(async move { + tokio::select! { + _ = wait_for_signal_impl(server_token.clone()) => { + info!("Shutting down..."); + + cancellation_token.cancel(); + let mut token_long = Default::default(); + + tokio::select! { + _ = wait_for_signal_impl(None) => { + warn!("Forcibly exiting!"); + big_boy_token.cancel(); + }, + _ = cancellation_token.cancelled() => {} + _ = async { + match server_token { + Some(token) => { + token_long = token; + token_long.cancelled().await; + }, + None => { + let mut interval = time::interval(Duration::from_millis(10)); + loop { + interval.tick().await; + } + } + } + } => {} + } + } + } + }) +} + +// taken from https://stackoverflow.com/questions/77585473/rust-tokio-how-to-handle-more-signals-than-just-sigint-i-e-sigquit#77591939 +/// Waits for a signal that requests a graceful shutdown, like SIGTERM or SIGINT. +#[cfg(unix)] +pub async fn wait_for_signal_impl(server_token: Option) { + use log::debug; + use tokio::signal::unix::{ + signal, + SignalKind, + }; + + // Infos here: + // https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html + let mut signal_terminate = signal(SignalKind::terminate()).unwrap(); + let mut signal_interrupt = signal(SignalKind::interrupt()).unwrap(); + let mut token_long = Default::default(); + + tokio::select! { + _ = signal_terminate.recv() => debug!("Received SIGTERM."), + _ = signal_interrupt.recv() => debug!("Received SIGINT."), + _ = async { + match server_token { + Some(token) => { + token_long = token; + token_long.cancelled().await; + }, + None => { + let mut interval = time::interval(Duration::from_millis(10)); + loop { + interval.tick().await; + } + } + } + } => {} + }; +} + +/// Waits for a signal that requests a graceful shutdown, Ctrl-C (SIGINT). +#[cfg(windows)] +pub async fn wait_for_signal_impl() { + use tokio::signal::windows; + + // Infos here: + // https://learn.microsoft.com/en-us/windows/console/handlerroutine + let mut signal_c = windows::ctrl_c().unwrap(); + let mut signal_break = windows::ctrl_break().unwrap(); + let mut signal_close = windows::ctrl_close().unwrap(); + let mut signal_shutdown = windows::ctrl_shutdown().unwrap(); + + tokio::select! { + _ = signal_c.recv() => debug!("Received CTRL_C."), + _ = signal_break.recv() => debug!("Received CTRL_BREAK."), + _ = signal_close.recv() => debug!("Received CTRL_CLOSE."), + _ = signal_shutdown.recv() => debug!("Received CTRL_SHUTDOWN."), + }; +} + +/// Run the primary CloverHub process. +pub async fn run(big_boy_token: CancellationToken) { + let matches = Box::leak(Box::new(cli().get_matches())); + let subcommand = matches.subcommand(); + + match subcommand { + Some(("run", sub_matches)) => { + let run_command = sub_matches.subcommand().unwrap_or(("aio", sub_matches)); + match run_command { + ("aio", sub_matches) => { + info!("Starting CloverHub!"); + let cancellation_token = CancellationToken::new(); + let from_server_token = CancellationToken::new(); + let server_cancellation_token_clone = from_server_token.clone(); + let data_dir = sub_matches + .get_one::("data_dir") + .expect("Default set in Clap."); + let port = unwrap_port_arg( + sub_matches + .get_one::("port") + .expect("Default set in Clap.") + .parse::(), + ); + + info!("Running Backend Server and Terminal UI (All-In-One)..."); + + let server_port = Arc::new(port); + let server_token = cancellation_token.clone(); + let server_handle = tokio::task::spawn(async move { + server_main( + data_dir, + *server_port.to_owned(), + server_token, + from_server_token, + ) + .await; + }); + + let tui_port = Arc::new(port); + let tui_token = cancellation_token.clone(); + let tui_handle = tokio::task::spawn(async move { + let _ = tui_main( + *tui_port.to_owned(), + Ok::("localhost".to_string()).ok(), + tui_token, + ) + .await; + }); + + let signal_handle = get_signal_handle( + big_boy_token.clone(), + cancellation_token, + Some(server_cancellation_token_clone), + ); + + tokio::select! {_ = futures::future::join_all(vec![signal_handle, tui_handle, server_handle]) => { + info!("Exiting..."); + exit(0); + }} + } + ("server", sub_matches) => { + info!("Starting CloverHub!"); + let from_server_token = CancellationToken::new(); + let server_cancellation_token_clone = from_server_token.clone(); + let cancellation_token = CancellationToken::new(); + let data_dir = sub_matches + .get_one::("data_dir") + .expect("Default set in Clap."); + let port = unwrap_port_arg( + sub_matches + .get_one::("port") + .expect("Default provided in Clap.") + .parse::(), + ); + + info!("Running Backend Server..."); + let server_token = cancellation_token.clone(); + let server_handle = tokio::task::spawn(async move { + server_main(data_dir, port, server_token, from_server_token).await; + }); + + let signal_handle = get_signal_handle( + big_boy_token.clone(), + cancellation_token, + Some(server_cancellation_token_clone), + ); + + tokio::select! {_ = futures::future::join_all(vec![signal_handle, server_handle]) => { + info!("Exiting..."); + exit(0); + }} + } + ("tui", sub_matches) => { + info!("Starting CloverHub!"); + let cancellation_token = CancellationToken::new(); + let host = sub_matches + .get_one::("host") + .expect("Default set in Clap."); + let port = unwrap_port_arg( + sub_matches + .get_one::("port") + .expect("Default set in Clap.") + .parse::(), + ); + + info!("Running Terminal UI..."); + let tui_host = Arc::new(host); + let tui_token = cancellation_token.clone(); + let tui_handle = tokio::task::spawn(async move { + tui_main( + port, + Ok::((*tui_host.to_owned()).to_string()).ok(), + tui_token, + ) + .await + .err(); + }); + + let signal_handle = get_signal_handle(big_boy_token.clone(), cancellation_token, None); + + tokio::select! {_ = futures::future::join_all(vec![signal_handle, tui_handle]) => { + info!("Exiting..."); + exit(0); + }} + } + (name, _) => { + unreachable!("Unsupported subcommand `{name}`") + } + } + } + Some((ext, sub_matches)) => { + let args = sub_matches + .get_many::("") + .into_iter() + .flatten() + .collect::>(); + info!("Calling out to {ext:?} with {args:?}"); + } + _ => unreachable!(), // If all subcommands are defined above, anything else is unreachable!() + } +} diff --git a/clover-hub/src/main.rs b/clover-hub/src/main.rs index 28d281c..897161b 100644 --- a/clover-hub/src/main.rs +++ b/clover-hub/src/main.rs @@ -11,352 +11,33 @@ //! Terminal User Interface to manage a clover instance over UART/SSH. //! -#![feature(stmt_expr_attributes)] -#![feature(ascii_char)] -#![feature(trivial_bounds)] - -pub mod server; -pub mod tui; -pub mod utils; - -use clap::{ - Arg, - Command, -}; -use env_logger; -use log::{ - info, - warn, -}; -use std::env; use std::error::Error; -use std::ffi::OsString; -use std::num::ParseIntError; -use std::process::exit; -use std::sync::Arc; -use std::time::Duration; -use tokio::time; use tokio_util::sync::CancellationToken; +use tracing_log::LogTracer; +use tracing_subscriber::{ + prelude::*, + EnvFilter, +}; -use crate::server::server_main; -use crate::tui::tui_main; - -pub struct Empty {} - -pub const DEFAULT_PORT_STR: &str = "6699"; -pub const DEFAULT_PORT: u16 = 6699; - -pub fn cli() -> Command { - Command::new("clover") - .about("Central command and control for the Clover system.") - .subcommand_required(true) - .arg_required_else_help(true) - .allow_external_subcommands(true) - .subcommand( - Command::new("run") - .args_conflicts_with_subcommands(true) - .flatten_help(true) - .args(aio_args()) - .subcommand(Command::new("aio").args(aio_args())) - .subcommand( - Command::new("server") - .arg( - Arg::new("data_dir") - .short('d') - .long("data-dir") - .required(false) - .default_value("/opt/clover") - .help("The data directory to use other than `/opt/clover`"), - ) - .arg(port_arg()), - ) - .subcommand( - Command::new("tui") - .arg( - Arg::new("host") - .short('H') - .long("host") - .required(false) - .default_value("localhost") - .help("The host to connect to other than `localhost`"), - ) - .arg(port_arg()), - ), - ) -} - -pub fn port_arg() -> Arg { - Arg::new("port") - .short('p') - .long("port") - .required(false) - .default_value(DEFAULT_PORT_STR) - .help(format!( - "The port on the host to connect to if not on {}.", - DEFAULT_PORT_STR - )) -} - -pub fn aio_args() -> Vec { - vec![port_arg()] -} - -pub fn unwrap_port_arg(arg: Result) -> u16 { - match arg { - Ok(val) => val, - Err(e) => { - warn!( - "User-provided port did not parse correctly, using default, due to:\n{}", - e - ); - DEFAULT_PORT - } - } -} - -pub fn get_signal_handle( - big_boy_token: CancellationToken, - cancellation_token: CancellationToken, - server_token: Option, -) -> tokio::task::JoinHandle<()> { - tokio::task::spawn(async move { - tokio::select! { - _ = wait_for_signal_impl(server_token.clone()) => { - info!("Shutting down..."); - - cancellation_token.cancel(); - let mut token_long = Default::default(); - - tokio::select! { - _ = wait_for_signal_impl(None) => { - warn!("Forcibly exiting!"); - big_boy_token.cancel(); - }, - _ = cancellation_token.cancelled() => {} - _ = async { - match server_token { - Some(token) => { - token_long = token; - token_long.cancelled().await; - }, - None => { - let mut interval = time::interval(Duration::from_millis(10)); - loop { - interval.tick().await; - } - } - } - } => {} - } - } - } - }) -} - -// taken from https://stackoverflow.com/questions/77585473/rust-tokio-how-to-handle-more-signals-than-just-sigint-i-e-sigquit#77591939 -/// Waits for a signal that requests a graceful shutdown, like SIGTERM or SIGINT. -#[cfg(unix)] -pub async fn wait_for_signal_impl(server_token: Option) { - use log::debug; - use tokio::signal::unix::{ - signal, - SignalKind, - }; - - // Infos here: - // https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html - let mut signal_terminate = signal(SignalKind::terminate()).unwrap(); - let mut signal_interrupt = signal(SignalKind::interrupt()).unwrap(); - let mut token_long = Default::default(); - - tokio::select! { - _ = signal_terminate.recv() => debug!("Received SIGTERM."), - _ = signal_interrupt.recv() => debug!("Received SIGINT."), - _ = async { - match server_token { - Some(token) => { - token_long = token; - token_long.cancelled().await; - }, - None => { - let mut interval = time::interval(Duration::from_millis(10)); - loop { - interval.tick().await; - } - } - } - } => {} - }; -} - -/// Waits for a signal that requests a graceful shutdown, Ctrl-C (SIGINT). -#[cfg(windows)] -pub async fn wait_for_signal_impl() { - use tokio::signal::windows; - - // Infos here: - // https://learn.microsoft.com/en-us/windows/console/handlerroutine - let mut signal_c = windows::ctrl_c().unwrap(); - let mut signal_break = windows::ctrl_break().unwrap(); - let mut signal_close = windows::ctrl_close().unwrap(); - let mut signal_shutdown = windows::ctrl_shutdown().unwrap(); - - tokio::select! { - _ = signal_c.recv() => debug!("Received CTRL_C."), - _ = signal_break.recv() => debug!("Received CTRL_BREAK."), - _ = signal_close.recv() => debug!("Received CTRL_CLOSE."), - _ = signal_shutdown.recv() => debug!("Received CTRL_SHUTDOWN."), - }; -} - -/// Run the primary CloverHub process. -pub async fn run(big_boy_token: CancellationToken) { - let matches = Box::leak(Box::new(cli().get_matches())); - let subcommand = matches.subcommand(); - - match subcommand { - Some(("run", sub_matches)) => { - let run_command = sub_matches.subcommand().unwrap_or(("aio", sub_matches)); - match run_command { - ("aio", sub_matches) => { - info!("Starting CloverHub!"); - let cancellation_token = CancellationToken::new(); - let from_server_token = CancellationToken::new(); - let server_cancellation_token_clone = from_server_token.clone(); - let data_dir = sub_matches - .get_one::("data_dir") - .expect("Default set in Clap."); - let port = unwrap_port_arg( - sub_matches - .get_one::("port") - .expect("Default set in Clap.") - .parse::(), - ); - - info!("Running Backend Server and Terminal UI (All-In-One)..."); - - let server_port = Arc::new(port); - let server_token = cancellation_token.clone(); - let server_handle = tokio::task::spawn(async move { - server_main( - data_dir, - *server_port.to_owned(), - server_token, - from_server_token, - ) - .await; - }); - - let tui_port = Arc::new(port); - let tui_token = cancellation_token.clone(); - let tui_handle = tokio::task::spawn(async move { - let _ = tui_main( - *tui_port.to_owned(), - Ok::("localhost".to_string()).ok(), - tui_token, - ) - .await; - }); - - let signal_handle = get_signal_handle( - big_boy_token.clone(), - cancellation_token, - Some(server_cancellation_token_clone), - ); - - tokio::select! {_ = futures::future::join_all(vec![signal_handle, tui_handle, server_handle]) => { - info!("Exiting..."); - exit(0); - }} - } - ("server", sub_matches) => { - info!("Starting CloverHub!"); - let from_server_token = CancellationToken::new(); - let server_cancellation_token_clone = from_server_token.clone(); - let cancellation_token = CancellationToken::new(); - let data_dir = sub_matches - .get_one::("data_dir") - .expect("Default set in Clap."); - let port = unwrap_port_arg( - sub_matches - .get_one::("port") - .expect("Default provided in Clap.") - .parse::(), - ); - - info!("Running Backend Server..."); - let server_token = cancellation_token.clone(); - let server_handle = tokio::task::spawn(async move { - server_main(data_dir, port, server_token, from_server_token).await; - }); - - let signal_handle = get_signal_handle( - big_boy_token.clone(), - cancellation_token, - Some(server_cancellation_token_clone), - ); +use clover_hub::run; - tokio::select! {_ = futures::future::join_all(vec![signal_handle, server_handle]) => { - info!("Exiting..."); - exit(0); - }} - } - ("tui", sub_matches) => { - info!("Starting CloverHub!"); - let cancellation_token = CancellationToken::new(); - let host = sub_matches - .get_one::("host") - .expect("Default set in Clap."); - let port = unwrap_port_arg( - sub_matches - .get_one::("port") - .expect("Default set in Clap.") - .parse::(), - ); +#[tokio::main] +pub async fn main() -> Result<(), Box> { + LogTracer::init()?; - info!("Running Terminal UI..."); - let tui_host = Arc::new(host); - let tui_token = cancellation_token.clone(); - let tui_handle = tokio::task::spawn(async move { - tui_main( - port, - Ok::((*tui_host.to_owned()).to_string()).ok(), - tui_token, - ) - .await - .err(); - }); + let env_filter = EnvFilter::try_from_env("CLOVER_LOG").unwrap_or_else(|_| EnvFilter::new("info")); + let stdout_layer = tracing_subscriber::fmt::layer(); + // TODO: Send logs to Zenoh log endpoint. + // let zenoh_layer = ZenohLogLayer { session: active_session, host_id: "hub-sbc".into() }; - let signal_handle = get_signal_handle(big_boy_token.clone(), cancellation_token, None); + let subscriber = tracing_subscriber::registry() + .with(env_filter) + .with(stdout_layer); + // .with(zenoh_layer); - tokio::select! {_ = futures::future::join_all(vec![signal_handle, tui_handle]) => { - info!("Exiting..."); - exit(0); - }} - } - (name, _) => { - unreachable!("Unsupported subcommand `{name}`") - } - } - } - Some((ext, sub_matches)) => { - let args = sub_matches - .get_many::("") - .into_iter() - .flatten() - .collect::>(); - info!("Calling out to {ext:?} with {args:?}"); - } - _ => unreachable!(), // If all subcommands are defined above, anything else is unreachable!() - } -} + tracing::subscriber::set_global_default(subscriber) + .expect("Failed to set global tracing subscriber"); -#[tokio::main] -pub async fn main() -> Result<(), Box> { - // TODO: Create a logger that will send logs to a FIFO buffer to send to CarbonSteel clients - env_logger::Builder::new() - .parse_filters(&env::var("CLOVER_LOG").unwrap_or("info".to_string())) - .init(); // Debugging console for tokio // console_subscriber::init(); diff --git a/dev.sh b/dev.sh deleted file mode 100755 index faaefc7..0000000 --- a/dev.sh +++ /dev/null @@ -1 +0,0 @@ -CLOVER_LOG="clover=debug,nexus=debug" CLOVER_SIMULATED_CONTROLS="true" CLOVER_MASTER_PRINT="true" cargo run --bin="clover-hub" run server diff --git a/flake.nix b/flake.nix index 6599895..e498ded 100644 --- a/flake.nix +++ b/flake.nix @@ -130,22 +130,45 @@ ); # nix develop - devShells.default = craneLib.devShell { - inherit buildInputs; + devShells.default = + let + cloverEnv = pkgs.writeShellScriptBin "clover-up" '' + CURRENT_REPO_ROOT=${pkgs.git}/bin/git rev-parse --show-toplevel 2>/dev/null - packages = [ - toolchain - ] - ++ (with pkgs; [ - nodejs_22 - yarn-berry - rust-analyzer - tokio-console - ]) - ++ libraries; + # Fallback to the current working directory if not inside a git repo + if [ -z "$CURRENT_REPO_ROOT" ]; then + CURRENT_REPO_ROOT=$(pwd) + fi - LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath libraries}"; - }; + # Verify the file actually exists before trying to pass it to process-compose + PROCESS_COMPOSE_FILE="$CURRENT_REPO_ROOT/process-compose.yaml" + if [ ! -f "$PROCESS_COMPOSE_FILE" ]; then + echo "Fatal: Could not find process-compose.yaml at root target: $CURRENT_REPO_ROOT" + exit 1 + fi + + exec ${pkgs.process-compose}/bin/process-compose up --no-server -f $PROCESS_COMPOSE_FILE + ''; + in + craneLib.devShell { + inherit buildInputs; + + packages = [ + toolchain + ] + ++ (with pkgs; [ + nodejs_22 + yarn-berry + rust-analyzer + tokio-console + zenoh + process-compose + cloverEnv + ]) + ++ libraries; + + LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath libraries}"; + }; } )); } diff --git a/process-compose.yaml b/process-compose.yaml new file mode 100644 index 0000000..ba3d157 --- /dev/null +++ b/process-compose.yaml @@ -0,0 +1,17 @@ +version: "0.5" + +processes: + zenohd-router: + command: > + zenohd -l tcp/0.0.0.0:6699 --adminspace-permissions rw + availability: + restart: "always" + clover-hub: + command: > + RUST_BACKTRACE=1 CLOVER_LOG="clover=debug,clover-hub-macros=debug,wgpu_hal=error" CLOVER_SIMULATED_CONTROLS="true" CLOVER_MASTER_PRINT="true" cargo run --bin="clover-hub" run server + availability: + restart: "on_failure" + # Wait until the local Zenoh TCP socket is actively listening before booting the hub + depends_on: + zenohd-router: + condition: process_started diff --git a/todo.md b/todo.md index 5b74f90..9b7c25c 100644 --- a/todo.md +++ b/todo.md @@ -4,7 +4,8 @@ - [ ] Server - [ ] Centralize common crates and types - [ ] Move to Tracing - - [ ] add `tracing`, `tracing-subscriber`, `tracing-log` + - [x] add `tracing`, `tracing-subscriber`, `tracing-log` + - [ ] Add file parsing for log rules - [ ] Pass logs to Zenoh - [ ] Move to Snafu - [ ] Move to Zenoh -- 2.51.2