use std::net::TcpStream; use std::time::Duration; use thiserror::Error; use tungstenite::stream::MaybeTlsStream; use tungstenite::{connect, Message, WebSocket}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct ProbeStep { pub label: String, pub payload: String, pub expect_reply: bool, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum ProbeOutcome { Received(Vec), NoReplyExpected, TimedOut, Closed, ConnectFailed(String), } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ProbeStepResult { pub label: String, pub sent: String, pub outcome: ProbeOutcome, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ProbeCliConfig { pub ws_url: String, pub timeout_ms: u64, pub steps: Vec, } const DEFAULT_TIMEOUT_MS: u64 = 1500; const DEFAULT_REGISTER_STEP_LABEL: &str = "register"; const DEFAULT_REGISTER_STEP_PAYLOAD: &str = r#"{"type":"register","role":"web"}"#; #[derive(Debug, Error)] pub enum ProbeError { #[error("io error: {0}")] Io(#[from] std::io::Error), #[error("probe timeout while waiting for websocket frame")] Timeout, #[error("probe websocket closed")] Closed, #[error("probe protocol error: {0}")] Protocol(String), #[error("probe argument error: {0}")] Args(String), } pub fn parse_probe_args(args: &[String]) -> Result { let mut ws_url = None; let mut timeout_ms = None; let mut steps = Vec::new(); let mut index = 0; while index < args.len() { match args[index].as_str() { "--ws-url" => { index += 1; let value = args .get(index) .ok_or_else(|| ProbeError::Args("missing value for --ws-url".to_string()))?; ws_url = Some(value.clone()); } "--timeout-ms" => { index += 1; let value = args.get(index).ok_or_else(|| { ProbeError::Args("missing value for --timeout-ms".to_string()) })?; let parsed = value.parse::().map_err(|_| { ProbeError::Args(format!("invalid --timeout-ms value: {value}")) })?; timeout_ms = Some(parsed); } "--step" => { index += 1; let value = args .get(index) .ok_or_else(|| ProbeError::Args("missing value for --step".to_string()))?; let (label, payload) = value.split_once("::").ok_or_else(|| { ProbeError::Args(format!( "invalid --step value (expected