refactor(cli): use unified managed frontend

This commit is contained in:
Nils Andreas Svee committed 2026-08-09 20:27:22 +07:00
1 parent 9de95b303c
commit 1a9e8f28aa
10 files changed
+470 -1455

No files matched your search

+2 -2
View File
@@ -10,6 +10,6 @@ pub use args::{
pub use config::{expected_probe_count, DEFAULT_RECV_TIMEOUT};
pub use session::is_shutdown_requested;
pub use targets::{
parse_labelled_target, resolved_managed_targets, target_specs, GroupPacingArg,
LabelledTargetArg, ResolvedTarget, TargetSpec,
parse_labelled_target, prepare_managed_targets, target_specs, GroupPacingArg,
LabelledTargetArg, PreparedTarget, TargetSpec,
};
+8 -8
View File
@@ -27,7 +27,7 @@ pub fn peer_close_run_error(
))
}
pub fn request_group_stop_for_peer_close(
pub fn request_managed_stop_for_peer_close(
continuous: bool,
interrupted: bool,
peer_closed_target_count: u64,
@@ -38,10 +38,10 @@ pub fn request_group_stop_for_peer_close(
return false;
}
*peer_close_requested_stop = true;
request_group_stop_once(stop_requested)
request_managed_stop_once(stop_requested)
}
pub fn request_group_stop_once(stop_requested: &mut bool) -> bool {
pub fn request_managed_stop_once(stop_requested: &mut bool) -> bool {
if *stop_requested {
return false;
}
@@ -72,21 +72,21 @@ mod tests {
fn grouped_peer_close_stop_policy_is_run_mode_and_one_shot() {
let mut peer_close_requested_stop = false;
let mut stop_requested = false;
assert!(!request_group_stop_for_peer_close(
assert!(!request_managed_stop_for_peer_close(
false,
false,
1,
&mut peer_close_requested_stop,
&mut stop_requested,
));
assert!(!request_group_stop_for_peer_close(
assert!(!request_managed_stop_for_peer_close(
true,
true,
1,
&mut peer_close_requested_stop,
&mut stop_requested,
));
assert!(!request_group_stop_for_peer_close(
assert!(!request_managed_stop_for_peer_close(
true,
false,
0,
@@ -96,7 +96,7 @@ mod tests {
assert!(!peer_close_requested_stop);
assert!(!stop_requested);
assert!(request_group_stop_for_peer_close(
assert!(request_managed_stop_for_peer_close(
true,
false,
1,
@@ -105,7 +105,7 @@ mod tests {
));
assert!(peer_close_requested_stop);
assert!(stop_requested);
assert!(!request_group_stop_for_peer_close(
assert!(!request_managed_stop_for_peer_close(
true,
false,
1,
+13 -110
View File
@@ -1,7 +1,7 @@
use std::{collections::HashSet, net::ToSocketAddrs};
use std::collections::HashSet;
use clap::ValueEnum;
use irtt_client::{ClientConfig, ManagedGroupPacing, ManagedTargetConfig, TargetId};
use irtt_client::managed::{ManagedPacing, ManagedTargetConfig, TargetId};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LabelledTargetArg {
@@ -16,7 +16,7 @@ pub struct TargetSpec {
}
#[derive(Debug, Clone)]
pub struct ResolvedTarget {
pub struct PreparedTarget {
pub label: String,
pub managed: ManagedTargetConfig,
}
@@ -27,7 +27,7 @@ pub enum GroupPacingArg {
Burst,
}
impl From<GroupPacingArg> for ManagedGroupPacing {
impl From<GroupPacingArg> for ManagedPacing {
fn from(value: GroupPacingArg) -> Self {
match value {
GroupPacingArg::Staggered => Self::Staggered,
@@ -93,118 +93,21 @@ pub fn target_specs(
Ok(specs)
}
pub fn resolved_managed_targets(
specs: Vec<TargetSpec>,
config: &ClientConfig,
) -> Result<Vec<ResolvedTarget>, String> {
let mut remotes = HashSet::new();
pub fn prepare_managed_targets(specs: Vec<TargetSpec>) -> Result<Vec<PreparedTarget>, String> {
let mut targets = Vec::with_capacity(specs.len());
for spec in specs {
let remote = resolve_target(&spec.addr, config).map_err(|err| {
format!(
"failed to resolve target {} ({:?}): {err}",
spec.label, spec.addr
)
})?;
if !remotes.insert(remote) {
return Err(format!(
"duplicate resolved target address {remote} for label {}",
spec.label
));
}
targets.push(ResolvedTarget {
targets.push(PreparedTarget {
label: spec.label.clone(),
managed: ManagedTargetConfig {
id: TargetId::from(spec.label),
remote,
auth: None,
},
managed: ManagedTargetConfig::new(TargetId::from(spec.label), spec.addr),
});
}
Ok(targets)
}
pub fn resolve_target(addr: &str, config: &ClientConfig) -> Result<std::net::SocketAddr, String> {
let normalized = normalize_target_addr(addr);
let mut addrs = normalized
.to_socket_addrs()
.map_err(|_| format!("failed to resolve address {normalized:?}"))?;
addrs
.find(|addr| {
(!config.socket_config.ipv4_only || addr.is_ipv4())
&& (!config.socket_config.ipv6_only || addr.is_ipv6())
})
.ok_or_else(|| format!("failed to resolve address {normalized:?}"))
}
pub fn normalize_target_addr(addr: &str) -> String {
const DEFAULT_PORT: u16 = 2112;
if addr.parse::<std::net::SocketAddr>().is_ok() {
return addr.to_owned();
}
if addr.starts_with('[') && addr.ends_with(']') {
return format!("{addr}:{DEFAULT_PORT}");
}
if addr.starts_with('[') {
return addr.to_owned();
}
if addr.parse::<std::net::Ipv6Addr>().is_ok() {
return format!("[{addr}]:{DEFAULT_PORT}");
}
if addr
.rsplit_once(':')
.is_some_and(|(_, port)| port.parse::<u16>().is_ok())
{
return addr.to_owned();
}
format!("{addr}:{DEFAULT_PORT}")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn target_normalization_matches_single_target_forms() {
assert_eq!(normalize_target_addr("127.0.0.1"), "127.0.0.1:2112");
assert_eq!(normalize_target_addr("127.0.0.1:1234"), "127.0.0.1:1234");
assert_eq!(normalize_target_addr("example.com"), "example.com:2112");
assert_eq!(
normalize_target_addr("example.com:1234"),
"example.com:1234"
);
assert_eq!(normalize_target_addr("[::1]"), "[::1]:2112");
assert_eq!(normalize_target_addr("[::1]:1234"), "[::1]:1234");
assert_eq!(normalize_target_addr("::1"), "[::1]:2112");
}
#[test]
fn target_resolution_respects_family_filters() {
let config = ClientConfig::default();
assert_eq!(
resolve_target("127.0.0.1", &config).unwrap(),
"127.0.0.1:2112".parse().unwrap()
);
assert_eq!(
resolve_target("[::1]", &config).unwrap(),
"[::1]:2112".parse().unwrap()
);
assert_eq!(
resolve_target("::1", &config).unwrap(),
"[::1]:2112".parse().unwrap()
);
let mut ipv4_only = ClientConfig::default();
ipv4_only.socket_config.ipv4_only = true;
assert!(resolve_target("127.0.0.1", &ipv4_only).unwrap().is_ipv4());
assert!(resolve_target("::1", &ipv4_only).is_err());
let mut ipv6_only = ClientConfig::default();
ipv6_only.socket_config.ipv6_only = true;
assert!(resolve_target("::1", &ipv6_only).unwrap().is_ipv6());
assert!(resolve_target("127.0.0.1", &ipv6_only).is_err());
}
#[test]
fn target_specs_suffix_repeated_positionals_and_reject_duplicate_labels() {
let positionals = vec!["host-a:2112".to_owned(), "host-a:2112".to_owned()];
@@ -222,19 +125,19 @@ mod tests {
}
#[test]
fn duplicate_resolved_target_addresses_are_rejected() {
fn target_preparation_preserves_hostname_and_allows_duplicate_endpoints() {
let specs = vec![
TargetSpec {
label: "a".to_owned(),
addr: "127.0.0.1:2112".to_owned(),
addr: "example.test".to_owned(),
},
TargetSpec {
label: "b".to_owned(),
addr: "127.0.0.1".to_owned(),
addr: "example.test".to_owned(),
},
];
let err = resolved_managed_targets(specs, &ClientConfig::default()).unwrap_err();
assert!(err.contains("duplicate resolved target address 127.0.0.1:2112"));
let targets = prepare_managed_targets(specs).unwrap();
assert_eq!(targets[0].managed.server_addr, "example.test");
assert_eq!(targets[1].managed.server_addr, "example.test");
}
}