134 lines
4.8 KiB
Rust
134 lines
4.8 KiB
Rust
//! One preparation step from parsed arguments to a runnable managed setup.
|
|
//!
|
|
//! Both client applets accept the same target and pacing arguments and then
|
|
//! have to turn them into the same three things: a validated target set, one
|
|
//! shared [`ClientConfig`] template, and a [`ManagedPacing`]. Doing that
|
|
//! separately in each applet is how the CLI ended up deriving its client
|
|
//! configuration from an arbitrary "primary" target whose address the managed
|
|
//! driver immediately replaced per target.
|
|
|
|
use std::time::Duration;
|
|
|
|
use irtt_client::{
|
|
managed::{ManagedClientConfig, ManagedCompletionPolicy, ManagedPacing},
|
|
ClientConfig,
|
|
};
|
|
|
|
use super::{
|
|
args::CommonClientArgs,
|
|
targets::{target_specs, GroupPacingArg, TargetArg, TargetPreparation},
|
|
PreparedTarget,
|
|
};
|
|
|
|
/// Capacity of the lossy managed presentation event channel.
|
|
pub const MANAGED_EVENT_CAPACITY: usize = 16_384;
|
|
pub const STDIN_MAX_DESIRED_TARGETS: usize = 128;
|
|
pub const STDIN_MAX_LIVE_TARGET_GENERATIONS: usize = 256;
|
|
pub const STDIN_OUTCOME_HISTORY_LIMIT: usize = 256;
|
|
|
|
/// Target and pacing arguments common to the client applets.
|
|
///
|
|
/// Duration is deliberately absent: the applets disagree about what a duration
|
|
/// means and what its default is, so each keeps its own.
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct TargetSelection<'a> {
|
|
pub targets: &'a [TargetArg],
|
|
pub pacing: GroupPacingArg,
|
|
pub stdin_controlled: bool,
|
|
}
|
|
|
|
/// Everything a managed run needs, prepared and validated together.
|
|
#[derive(Debug, Clone)]
|
|
pub struct ManagedRunSetup {
|
|
/// Validated targets, in the order the user gave them.
|
|
pub targets: Vec<PreparedTarget>,
|
|
/// Shared client configuration template.
|
|
///
|
|
/// The managed driver supplies each target's address and authentication
|
|
/// from its [`ManagedTargetConfig`](irtt_client::managed::ManagedTargetConfig),
|
|
/// so this template carries no target of its own.
|
|
pub client: ClientConfig,
|
|
/// Send coordination across active targets.
|
|
pub pacing: ManagedPacing,
|
|
/// Whether this stream may replace its desired set from stdin.
|
|
pub stdin_controlled: bool,
|
|
/// Preparation policy and family selections for later stdin declarations.
|
|
pub preparation: TargetPreparation,
|
|
}
|
|
|
|
impl ManagedRunSetup {
|
|
/// Number of validated targets.
|
|
pub fn target_count(&self) -> usize {
|
|
self.targets.len()
|
|
}
|
|
|
|
/// Whether this run drives more than one target.
|
|
pub fn is_multi_target(&self) -> bool {
|
|
self.targets.len() > 1
|
|
}
|
|
|
|
/// Managed target configurations, in argument order.
|
|
pub fn managed_targets(&self) -> Vec<irtt_client::managed::ManagedTargetConfig> {
|
|
self.targets
|
|
.iter()
|
|
.map(|target| target.managed.clone())
|
|
.collect()
|
|
}
|
|
|
|
/// Managed driver configuration for this run.
|
|
pub fn managed_config(&self) -> ManagedClientConfig {
|
|
let target_count = self.target_count();
|
|
let mut config = ManagedClientConfig {
|
|
client: self.client.clone(),
|
|
pacing: self.pacing,
|
|
completion: ManagedCompletionPolicy::FinishWhenQuiescent,
|
|
event_capacity: MANAGED_EVENT_CAPACITY,
|
|
outcome_history_limit: target_count,
|
|
max_live_target_generations: target_count,
|
|
..ManagedClientConfig::default()
|
|
};
|
|
if self.stdin_controlled {
|
|
config.completion = ManagedCompletionPolicy::ExplicitStop;
|
|
config.outcome_history_limit = STDIN_OUTCOME_HISTORY_LIMIT;
|
|
config.max_live_target_generations = STDIN_MAX_LIVE_TARGET_GENERATIONS;
|
|
}
|
|
config
|
|
}
|
|
}
|
|
|
|
/// Validate the selected targets and build the shared run setup.
|
|
///
|
|
/// Targets are validated before any configuration is built, so a bad target set
|
|
/// fails before the caller can act on a half-prepared run.
|
|
pub async fn prepare_managed_run(
|
|
common: &CommonClientArgs,
|
|
duration: Duration,
|
|
selection: TargetSelection<'_>,
|
|
) -> Result<ManagedRunSetup, String> {
|
|
let specs = if selection.stdin_controlled {
|
|
if selection.targets.len() > STDIN_MAX_DESIRED_TARGETS {
|
|
return Err(format!(
|
|
"initial target set exceeds the {STDIN_MAX_DESIRED_TARGETS}-target limit"
|
|
));
|
|
}
|
|
super::targets::target_specs_with_empty(selection.targets, true)?
|
|
} else {
|
|
target_specs(selection.targets)?
|
|
};
|
|
let (targets, preparation) = TargetPreparation::new(common.address_family(), common.dual_stack)
|
|
.prepare(
|
|
specs,
|
|
selection
|
|
.stdin_controlled
|
|
.then_some(STDIN_MAX_DESIRED_TARGETS),
|
|
)
|
|
.await?;
|
|
Ok(ManagedRunSetup {
|
|
targets,
|
|
client: common.to_client_config(duration),
|
|
pacing: selection.pacing.into(),
|
|
stdin_controlled: selection.stdin_controlled,
|
|
preparation,
|
|
})
|
|
}
|