refactor(app): clarify application and binary roles
Rename the application Cargo package from irtt-cli to irtt-rs (crates/irtt-cli -> crates/irtt-app), and hard-rename its scriptable client binary from irtt-cli to irtt-client, now that the application also ships a first-class server and the old name reads as an umbrella CLI for both roles. Give each dedicated binary (irtt-client, irtt-tui, irtt-server) its own entry point instead of funneling through the multicall dispatcher's argv0/subcommand logic, so a dedicated binary only links the applet code for the role it implements and always runs that role regardless of the name it's invoked or copied under. irtt-rs remains the feature-selectable multicall dispatcher and is now the only binary that inspects argv0 or subcommands. Move future application releases to the irtt-rs/vX.Y.Z tag namespace (regenerated via `dist generate`), and bump the application package to 0.6.0 as a breaking distribution change. Library crate versions are unaffected.
This commit is contained in:
49 files changed
+365
-213
No files matched your search
@@ -0,0 +1,85 @@
|
||||
use std::{
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use irtt_server::ServerSet;
|
||||
|
||||
use super::args::ServerArgs;
|
||||
|
||||
/// How often the shutdown future samples the process-wide signal flag.
|
||||
///
|
||||
/// The flag a signal handler sets has no async wake mechanism, so the future
|
||||
/// polls it on a timer rather than spinning. `ServerSet::run` owns everything
|
||||
/// after that future becomes ready, including fanning it out to the listeners.
|
||||
const SHUTDOWN_POLL_INTERVAL: Duration = Duration::from_millis(50);
|
||||
|
||||
/// Runs the configured listeners until the process is asked to shut down.
|
||||
///
|
||||
/// The applet owns exactly one current-thread Tokio runtime and one
|
||||
/// [`ServerSet`], whatever number of addresses was requested. A single `--bind`
|
||||
/// is an ordinary set of one and takes the same path as a set of several: one
|
||||
/// construction, one shutdown future, one supervision rule. Listener
|
||||
/// concurrency is async I/O concurrency and needs no worker threads.
|
||||
pub fn run_server(
|
||||
args: ServerArgs,
|
||||
shutdown_requested: &AtomicBool,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()?;
|
||||
runtime.block_on(serve(args, shutdown_requested))
|
||||
}
|
||||
|
||||
async fn serve(
|
||||
args: ServerArgs,
|
||||
shutdown_requested: &AtomicBool,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let config = args.server_config();
|
||||
let set = ServerSet::bind(args.bind, config).await?;
|
||||
// Only once every listener is up. Announcing one address and then failing
|
||||
// to bind the next would report a service that never started.
|
||||
for addr in set.local_addrs() {
|
||||
eprintln!("irtt-server: listening on {addr}");
|
||||
}
|
||||
set.run(shutdown_signal(shutdown_requested)).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn shutdown_signal(shutdown_requested: &AtomicBool) {
|
||||
while !shutdown_requested.load(Ordering::Relaxed) {
|
||||
tokio::time::sleep(SHUTDOWN_POLL_INTERVAL).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use clap::Parser;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// The ordinary invocation, and the one that keeps the single-listener case
|
||||
/// on the same orchestration path as every other.
|
||||
#[test]
|
||||
fn an_already_requested_shutdown_binds_one_listener_and_returns() {
|
||||
let args = ServerArgs::try_parse_from(["irtt-server", "--bind", "127.0.0.1:0"]).unwrap();
|
||||
let shutdown_requested = AtomicBool::new(true);
|
||||
|
||||
run_server(args, &shutdown_requested).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_already_requested_shutdown_binds_every_listener_and_returns() {
|
||||
let args = ServerArgs::try_parse_from([
|
||||
"irtt-server",
|
||||
"--bind",
|
||||
"127.0.0.1:0",
|
||||
"--bind",
|
||||
"127.0.0.1:0",
|
||||
])
|
||||
.unwrap();
|
||||
let shutdown_requested = AtomicBool::new(true);
|
||||
|
||||
run_server(args, &shutdown_requested).unwrap();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user