From 8e18dc47140f527a88436d4c21e774e66af33a74 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 14 Feb 2026 00:32:19 +0700 Subject: [PATCH] refactor: consolidate crates Crates continued to grow in number, but most are still quite small and feature specific. This refactor consolidates them. --- Cargo.lock | 40 +----- Cargo.toml | 2 +- Dockerfile | 2 +- crates/{wasm-actor => bin-runner}/Cargo.toml | 3 +- .../{wasm-actor => bin-runner}/src/actor.rs | 0 .../{wasm-actor => bin-runner}/src/builder.rs | 0 .../{wasm-actor => bin-runner}/src/engine.rs | 0 .../{wasm-actor => bin-runner}/src/error.rs | 0 crates/{wasm-actor => bin-runner}/src/lib.rs | 0 .../tests/guests/double/Cargo.lock | 0 .../tests/guests/double/Cargo.toml | 0 .../tests/guests/double/src/lib.rs | 0 .../tests/guests/echo/Cargo.lock | 0 .../tests/guests/echo/Cargo.toml | 0 .../tests/guests/echo/src/lib.rs | 0 .../tests/guests/silent/Cargo.lock | 0 .../tests/guests/silent/Cargo.toml | 0 .../tests/guests/silent/src/lib.rs | 0 .../tests/wasm_actor.proptest-regressions | 8 ++ .../tests/wasm_actor.rs | 3 +- crates/command/Cargo.toml | 9 -- crates/node/Cargo.toml | 15 --- crates/runtime-dashboard/Cargo.toml | 12 +- .../src/bin/swactor-node.rs} | 1 + crates/runtime-dashboard/src/collector.rs | 2 +- .../src/command}/builtins.rs | 2 +- .../src/command/mod.rs} | 0 .../src/command}/parse.rs | 2 +- crates/runtime-dashboard/src/investigate.rs | 8 +- crates/runtime-dashboard/src/lib.rs | 1 + crates/runtime-dashboard/src/server.rs | 12 +- .../tests/command_api.rs | 8 +- .../runtime-dashboard/tests/dashboard_core.rs | 7 + crates/simulation-dashboard/Cargo.toml | 11 -- crates/simulation-dashboard/README.md | 126 ------------------ crates/simulation/Cargo.toml | 11 ++ .../examples/configs/chain_8.toml | 0 .../examples/configs/full_mesh_6.toml | 0 .../configs/partitioned_800_heal.toml | 0 .../examples/configs/partitioned_8_heal.toml | 0 .../examples/configs/ring_10.toml | 0 .../examples/configs/star_7.toml | 0 .../examples/generate_traces.rs | 6 +- .../examples/replay.rs | 2 +- .../src/dashboard}/config.rs | 4 +- .../src/dashboard}/dashboard_html.rs | 0 .../src/dashboard/mod.rs} | 2 +- .../src/dashboard}/server.rs | 2 +- crates/simulation/src/lib.rs | 3 + crates/wasm/src/lib.rs | 2 +- .../bin-runner/WASM_ACTOR.md | 20 +-- {crates => examples}/dp-mnist/README.md | 0 {crates => examples}/dp-mnist/aggregator.py | 0 {crates => examples}/dp-mnist/pyproject.toml | 2 +- {crates => examples}/dp-mnist/run_training.py | 0 {crates => examples}/dp-mnist/uv.lock | 0 {crates => examples}/dp-mnist/worker.py | 0 scripts/sim-dashboard.sh | 2 +- 58 files changed, 89 insertions(+), 241 deletions(-) rename crates/{wasm-actor => bin-runner}/Cargo.toml (76%) rename crates/{wasm-actor => bin-runner}/src/actor.rs (100%) rename crates/{wasm-actor => bin-runner}/src/builder.rs (100%) rename crates/{wasm-actor => bin-runner}/src/engine.rs (100%) rename crates/{wasm-actor => bin-runner}/src/error.rs (100%) rename crates/{wasm-actor => bin-runner}/src/lib.rs (100%) rename crates/{wasm-actor => bin-runner}/tests/guests/double/Cargo.lock (100%) rename crates/{wasm-actor => bin-runner}/tests/guests/double/Cargo.toml (100%) rename crates/{wasm-actor => bin-runner}/tests/guests/double/src/lib.rs (100%) rename crates/{wasm-actor => bin-runner}/tests/guests/echo/Cargo.lock (100%) rename crates/{wasm-actor => bin-runner}/tests/guests/echo/Cargo.toml (100%) rename crates/{wasm-actor => bin-runner}/tests/guests/echo/src/lib.rs (100%) rename crates/{wasm-actor => bin-runner}/tests/guests/silent/Cargo.lock (100%) rename crates/{wasm-actor => bin-runner}/tests/guests/silent/Cargo.toml (100%) rename crates/{wasm-actor => bin-runner}/tests/guests/silent/src/lib.rs (100%) create mode 100644 crates/bin-runner/tests/wasm_actor.proptest-regressions rename crates/{wasm-actor => bin-runner}/tests/wasm_actor.rs (99%) delete mode 100644 crates/command/Cargo.toml delete mode 100644 crates/node/Cargo.toml rename crates/{node/src/main.rs => runtime-dashboard/src/bin/swactor-node.rs} (99%) rename crates/{command/src => runtime-dashboard/src/command}/builtins.rs (99%) rename crates/{command/src/lib.rs => runtime-dashboard/src/command/mod.rs} (100%) rename crates/{command/src => runtime-dashboard/src/command}/parse.rs (99%) rename crates/{command => runtime-dashboard}/tests/command_api.rs (98%) delete mode 100644 crates/simulation-dashboard/Cargo.toml delete mode 100644 crates/simulation-dashboard/README.md rename crates/{simulation-dashboard => simulation}/examples/configs/chain_8.toml (100%) rename crates/{simulation-dashboard => simulation}/examples/configs/full_mesh_6.toml (100%) rename crates/{simulation-dashboard => simulation}/examples/configs/partitioned_800_heal.toml (100%) rename crates/{simulation-dashboard => simulation}/examples/configs/partitioned_8_heal.toml (100%) rename crates/{simulation-dashboard => simulation}/examples/configs/ring_10.toml (100%) rename crates/{simulation-dashboard => simulation}/examples/configs/star_7.toml (100%) rename crates/{simulation-dashboard => simulation}/examples/generate_traces.rs (92%) rename crates/{simulation-dashboard => simulation}/examples/replay.rs (87%) rename crates/{simulation-dashboard/src => simulation/src/dashboard}/config.rs (95%) rename crates/{simulation-dashboard/src => simulation/src/dashboard}/dashboard_html.rs (100%) rename crates/{simulation-dashboard/src/lib.rs => simulation/src/dashboard/mod.rs} (92%) rename crates/{simulation-dashboard/src => simulation/src/dashboard}/server.rs (99%) rename {crates => examples}/dp-mnist/README.md (100%) rename {crates => examples}/dp-mnist/aggregator.py (100%) rename {crates => examples}/dp-mnist/pyproject.toml (80%) rename {crates => examples}/dp-mnist/run_training.py (100%) rename {crates => examples}/dp-mnist/uv.lock (100%) rename {crates => examples}/dp-mnist/worker.py (100%) diff --git a/Cargo.lock b/Cargo.lock index cedde91..52da10d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1668,17 +1668,6 @@ dependencies = [ "libc", ] -[[package]] -name = "node" -version = "0.1.0" -dependencies = [ - "clap", - "ctrlc", - "distribution", - "runtime-dashboard", - "swactor", -] - [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -2294,6 +2283,7 @@ dependencies = [ name = "runtime-dashboard" version = "0.1.0" dependencies = [ + "clap", "crossbeam-queue", "crossterm", "ctrlc", @@ -2302,7 +2292,6 @@ dependencies = [ "serde", "serde_json", "swactor", - "swactor-command", "tiny_http", "tracing", "tracing-subscriber", @@ -2610,15 +2599,6 @@ dependencies = [ "serde_json", "simulation", "swactor", -] - -[[package]] -name = "simulation-dashboard" -version = "0.1.0" -dependencies = [ - "serde", - "serde_json", - "simulation", "tiny_http", "toml", ] @@ -2727,12 +2707,14 @@ dependencies = [ ] [[package]] -name = "swactor-command" +name = "swactor-bin-runner" version = "0.1.0" dependencies = [ - "serde", - "serde_json", + "proptest", "swactor", + "swactor-std", + "wasmtime", + "wat", ] [[package]] @@ -2743,16 +2725,6 @@ dependencies = [ "swactor", ] -[[package]] -name = "swactor-wasm-actor" -version = "0.1.0" -dependencies = [ - "proptest", - "swactor", - "wasmtime", - "wat", -] - [[package]] name = "syn" version = "2.0.115" diff --git a/Cargo.toml b/Cargo.toml index 2634ddc..876270b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = [".", "crates/python", "crates/wasm", "crates/wasm-actor", "crates/simulation", "crates/runtime-dashboard", "crates/distribution", "crates/simulation-dashboard", "crates/std", "crates/command", "crates/node", "tests/docker"] +members = [".", "crates/python", "crates/wasm", "crates/bin-runner", "crates/simulation", "crates/runtime-dashboard", "crates/distribution", "crates/std", "tests/docker"] exclude = ["tools/depgraph"] [package] diff --git a/Dockerfile b/Dockerfile index 74b67af..0e95fb8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM rust:1.93-slim AS builder WORKDIR /build COPY . . -RUN cargo build --release -p node +RUN cargo build --release -p runtime-dashboard --features node FROM debian:bookworm-slim COPY --from=builder /build/target/release/swactor-node /usr/local/bin/ diff --git a/crates/wasm-actor/Cargo.toml b/crates/bin-runner/Cargo.toml similarity index 76% rename from crates/wasm-actor/Cargo.toml rename to crates/bin-runner/Cargo.toml index 4245a9b..d7891dd 100644 --- a/crates/wasm-actor/Cargo.toml +++ b/crates/bin-runner/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "swactor-wasm-actor" +name = "swactor-bin-runner" version = "0.1.0" edition = "2024" @@ -9,5 +9,6 @@ wasmtime = "29" [dev-dependencies] swactor = { path = "../..", features = ["getrandom"] } +swactor-std = { path = "../std" } wat = "1" proptest = "1" diff --git a/crates/wasm-actor/src/actor.rs b/crates/bin-runner/src/actor.rs similarity index 100% rename from crates/wasm-actor/src/actor.rs rename to crates/bin-runner/src/actor.rs diff --git a/crates/wasm-actor/src/builder.rs b/crates/bin-runner/src/builder.rs similarity index 100% rename from crates/wasm-actor/src/builder.rs rename to crates/bin-runner/src/builder.rs diff --git a/crates/wasm-actor/src/engine.rs b/crates/bin-runner/src/engine.rs similarity index 100% rename from crates/wasm-actor/src/engine.rs rename to crates/bin-runner/src/engine.rs diff --git a/crates/wasm-actor/src/error.rs b/crates/bin-runner/src/error.rs similarity index 100% rename from crates/wasm-actor/src/error.rs rename to crates/bin-runner/src/error.rs diff --git a/crates/wasm-actor/src/lib.rs b/crates/bin-runner/src/lib.rs similarity index 100% rename from crates/wasm-actor/src/lib.rs rename to crates/bin-runner/src/lib.rs diff --git a/crates/wasm-actor/tests/guests/double/Cargo.lock b/crates/bin-runner/tests/guests/double/Cargo.lock similarity index 100% rename from crates/wasm-actor/tests/guests/double/Cargo.lock rename to crates/bin-runner/tests/guests/double/Cargo.lock diff --git a/crates/wasm-actor/tests/guests/double/Cargo.toml b/crates/bin-runner/tests/guests/double/Cargo.toml similarity index 100% rename from crates/wasm-actor/tests/guests/double/Cargo.toml rename to crates/bin-runner/tests/guests/double/Cargo.toml diff --git a/crates/wasm-actor/tests/guests/double/src/lib.rs b/crates/bin-runner/tests/guests/double/src/lib.rs similarity index 100% rename from crates/wasm-actor/tests/guests/double/src/lib.rs rename to crates/bin-runner/tests/guests/double/src/lib.rs diff --git a/crates/wasm-actor/tests/guests/echo/Cargo.lock b/crates/bin-runner/tests/guests/echo/Cargo.lock similarity index 100% rename from crates/wasm-actor/tests/guests/echo/Cargo.lock rename to crates/bin-runner/tests/guests/echo/Cargo.lock diff --git a/crates/wasm-actor/tests/guests/echo/Cargo.toml b/crates/bin-runner/tests/guests/echo/Cargo.toml similarity index 100% rename from crates/wasm-actor/tests/guests/echo/Cargo.toml rename to crates/bin-runner/tests/guests/echo/Cargo.toml diff --git a/crates/wasm-actor/tests/guests/echo/src/lib.rs b/crates/bin-runner/tests/guests/echo/src/lib.rs similarity index 100% rename from crates/wasm-actor/tests/guests/echo/src/lib.rs rename to crates/bin-runner/tests/guests/echo/src/lib.rs diff --git a/crates/wasm-actor/tests/guests/silent/Cargo.lock b/crates/bin-runner/tests/guests/silent/Cargo.lock similarity index 100% rename from crates/wasm-actor/tests/guests/silent/Cargo.lock rename to crates/bin-runner/tests/guests/silent/Cargo.lock diff --git a/crates/wasm-actor/tests/guests/silent/Cargo.toml b/crates/bin-runner/tests/guests/silent/Cargo.toml similarity index 100% rename from crates/wasm-actor/tests/guests/silent/Cargo.toml rename to crates/bin-runner/tests/guests/silent/Cargo.toml diff --git a/crates/wasm-actor/tests/guests/silent/src/lib.rs b/crates/bin-runner/tests/guests/silent/src/lib.rs similarity index 100% rename from crates/wasm-actor/tests/guests/silent/src/lib.rs rename to crates/bin-runner/tests/guests/silent/src/lib.rs diff --git a/crates/bin-runner/tests/wasm_actor.proptest-regressions b/crates/bin-runner/tests/wasm_actor.proptest-regressions new file mode 100644 index 0000000..8a4ef8c --- /dev/null +++ b/crates/bin-runner/tests/wasm_actor.proptest-regressions @@ -0,0 +1,8 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc f8674b306ba8187ad75bcc5a33c4a679e497a0053dc6fdb2234ccaeaae8f85b7 # shrinks to guest_idx = 0, n_msgs = 0, ticks_before = 1, ticks_after = 1 +cc db98a9c0726c0477ba56ec6098a1f21518faaff4551d90e915790ce3c890dd53 # shrinks to payload = [] diff --git a/crates/wasm-actor/tests/wasm_actor.rs b/crates/bin-runner/tests/wasm_actor.rs similarity index 99% rename from crates/wasm-actor/tests/wasm_actor.rs rename to crates/bin-runner/tests/wasm_actor.rs index 866c1d1..717df9e 100644 --- a/crates/wasm-actor/tests/wasm_actor.rs +++ b/crates/bin-runner/tests/wasm_actor.rs @@ -1,6 +1,7 @@ use swactor::actor::{ActorAddress, ActorInterface}; use swactor::runtime::{Ctx, Runtime, RuntimeConfig}; -use swactor_wasm_actor::{ByteMessage, SharedEngine, WasmActor, WasmActorBuilder, WasmActorError}; +use swactor_bin_runner::{ByteMessage, SharedEngine, WasmActor, WasmActorBuilder, WasmActorError}; +use swactor_std::CtxWatching; use proptest::prelude::*; diff --git a/crates/command/Cargo.toml b/crates/command/Cargo.toml deleted file mode 100644 index d4f80fa..0000000 --- a/crates/command/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "swactor-command" -version = "0.1.0" -edition = "2024" - -[dependencies] -swactor = { path = "../..", features = ["serde"] } -serde = { version = "1", features = ["derive"] } -serde_json = "1" diff --git a/crates/node/Cargo.toml b/crates/node/Cargo.toml deleted file mode 100644 index 1968909..0000000 --- a/crates/node/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "node" -version = "0.1.0" -edition = "2024" - -[[bin]] -name = "swactor-node" -path = "src/main.rs" - -[dependencies] -swactor = { path = "../..", features = ["serde", "tracing", "transport"] } -distribution = { path = "../distribution" } -runtime-dashboard = { path = "../runtime-dashboard", features = ["distribution"] } -clap = { version = "4", features = ["derive"] } -ctrlc = "3" diff --git a/crates/runtime-dashboard/Cargo.toml b/crates/runtime-dashboard/Cargo.toml index 1894aa7..3f71d56 100644 --- a/crates/runtime-dashboard/Cargo.toml +++ b/crates/runtime-dashboard/Cargo.toml @@ -14,17 +14,21 @@ crossbeam-queue = "0.3.12" ratatui = { version = "0.29", optional = true, default-features = false, features = ["crossterm"] } crossterm = { version = "0.28", optional = true } distribution = { path = "../distribution", optional = true } -swactor-command = { path = "../command" } - -[dependencies.ctrlc] -version = "3" +clap = { version = "4", features = ["derive"], optional = true } +ctrlc = "3" [features] default = ["distribution"] tui = ["dep:ratatui", "dep:crossterm"] distribution = ["dep:distribution"] +node = ["distribution", "dep:clap", "swactor/transport"] [[bin]] name = "swactor-tui" path = "src/bin/tui.rs" required-features = ["tui"] + +[[bin]] +name = "swactor-node" +path = "src/bin/swactor-node.rs" +required-features = ["node"] diff --git a/crates/node/src/main.rs b/crates/runtime-dashboard/src/bin/swactor-node.rs similarity index 99% rename from crates/node/src/main.rs rename to crates/runtime-dashboard/src/bin/swactor-node.rs index 84d763b..50e0300 100644 --- a/crates/node/src/main.rs +++ b/crates/runtime-dashboard/src/bin/swactor-node.rs @@ -116,6 +116,7 @@ fn main() { swim: swim_config, cache_capacity: 1000, republish_interval: 500, + ..Default::default() }; let mut driver = NodeDriver::new(node_config).expect("failed to create node driver"); diff --git a/crates/runtime-dashboard/src/collector.rs b/crates/runtime-dashboard/src/collector.rs index 145032b..47837c3 100644 --- a/crates/runtime-dashboard/src/collector.rs +++ b/crates/runtime-dashboard/src/collector.rs @@ -42,7 +42,7 @@ impl StatsCollector { } } -impl swactor_command::StatsEnricher for StatsCollector { +impl crate::command::StatsEnricher for StatsCollector { fn enrich(&self, stats: &mut swactor::stats::RuntimeStats) { stats.actor_details = self.actor_details(); } diff --git a/crates/command/src/builtins.rs b/crates/runtime-dashboard/src/command/builtins.rs similarity index 99% rename from crates/command/src/builtins.rs rename to crates/runtime-dashboard/src/command/builtins.rs index 42a06ac..30f09c5 100644 --- a/crates/command/src/builtins.rs +++ b/crates/runtime-dashboard/src/command/builtins.rs @@ -8,7 +8,7 @@ use std::time::{Duration, Instant}; use swactor::actor::ActorAddress; use swactor::stats::TickTiming; -use crate::{CommandContext, CommandHandler, CommandMeta, CommandResponse}; +use super::{CommandContext, CommandHandler, CommandMeta, CommandResponse}; // ─── Arg helpers ───────────────────────────────────────────────────────────── diff --git a/crates/command/src/lib.rs b/crates/runtime-dashboard/src/command/mod.rs similarity index 100% rename from crates/command/src/lib.rs rename to crates/runtime-dashboard/src/command/mod.rs diff --git a/crates/command/src/parse.rs b/crates/runtime-dashboard/src/command/parse.rs similarity index 99% rename from crates/command/src/parse.rs rename to crates/runtime-dashboard/src/command/parse.rs index 7703da5..4809bde 100644 --- a/crates/command/src/parse.rs +++ b/crates/runtime-dashboard/src/command/parse.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; -use crate::CommandRequest; +use super::CommandRequest; /// Parse a REPL text line into a [`CommandRequest`]. /// diff --git a/crates/runtime-dashboard/src/investigate.rs b/crates/runtime-dashboard/src/investigate.rs index cd81995..446b872 100644 --- a/crates/runtime-dashboard/src/investigate.rs +++ b/crates/runtime-dashboard/src/investigate.rs @@ -1,6 +1,6 @@ //! Line-oriented diagnostic protocol for LLM-driven runtime investigation. //! -//! Delegates all command logic to the `swactor-command` crate. +//! Delegates all command logic to the `command` module. //! //! Send text commands on stdin, receive JSON responses on stdout (one per line). //! All human-readable diagnostics go to stderr. @@ -23,7 +23,7 @@ use std::io::{self, BufRead, Write}; use std::sync::Arc; use swactor::runtime::Runtime; -use swactor_command::{CommandContext, CommandRouter}; +use crate::command::{CommandContext, CommandRouter}; use crate::collector::StatsCollector; @@ -47,7 +47,7 @@ pub fn run_investigate(runtime: Arc, collector: Arc) -> break; } - let req = swactor_command::parse_line(line); + let req = crate::command::parse_line(line); let resp = router.dispatch(&req, &ctx); stdout.write_all(resp.to_json_line().as_bytes())?; @@ -66,6 +66,6 @@ pub fn dispatch_command( router: &CommandRouter, ctx: &CommandContext, ) -> String { - let req = swactor_command::from_query_params(params); + let req = crate::command::from_query_params(params); router.dispatch(&req, ctx).to_json_line() } diff --git a/crates/runtime-dashboard/src/lib.rs b/crates/runtime-dashboard/src/lib.rs index ac7a1c1..08cbd73 100644 --- a/crates/runtime-dashboard/src/lib.rs +++ b/crates/runtime-dashboard/src/lib.rs @@ -1,4 +1,5 @@ pub mod collector; +pub mod command; pub mod history; pub mod investigate; pub mod layer; diff --git a/crates/runtime-dashboard/src/server.rs b/crates/runtime-dashboard/src/server.rs index a37796e..ee9bba5 100644 --- a/crates/runtime-dashboard/src/server.rs +++ b/crates/runtime-dashboard/src/server.rs @@ -132,7 +132,7 @@ pub(crate) fn spawn_http_server( let addr = format!("0.0.0.0:{port}"); let server = tiny_http::Server::http(&addr).expect("failed to bind HTTP server"); let server = Arc::new(server); - let cmd_router = Arc::new(swactor_command::CommandRouter::with_builtins()); + let cmd_router = Arc::new(crate::command::CommandRouter::with_builtins()); for _ in 0..4 { let server = Arc::clone(&server); @@ -362,7 +362,7 @@ fn handle_investigate_api( url: &str, runtime: Arc>>>, collector: Arc>>>, - cmd_router: Arc, + cmd_router: Arc, ) { let params = parse_query_string(url); @@ -371,13 +371,13 @@ fn handle_investigate_api( let json = match (maybe_rt, maybe_col) { (Some(rt), Some(col)) => { - let ctx = swactor_command::CommandContext::with_enricher(rt, col); - let req = swactor_command::from_query_params(¶ms); + let ctx = crate::command::CommandContext::with_enricher(rt, col); + let req = crate::command::from_query_params(¶ms); cmd_router.dispatch(&req, &ctx).to_json_line() } (Some(rt), None) => { - let ctx = swactor_command::CommandContext::new(rt); - let req = swactor_command::from_query_params(¶ms); + let ctx = crate::command::CommandContext::new(rt); + let req = crate::command::from_query_params(¶ms); cmd_router.dispatch(&req, &ctx).to_json_line() } _ => { diff --git a/crates/command/tests/command_api.rs b/crates/runtime-dashboard/tests/command_api.rs similarity index 98% rename from crates/command/tests/command_api.rs rename to crates/runtime-dashboard/tests/command_api.rs index 4e6e33d..620c266 100644 --- a/crates/command/tests/command_api.rs +++ b/crates/runtime-dashboard/tests/command_api.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use swactor::actor::ActorInterface; use swactor::runtime::{Ctx, Runtime, RuntimeConfig}; -use swactor_command::{ +use runtime_dashboard::command::{ from_query_params, parse_line, CommandContext, CommandRequest, CommandResponse, CommandRouter, }; @@ -310,9 +310,9 @@ fn from_query_params_defaults_to_help() { #[test] fn custom_command_handler() { struct PingCommand; - impl swactor_command::CommandHandler for PingCommand { - fn meta(&self) -> swactor_command::CommandMeta { - swactor_command::CommandMeta { + impl runtime_dashboard::command::CommandHandler for PingCommand { + fn meta(&self) -> runtime_dashboard::command::CommandMeta { + runtime_dashboard::command::CommandMeta { name: "ping", description: "Respond with pong", usage: "ping", diff --git a/crates/runtime-dashboard/tests/dashboard_core.rs b/crates/runtime-dashboard/tests/dashboard_core.rs index 4e36344..8bfe6c4 100644 --- a/crates/runtime-dashboard/tests/dashboard_core.rs +++ b/crates/runtime-dashboard/tests/dashboard_core.rs @@ -13,6 +13,7 @@ fn make_event(message: &str) -> DashboardEvent { level: "INFO".into(), message: message.into(), worker_id: None, + actor_addr: None, fields: serde_json::Map::new(), } } @@ -181,6 +182,7 @@ fn three_workers_report_independently_merged_view_is_complete() { last_msg_type: Some("Ping"), messages_processed: 100, poisoned: false, + message_type_counts: vec![], }]); // Worker 1 reports 1 actor @@ -190,6 +192,7 @@ fn three_workers_report_independently_merged_view_is_complete() { last_msg_type: None, messages_processed: 50, poisoned: false, + message_type_counts: vec![], }]); // Worker 2 reports 1 actor (poisoned) @@ -199,6 +202,7 @@ fn three_workers_report_independently_merged_view_is_complete() { last_msg_type: Some("BadMsg"), messages_processed: 10, poisoned: true, + message_type_counts: vec![], }]); // Dashboard reads merged view @@ -228,6 +232,7 @@ fn worker_update_replaces_stale_snapshot() { last_msg_type: None, messages_processed: 10, poisoned: false, + message_type_counts: vec![], }]); assert_eq!(collector.actor_details().len(), 1); @@ -240,6 +245,7 @@ fn worker_update_replaces_stale_snapshot() { last_msg_type: Some("Update"), messages_processed: 25, poisoned: false, + message_type_counts: vec![], }]); let details = collector.actor_details(); @@ -261,6 +267,7 @@ fn worker_reports_empty_after_all_actors_stop() { last_msg_type: None, messages_processed: 5, poisoned: false, + message_type_counts: vec![], }]); assert_eq!(collector.actor_details().len(), 1); diff --git a/crates/simulation-dashboard/Cargo.toml b/crates/simulation-dashboard/Cargo.toml deleted file mode 100644 index 7609a4b..0000000 --- a/crates/simulation-dashboard/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "simulation-dashboard" -version = "0.1.0" -edition = "2024" - -[dependencies] -simulation = { path = "../simulation", features = ["gossip"] } -serde = { version = "1", features = ["derive"] } -serde_json = "1" -tiny_http = "0.12" -toml = "0.8" diff --git a/crates/simulation-dashboard/README.md b/crates/simulation-dashboard/README.md deleted file mode 100644 index a6b9cd5..0000000 --- a/crates/simulation-dashboard/README.md +++ /dev/null @@ -1,126 +0,0 @@ -# gossip-dashboard - -Interactive web dashboard for visualizing gossip protocol simulations. - -The workflow has two steps: - -1. **Generate traces** -- run simulations against TOML config files, producing `.trace.json` files. -2. **Replay traces** -- start the dashboard server, point it at a directory of traces, and explore them in the browser. - -## Quick start - -```bash -# 1. Generate traces from the bundled configs (outputs to traces/) -cargo run -p gossip-dashboard --example generate_traces - -# 2. Launch the dashboard -cargo run -p gossip-dashboard --example replay -- traces -# => open http://localhost:8080 -``` - -## Commands - -### `generate_traces` - -Runs gossip simulations and writes `.trace.json` files. - -``` -generate_traces # all bundled configs -> traces/ -generate_traces # all bundled configs -> / -generate_traces [more.toml …] # specific configs -> / -``` - -Bundled configs live in `examples/configs/`. When no config paths are given, every `.toml` in that directory is run. - -Output filenames are derived from the simulation name (lowercased, spaces to underscores). Example output: - -``` -traces/ - ring_10_nodes.trace.json - star_7_nodes.trace.json - chain_8_nodes.trace.json - full_mesh_6_nodes.trace.json - partition_&_heal_8_nodes.trace.json -``` - -### `replay` - -Starts an HTTP server that serves the dashboard UI and the trace data. - -``` -replay [port] -``` - -| Argument | Required | Default | Description | -|-------------|----------|---------|------------------------------------------| -| `trace-dir` | yes | -- | Directory containing `.trace.json` files | -| `port` | no | 8080 | Port to bind on | - -The server exposes three endpoints: - -| Route | Description | -|--------------------------|------------------------------------| -| `GET /` | Dashboard HTML | -| `GET /traces` | JSON list of available trace files | -| `GET /trace.json?file=…` | Fetch a specific trace | - -## Configuration (TOML) - -Each simulation is defined by a TOML file. Example (`ring_10.toml`): - -```toml -name = "Ring (10 nodes)" -topology = "ring" -num_nodes = 10 -num_rounds = 15 -ticks_per_round = 5 -num_threads = 1 - -[initial_data] -color = "blue" -version = "1" -status = "active" -``` - -### Fields - -| Field | Type | Required | Description | -|--------------------|-------------------|----------|-------------------------------------------------------------------| -| `name` | string | yes | Display name for the simulation | -| `topology` | string | yes | Network topology (see below) | -| `num_nodes` | integer | yes | Number of gossip nodes | -| `num_rounds` | integer | yes | Number of gossip rounds to run | -| `ticks_per_round` | integer | yes | Simulation ticks per round | -| `num_threads` | integer | yes | Worker threads (`1` = deterministic single-threaded) | -| `heal_after_round` | integer | no | Round after which partitioned halves are bridged | -| `initial_data` | table of strings | no | Key-value pairs seeded on node 0 before gossip begins | - -### Topologies - -| Value | Shape | -|---------------|--------------------------------------------------------------------------| -| `ring` | Each node connects to the next, forming a circle | -| `star` | Node 0 is a hub with bidirectional links to every other node | -| `full_mesh` | Every node connects bidirectionally to every other node | -| `chain` | Unidirectional chain: node 0 -> 1 -> 2 -> ... -> N-1 | -| `partitioned` | Two isolated full-mesh halves; use `heal_after_round` to bridge them | - -## Bundled configs - -| File | Topology | Nodes | Rounds | Notes | -|---------------------------|-------------|-------|--------|----------------------------| -| `ring_10.toml` | ring | 10 | 15 | | -| `star_7.toml` | star | 7 | 10 | | -| `full_mesh_6.toml` | full_mesh | 6 | 8 | | -| `chain_8.toml` | chain | 8 | 20 | | -| `partitioned_8_heal.toml` | partitioned | 8 | 20 | Heals after round 10 | - -## Dashboard UI - -Once a trace is loaded in the browser: - -- **Graph canvas** -- nodes arranged in a circle then refined with force-directed layout. Nodes and edges flash as events are replayed. -- **Stats panel** -- total nodes, edges, messages, current round. -- **Worker logs** -- per-thread activity feed. -- **Event table** -- full event log with columns: Seq, Round, Thread, Node, Event, Details. -- **Playback controls** -- First / Prev / Play / Pause / Next / Last, timeline slider, speed adjustment (10 ms -- 2000 ms per event). diff --git a/crates/simulation/Cargo.toml b/crates/simulation/Cargo.toml index 616a380..93c8b35 100644 --- a/crates/simulation/Cargo.toml +++ b/crates/simulation/Cargo.toml @@ -6,6 +6,7 @@ edition = "2024" [features] default = [] gossip = ["dep:log"] +dashboard = ["gossip", "dep:tiny_http", "dep:toml"] [dependencies] distribution = { path = "../distribution" } @@ -14,6 +15,8 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" getrandom = "0.2" log = { version = "0.4", optional = true } +tiny_http = { version = "0.12", optional = true } +toml = { version = "0.8", optional = true } [dev-dependencies] simulation = { path = ".", features = ["gossip"] } @@ -21,3 +24,11 @@ simulation = { path = ".", features = ["gossip"] } [[example]] name = "gossip_sim" required-features = ["gossip"] + +[[example]] +name = "replay" +required-features = ["dashboard"] + +[[example]] +name = "generate_traces" +required-features = ["dashboard"] diff --git a/crates/simulation-dashboard/examples/configs/chain_8.toml b/crates/simulation/examples/configs/chain_8.toml similarity index 100% rename from crates/simulation-dashboard/examples/configs/chain_8.toml rename to crates/simulation/examples/configs/chain_8.toml diff --git a/crates/simulation-dashboard/examples/configs/full_mesh_6.toml b/crates/simulation/examples/configs/full_mesh_6.toml similarity index 100% rename from crates/simulation-dashboard/examples/configs/full_mesh_6.toml rename to crates/simulation/examples/configs/full_mesh_6.toml diff --git a/crates/simulation-dashboard/examples/configs/partitioned_800_heal.toml b/crates/simulation/examples/configs/partitioned_800_heal.toml similarity index 100% rename from crates/simulation-dashboard/examples/configs/partitioned_800_heal.toml rename to crates/simulation/examples/configs/partitioned_800_heal.toml diff --git a/crates/simulation-dashboard/examples/configs/partitioned_8_heal.toml b/crates/simulation/examples/configs/partitioned_8_heal.toml similarity index 100% rename from crates/simulation-dashboard/examples/configs/partitioned_8_heal.toml rename to crates/simulation/examples/configs/partitioned_8_heal.toml diff --git a/crates/simulation-dashboard/examples/configs/ring_10.toml b/crates/simulation/examples/configs/ring_10.toml similarity index 100% rename from crates/simulation-dashboard/examples/configs/ring_10.toml rename to crates/simulation/examples/configs/ring_10.toml diff --git a/crates/simulation-dashboard/examples/configs/star_7.toml b/crates/simulation/examples/configs/star_7.toml similarity index 100% rename from crates/simulation-dashboard/examples/configs/star_7.toml rename to crates/simulation/examples/configs/star_7.toml diff --git a/crates/simulation-dashboard/examples/generate_traces.rs b/crates/simulation/examples/generate_traces.rs similarity index 92% rename from crates/simulation-dashboard/examples/generate_traces.rs rename to crates/simulation/examples/generate_traces.rs index 5b1b653..277eb6d 100644 --- a/crates/simulation-dashboard/examples/generate_traces.rs +++ b/crates/simulation/examples/generate_traces.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; -use simulation_dashboard::config::SimFileConfig; -use simulation_dashboard::save_trace; +use simulation::dashboard::config::SimFileConfig; +use simulation::dashboard::save_trace; use simulation::gossip::sim::run_simulation; const CONFIGS_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/configs"); @@ -54,7 +54,7 @@ fn main() { trace.events.len() ); } - eprintln!("Done. View with: cargo run -p simulation-dashboard --example replay -- {out_dir}"); + eprintln!("Done. View with: cargo run -p simulation --features dashboard --example replay -- {out_dir}"); } fn collect_configs(dir: &str) -> Vec { diff --git a/crates/simulation-dashboard/examples/replay.rs b/crates/simulation/examples/replay.rs similarity index 87% rename from crates/simulation-dashboard/examples/replay.rs rename to crates/simulation/examples/replay.rs index 0537c66..c974793 100644 --- a/crates/simulation-dashboard/examples/replay.rs +++ b/crates/simulation/examples/replay.rs @@ -1,4 +1,4 @@ -use simulation_dashboard::serve_dashboard; +use simulation::dashboard::serve_dashboard; fn main() { let args: Vec = std::env::args().collect(); diff --git a/crates/simulation-dashboard/src/config.rs b/crates/simulation/src/dashboard/config.rs similarity index 95% rename from crates/simulation-dashboard/src/config.rs rename to crates/simulation/src/dashboard/config.rs index 1d8dc63..9bb3673 100644 --- a/crates/simulation-dashboard/src/config.rs +++ b/crates/simulation/src/dashboard/config.rs @@ -3,8 +3,8 @@ use std::fs; use std::io; use serde::Deserialize; -use simulation::gossip::sim::GossipSimConfig; -use simulation::topology::Topology; +use crate::gossip::sim::GossipSimConfig; +use crate::topology::Topology; #[derive(Deserialize)] pub struct SimFileConfig { diff --git a/crates/simulation-dashboard/src/dashboard_html.rs b/crates/simulation/src/dashboard/dashboard_html.rs similarity index 100% rename from crates/simulation-dashboard/src/dashboard_html.rs rename to crates/simulation/src/dashboard/dashboard_html.rs diff --git a/crates/simulation-dashboard/src/lib.rs b/crates/simulation/src/dashboard/mod.rs similarity index 92% rename from crates/simulation-dashboard/src/lib.rs rename to crates/simulation/src/dashboard/mod.rs index e6391b3..53c8a10 100644 --- a/crates/simulation-dashboard/src/lib.rs +++ b/crates/simulation/src/dashboard/mod.rs @@ -7,7 +7,7 @@ pub use server::serve_dashboard; use std::fs; use std::io; -use simulation::gossip::trace::SimulationTrace; +use crate::gossip::trace::SimulationTrace; pub fn save_trace(trace: &SimulationTrace, path: &str) -> io::Result<()> { let json = serde_json::to_string_pretty(trace) diff --git a/crates/simulation-dashboard/src/server.rs b/crates/simulation/src/dashboard/server.rs similarity index 99% rename from crates/simulation-dashboard/src/server.rs rename to crates/simulation/src/dashboard/server.rs index 06b39ae..b2d6d50 100644 --- a/crates/simulation-dashboard/src/server.rs +++ b/crates/simulation/src/dashboard/server.rs @@ -3,7 +3,7 @@ use std::path::{Path, PathBuf}; use serde::Serialize; -use crate::dashboard_html::DASHBOARD_HTML; +use super::dashboard_html::DASHBOARD_HTML; // ── Trace directory scanning ────────────────────────────────────────── diff --git a/crates/simulation/src/lib.rs b/crates/simulation/src/lib.rs index 179afb6..fcb4c4d 100644 --- a/crates/simulation/src/lib.rs +++ b/crates/simulation/src/lib.rs @@ -6,3 +6,6 @@ pub mod distribution; #[cfg(feature = "gossip")] pub mod gossip; + +#[cfg(feature = "dashboard")] +pub mod dashboard; diff --git a/crates/wasm/src/lib.rs b/crates/wasm/src/lib.rs index 36fcf4f..1268b49 100644 --- a/crates/wasm/src/lib.rs +++ b/crates/wasm/src/lib.rs @@ -4,7 +4,7 @@ use wasm_bindgen::prelude::*; use swactor::actor::{ActorAddress, ActorExited, ActorInterface}; use swactor::runtime::{Ctx, Inbox, Runtime, RuntimeConfig}; -use swactor_std::{CtxGroups, RuntimeNaming, RuntimeGroups, StdExtension}; +use swactor_std::{CtxGroups, CtxWatching, RuntimeNaming, RuntimeGroups, StdExtension}; // ─── Core JS-facing types ─────────────────────────────────────────────────── diff --git a/docs/development_history/bin-runner/WASM_ACTOR.md b/docs/development_history/bin-runner/WASM_ACTOR.md index 3d2cf68..9294b97 100644 --- a/docs/development_history/bin-runner/WASM_ACTOR.md +++ b/docs/development_history/bin-runner/WASM_ACTOR.md @@ -1,6 +1,6 @@ # Wasm Actor Crate — Development History -> Adds a new crate (`crates/wasm-actor/`) that runs WebAssembly guest code +> Adds a new crate (`crates/bin-runner/`) that runs WebAssembly guest code > **inside** a swactor actor. The Wasm instance lives in the actor — not as a > separate OS process. Messages arrive as bytes, get written into Wasm linear > memory, and the guest's `handle` export is called. @@ -30,7 +30,7 @@ Swactor already supported running *inside* a browser via `crates/wasm/` plugins, multi-language actors, and capability-restricted compute. The main swactor crate has no wasmtime dependency — all Wasm machinery is -isolated in `crates/wasm-actor/`. +isolated in `crates/bin-runner/`. --- @@ -38,14 +38,14 @@ isolated in `crates/wasm-actor/`. | Component | Location | Purpose | |-----------|----------|---------| -| `swactor-wasm-actor` crate | `crates/wasm-actor/` | Host-side: engine, builder, actor impl | -| 3 guest crates | `crates/wasm-actor/tests/guests/{echo,double,silent}/` | `#![no_std]` Wasm modules for testing | -| Integration tests | `crates/wasm-actor/tests/wasm_actor.rs` | 7 behavioral tests | +| `swactor-bin-runner` crate | `crates/bin-runner/` | Host-side: engine, builder, actor impl | +| 3 guest crates | `crates/bin-runner/tests/guests/{echo,double,silent}/` | `#![no_std]` Wasm modules for testing | +| Integration tests | `crates/bin-runner/tests/wasm_actor.rs` | 7 behavioral tests | ### Crate modules ``` -crates/wasm-actor/src/ +crates/bin-runner/src/ lib.rs — ByteMessage, re-exports engine.rs — SharedEngine (Arc) builder.rs — WasmActorBuilder (compile + link + instantiate) @@ -138,9 +138,9 @@ This allows guests to send replies without hardcoding addresses. ```bash rustup target add wasm32-unknown-unknown # one-time -cd crates/wasm-actor/tests/guests/echo && cargo build --target wasm32-unknown-unknown --release -cd crates/wasm-actor/tests/guests/double && cargo build --target wasm32-unknown-unknown --release -cd crates/wasm-actor/tests/guests/silent && cargo build --target wasm32-unknown-unknown --release +cd crates/bin-runner/tests/guests/echo && cargo build --target wasm32-unknown-unknown --release +cd crates/bin-runner/tests/guests/double && cargo build --target wasm32-unknown-unknown --release +cd crates/bin-runner/tests/guests/silent && cargo build --target wasm32-unknown-unknown --release ``` Each guest crate has its own `[workspace]` marker to stay independent of the @@ -178,7 +178,7 @@ root workspace. ## 8. Test Coverage Summary -7 behavioral tests in `crates/wasm-actor/tests/wasm_actor.rs`: +7 behavioral tests in `crates/bin-runner/tests/wasm_actor.rs`: | Test | Scenario | |------|----------| diff --git a/crates/dp-mnist/README.md b/examples/dp-mnist/README.md similarity index 100% rename from crates/dp-mnist/README.md rename to examples/dp-mnist/README.md diff --git a/crates/dp-mnist/aggregator.py b/examples/dp-mnist/aggregator.py similarity index 100% rename from crates/dp-mnist/aggregator.py rename to examples/dp-mnist/aggregator.py diff --git a/crates/dp-mnist/pyproject.toml b/examples/dp-mnist/pyproject.toml similarity index 80% rename from crates/dp-mnist/pyproject.toml rename to examples/dp-mnist/pyproject.toml index f7f21c5..be9f8fc 100644 --- a/crates/dp-mnist/pyproject.toml +++ b/examples/dp-mnist/pyproject.toml @@ -10,7 +10,7 @@ dependencies = [ ] [tool.uv.sources] -swactor = { path = "../python", editable = true } +swactor = { path = "../../crates/python", editable = true } [[tool.uv.index]] name = "pytorch-cpu" diff --git a/crates/dp-mnist/run_training.py b/examples/dp-mnist/run_training.py similarity index 100% rename from crates/dp-mnist/run_training.py rename to examples/dp-mnist/run_training.py diff --git a/crates/dp-mnist/uv.lock b/examples/dp-mnist/uv.lock similarity index 100% rename from crates/dp-mnist/uv.lock rename to examples/dp-mnist/uv.lock diff --git a/crates/dp-mnist/worker.py b/examples/dp-mnist/worker.py similarity index 100% rename from crates/dp-mnist/worker.py rename to examples/dp-mnist/worker.py diff --git a/scripts/sim-dashboard.sh b/scripts/sim-dashboard.sh index a062a9f..41f981a 100755 --- a/scripts/sim-dashboard.sh +++ b/scripts/sim-dashboard.sh @@ -16,4 +16,4 @@ SWACTOR_TRACE_DIR="$DIR" cargo test -p simulation \ COUNT=$(find "$DIR" -name '*.trace.json' 2>/dev/null | wc -l) echo "$COUNT traces in $DIR/" echo "Dashboard at http://localhost:$PORT" -cargo run -p simulation-dashboard --example replay -- "$DIR" "$PORT" +cargo run -p simulation --features dashboard --example replay -- "$DIR" "$PORT" -- 2.45.2