spvirit_tools/spvirit_client/
cli.rs1use std::net::SocketAddr;
2use std::time::Duration;
3
4use argparse::{ArgumentParser, Store, StoreTrue};
5
6use super::search::{is_auto_addr_list_enabled, parse_name_servers};
7use super::types::PvGetOptions;
8
9pub struct CommonClientArgs {
26 pub timeout_secs: u64,
27 pub server: String,
28 pub search_addr: String,
29 pub bind_addr: String,
30 pub name_server: String,
31 pub udp_port: u16,
32 pub tcp_port: u16,
33 pub debug: bool,
34 pub no_broadcast: bool,
35 pub authnz_user: String,
36 pub authnz_host: String,
37}
38
39impl CommonClientArgs {
40 pub fn new() -> Self {
41 Self {
42 timeout_secs: 5,
43 server: String::new(),
44 search_addr: String::new(),
45 bind_addr: String::new(),
46 name_server: String::new(),
47 udp_port: 5076,
48 tcp_port: 5075,
49 debug: false,
50 no_broadcast: false,
51 authnz_user: String::new(),
52 authnz_host: String::new(),
53 }
54 }
55
56 pub fn add_to_parser<'a, 'b>(&'a mut self, ap: &'b mut ArgumentParser<'a>) {
61 ap.refer(&mut self.timeout_secs).add_option(
62 &["-w", "--timeout"],
63 Store,
64 "Timeout in seconds",
65 );
66 ap.refer(&mut self.server)
67 .add_option(&["--server"], Store, "Server address (ip:port)");
68 ap.refer(&mut self.search_addr).add_option(
69 &["--search-addr"],
70 Store,
71 "Search target IP (default EPICS_PVA_ADDR_LIST/auto broadcast)",
72 );
73 ap.refer(&mut self.bind_addr).add_option(
74 &["--bind-addr"],
75 Store,
76 "Local bind IP for UDP search",
77 );
78 ap.refer(&mut self.name_server).add_option(
79 &["--name-server"],
80 Store,
81 "PVA name server address (host:port, repeatable via EPICS_PVA_NAME_SERVERS)",
82 );
83 ap.refer(&mut self.udp_port)
84 .add_option(&["--udp-port"], Store, "UDP search port");
85 ap.refer(&mut self.tcp_port)
86 .add_option(&["--tcp-port"], Store, "TCP server default port");
87 ap.refer(&mut self.debug)
88 .add_option(&["-d", "--debug"], StoreTrue, "Enable debug logging");
89 ap.refer(&mut self.no_broadcast).add_option(
90 &["--no-broadcast"],
91 StoreTrue,
92 "Disable UDP broadcast/multicast search (also set via EPICS_PVA_AUTO_ADDR_LIST=NO)",
93 );
94 ap.refer(&mut self.authnz_user).add_option(
95 &["--authnz-user"],
96 Store,
97 "AuthNZ user override (takes precedence over env)",
98 );
99 ap.refer(&mut self.authnz_host).add_option(
100 &["--authnz-host"],
101 Store,
102 "AuthNZ host override (takes precedence over env)",
103 );
104 }
105
106 pub fn init_tracing(&self) {
108 let max_level = if self.debug {
109 tracing::Level::DEBUG
110 } else {
111 tracing::Level::INFO
112 };
113 tracing_subscriber::fmt().with_max_level(max_level).init();
114 }
115
116 pub fn into_pv_get_options(
118 self,
119 pv_name: String,
120 ) -> Result<PvGetOptions, Box<dyn std::error::Error>> {
121 let mut opts = PvGetOptions::new(pv_name);
122 opts.timeout = Duration::from_secs(self.timeout_secs);
123 opts.udp_port = self.udp_port;
124 opts.tcp_port = self.tcp_port;
125 opts.debug = self.debug;
126 opts.no_broadcast = self.no_broadcast || !is_auto_addr_list_enabled();
127
128 if !self.server.is_empty() {
129 let addr: SocketAddr = self.server.parse()?;
130 opts.server_addr = Some(addr);
131 }
132 if !self.search_addr.is_empty() {
133 opts.search_addr = Some(self.search_addr.parse()?);
134 }
135 if !self.bind_addr.is_empty() {
136 opts.bind_addr = Some(self.bind_addr.parse()?);
137 }
138
139 let mut ns = parse_name_servers(&self.name_server);
140 if let Ok(env) = std::env::var("EPICS_PVA_NAME_SERVERS") {
141 ns.extend(parse_name_servers(&env));
142 }
143 opts.name_servers = ns;
144
145 if !self.authnz_user.is_empty() {
146 opts.authnz_user = Some(self.authnz_user);
147 }
148 if !self.authnz_host.is_empty() {
149 opts.authnz_host = Some(self.authnz_host);
150 }
151
152 Ok(opts)
153 }
154}