Phase 8e: cluster-ping migrates to connect_lan_first #68

Merged
osobh merged 1 commits from phase-8e-ping-lan-first into main 2026-07-14 19:11:00 +00:00
+27 -3
View File
@@ -104,6 +104,13 @@ enum Cmd {
/// Peer's RPC socket. Typically gossip_port + 1. /// Peer's RPC socket. Typically gossip_port + 1.
#[arg(long)] #[arg(long)]
rpc_addr: SocketAddr, rpc_addr: SocketAddr,
/// Phase 8c/8d: optional Tailscale RPC socket for
/// LAN-first-with-fallback routing. See `cluster-peer-status`.
#[arg(long)]
tailscale_addr: Option<SocketAddr>,
/// LAN probe deadline (ms) when `--tailscale-addr` is set.
#[arg(long, default_value_t = 200)]
lan_probe_ms: u64,
/// Payload to send. Echoed back with a "pong:" prefix. /// Payload to send. Echoed back with a "pong:" prefix.
#[arg(long, default_value = "hello")] #[arg(long, default_value = "hello")]
payload: String, payload: String,
@@ -345,9 +352,11 @@ async fn main() -> Result<()> {
name, name,
peer, peer,
rpc_addr, rpc_addr,
tailscale_addr,
lan_probe_ms,
payload, payload,
tls_dir, tls_dir,
} => cmd_cluster_ping(&name, &peer, rpc_addr, &payload, tls_dir.as_deref()).await?, } => cmd_cluster_ping(&name, &peer, rpc_addr, tailscale_addr, lan_probe_ms, &payload, tls_dir.as_deref()).await?,
Cmd::ClusterGc { evict_to_gb } => cmd_cluster_gc(&cfg, evict_to_gb).await?, Cmd::ClusterGc { evict_to_gb } => cmd_cluster_gc(&cfg, evict_to_gb).await?,
Cmd::ClusterScrub { verbose } => cmd_cluster_scrub(&cfg, verbose).await?, Cmd::ClusterScrub { verbose } => cmd_cluster_scrub(&cfg, verbose).await?,
Cmd::ClusterRepair { Cmd::ClusterRepair {
@@ -1072,10 +1081,12 @@ async fn cmd_cluster_ping(
name: &str, name: &str,
peer: &str, peer: &str,
rpc_addr: SocketAddr, rpc_addr: SocketAddr,
tailscale_addr: Option<SocketAddr>,
lan_probe_ms: u64,
payload: &str, payload: &str,
tls_dir: Option<&std::path::Path>, tls_dir: Option<&std::path::Path>,
) -> Result<()> { ) -> Result<()> {
use cluster::transport::{ping, NodeIdentity, QuicClient}; use cluster::transport::{ping, ConnectRoute, NodeIdentity, QuicClient};
// Two identity paths: // Two identity paths:
// 1. `--tls-dir` present → load persisted PEM. The peer must have // 1. `--tls-dir` present → load persisted PEM. The peer must have
@@ -1093,7 +1104,20 @@ async fn cmd_cluster_ping(
}; };
let client = QuicClient::new("0.0.0.0:0".parse()?, id_self)?; let client = QuicClient::new("0.0.0.0:0".parse()?, id_self)?;
let conn = client.connect(rpc_addr, peer).await?; // Phase 8: LAN-first with optional tailnet fallback. Zero flag
// = identical to pre-8 single-addr dial.
let (conn, route) = client
.connect_lan_first(
peer,
Some(rpc_addr),
tailscale_addr,
std::time::Duration::from_millis(lan_probe_ms),
)
.await?;
match route {
ConnectRoute::Lan(a) => println!("route: LAN ({a})"),
ConnectRoute::Tailscale(a) => println!("route: tailnet ({a})"),
}
let response = ping(&conn, payload.as_bytes()).await?; let response = ping(&conn, payload.as_bytes()).await?;
println!("→ sent: {}", payload); println!("→ sent: {}", payload);
println!("← recv: {}", String::from_utf8_lossy(&response)); println!("← recv: {}", String::from_utf8_lossy(&response));