1use core::{error::Error, net::SocketAddr, num::NonZero};
2use std::path::PathBuf;
3
4use clap::{ArgAction, Parser};
5use pnet::ipnetwork::IpNetwork;
6
7use crate::engine::{
8 http::{payload::jsonline::JsonLineRecord, Config as HttpConfig},
9 udp::Config as UdpConfig,
10};
11
12#[derive(Debug, Clone, Parser)]
14#[command(version, about)]
15#[command(flatten_help = true)]
16pub struct Cmd {
17 #[clap(subcommand)]
18 pub mode: ModeCmd,
19 #[clap(long, global = true)]
22 pub generator: Option<PathBuf>,
23 #[clap(short, action = ArgAction::Count, global = true)]
25 pub verbose: u8,
26}
27
28#[derive(Debug, Clone, Parser)]
29pub enum ModeCmd {
30 Http(HttpCmd),
32 #[command(name = "http/raw")]
34 HttpRaw(HttpRawCmd),
35 Udp(UdpCmd),
39 #[cfg(feature = "dpdk")]
40 Dpdk(DpdkCmd),
50}
51
52#[derive(Debug, Clone, Parser)]
53pub struct HttpRawCmd {
54 #[clap(flatten)]
55 pub cmd: HttpCmd,
56}
57
58#[derive(Debug, Clone, Parser)]
59pub struct HttpCmd {
60 #[clap(required = true)]
62 pub addr: SocketAddr,
63 #[clap(flatten)]
65 pub native: NativeLoadCmd,
66 #[clap(short, long, default_value_t = std::thread::available_parallelism().unwrap_or(NonZero::<usize>::MIN))]
72 pub concurrency: NonZero<usize>,
73 #[clap(long, value_name = "PATH", required = true)]
75 pub payload_json: Option<PathBuf>,
76 #[clap(long)]
78 pub tcp_linger: Option<u64>,
79 #[clap(long)]
81 pub tcp_no_delay: bool,
82}
83
84impl<T> TryFrom<HttpCmd> for HttpConfig<T>
85where
86 T: TryFrom<JsonLineRecord, Error = Box<dyn Error>>,
87{
88 type Error = Box<dyn Error>;
89
90 fn try_from(cmd: HttpCmd) -> Result<Self, Self::Error> {
91 let HttpCmd {
92 addr,
93 native,
94 concurrency,
95 payload_json,
96 tcp_linger,
97 tcp_no_delay,
98 } = cmd;
99
100 let requests = {
101 if let Some(path) = payload_json {
102 JsonLineRecord::from_fs(path)?
103 } else {
104 todo!();
105 }
106 };
107
108 let m = Self {
109 addr,
110 native: native.try_into()?,
111 concurrency,
112 tcp_linger,
113 tcp_no_delay,
114 requests,
115 };
116
117 Ok(m)
118 }
119}
120
121#[derive(Debug, Clone, Parser)]
122pub struct UdpCmd {
123 #[clap(required = true)]
125 pub addr: SocketAddr,
126 #[clap(flatten)]
128 pub native: NativeLoadCmd,
129}
130
131impl TryFrom<UdpCmd> for UdpConfig {
132 type Error = Box<dyn Error>;
133
134 fn try_from(v: UdpCmd) -> Result<Self, Self::Error> {
135 let UdpCmd { addr, native } = v;
136
137 let native = native.try_into()?;
138
139 let m = Self { addr, native };
140
141 Ok(m)
142 }
143}
144
145#[derive(Debug, Clone, Parser)]
147pub struct NativeLoadCmd {
148 #[clap(short, long, default_value_t = std::thread::available_parallelism().unwrap_or(NonZero::<usize>::MIN))]
150 pub threads: NonZero<usize>,
151 #[clap(long)]
155 pub requests_per_socket: Option<u64>,
156 #[clap(long)]
164 pub bind_network: Option<IpNetwork>,
165}
166
167#[derive(Debug, Clone, Parser)]
168pub struct DpdkCmd {
169 #[clap(long, required = true)]
171 pub dpdk_path: PathBuf,
172 #[clap(long, required = true)]
177 pub pcap_path: PathBuf,
178}