1use std::str::FromStr;
2
3use clap::{ArgAction, Parser, builder::ValueParser};
4use hopr_lib::{HostConfig, looks_like_domain};
5use serde::{Deserialize, Serialize};
6
7pub const DEFAULT_API_HOST: &str = "localhost";
8pub const DEFAULT_API_PORT: u16 = 3001;
9
10pub const MINIMAL_API_TOKEN_LENGTH: usize = 8;
11
12fn parse_host(s: &str) -> Result<HostConfig, String> {
13 let host = s.split_once(':').map_or(s, |(h, _)| h);
14 if !(validator::ValidateIp::validate_ipv4(&host) || looks_like_domain(host)) {
15 return Err(format!(
16 "Given string {s} is not a valid host, should have a format: <ip>:<port> or <domain>(:<port>)"
17 ));
18 }
19
20 HostConfig::from_str(s)
21}
22
23fn parse_api_token(mut s: &str) -> Result<String, String> {
24 if s.len() < MINIMAL_API_TOKEN_LENGTH {
25 return Err(format!(
26 "Length of API token is too short, minimally required {MINIMAL_API_TOKEN_LENGTH} but given {}",
27 s.len()
28 ));
29 }
30
31 match (s.starts_with('\''), s.ends_with('\'')) {
32 (true, true) => {
33 s = s.strip_prefix('\'').ok_or("failed to parse strip prefix part")?;
34 s = s.strip_suffix('\'').ok_or("failed to parse strip suffix part")?;
35
36 Ok(s.into())
37 }
38 (true, false) => Err("Found leading quote but no trailing quote".into()),
39 (false, true) => Err("Found trailing quote but no leading quote".into()),
40 (false, false) => Ok(s.into()),
41 }
42}
43
44#[derive(Serialize, Deserialize, Clone, Parser)]
48#[command(author, version, about, long_about = None)]
49pub struct CliArgs {
50 #[arg(
52 long,
53 env = "HOPRD_NETWORK",
54 help = "ID of the network the node will attempt to connect to",
55 required = false
56 )]
57 pub network: Option<String>,
58
59 #[arg(
61 long,
62 env = "HOPRD_IDENTITY",
63 help = "The path to the identity file",
64 required = false
65 )]
66 pub identity: Option<String>,
67
68 #[arg(
70 long,
71 env = "HOPRD_DATA",
72 help = "Specifies the directory to hold all the data",
73 required = false
74 )]
75 pub data: Option<String>,
76
77 #[arg(
78 long,
79 env = "HOPRD_HOST",
80 help = "Host to listen on for P2P connections",
81 value_parser = ValueParser::new(parse_host),
82 )]
83 pub host: Option<HostConfig>,
84
85 #[arg(
86 long,
87 env = "HOPRD_ANNOUNCE",
88 help = "Announce the node on chain with a public address",
89 action = ArgAction::Count
90 )]
91 pub announce: u8,
92
93 #[arg(
94 long,
95 env = "HOPRD_API",
96 help = format!("Expose the API on {}:{}", DEFAULT_API_HOST, DEFAULT_API_PORT),
97 action = ArgAction::Count
98 )]
99 pub api: u8,
100
101 #[arg(
102 long = "apiHost",
103 value_name = "HOST",
104 help = "Set host IP to which the API server will bind",
105 env = "HOPRD_API_HOST"
106 )]
107 pub api_host: Option<String>,
108
109 #[arg(
110 long = "apiPort",
111 value_parser = clap::value_parser ! (u16),
112 value_name = "PORT",
113 help = "Set port to which the API server will bind",
114 env = "HOPRD_API_PORT"
115 )]
116 pub api_port: Option<u16>,
117
118 #[arg(
119 long = "defaultSessionListenHost",
120 env = "HOPRD_DEFAULT_SESSION_LISTEN_HOST",
121 help = "Default Session listening host for Session IP forwarding",
122 value_parser = ValueParser::new(parse_host),
123 )]
124 pub default_session_listen_host: Option<HostConfig>,
125
126 #[arg(
127 long = "disableApiAuthentication",
128 help = "Completely disables the token authentication for the API, overrides any apiToken if set",
129 env = "HOPRD_DISABLE_API_AUTHENTICATION",
130 hide = true,
131 action = ArgAction::Count
132 )]
133 pub disable_api_authentication: u8,
134
135 #[arg(
136 long = "apiToken",
137 alias = "api-token",
138 help = "A REST API token and for user authentication",
139 value_name = "TOKEN",
140 value_parser = ValueParser::new(parse_api_token),
141 env = "HOPRD_API_TOKEN"
142 )]
143 pub api_token: Option<String>,
144
145 #[arg(
146 long,
147 env = "HOPRD_PASSWORD",
148 help = "A password to encrypt your keys",
149 value_name = "PASSWORD"
150 )]
151 pub password: Option<String>,
152
153 #[arg(
154 long = "noKeepLogs",
155 env = "HOPRD_INDEXER_DISABLE_KEEP_LOGS",
156 help = "Disables keeping RPC logs in the logs database after they were processed.",
157 action = ArgAction::Count
158 )]
159 pub no_keep_logs: u8,
160
161 #[arg(
162 long = "noFastSync",
163 env = "HOPRD_INDEXER_DISABLE_FAST_SYNC",
164 help = "Disables using fast sync at node start.",
165 action = ArgAction::Count
166 )]
167 pub no_fast_sync: u8,
168
169 #[arg(
170 long = "maxBlockRange",
171 help = "Maximum number of blocks that can be fetched in a batch request from the RPC provider.",
172 env = "HOPRD_MAX_BLOCK_RANGE",
173 value_name = "MAX_BLOCK_RANGE",
174 value_parser = clap::value_parser ! (u64)
175 )]
176 pub max_block_range: Option<u64>,
177
178 #[arg(
179 long = "maxRequestsPerSec",
180 help = "Maximum number of RPC requests that can be performed per second.",
181 env = "HOPRD_MAX_RPC_REQUESTS_PER_SEC",
182 value_name = "MAX_RPC_REQUESTS_PER_SEC",
183 value_parser = clap::value_parser ! (u32)
184 )]
185 pub max_rpc_requests_per_sec: Option<u32>,
186
187 #[arg(
188 long,
189 help = "A custom RPC provider to be used for the node to connect to blockchain",
190 env = "HOPRD_PROVIDER",
191 value_name = "PROVIDER"
192 )]
193 pub provider: Option<String>,
194
195 #[arg(
196 long,
197 help = "initialize a database if it doesn't already exist",
198 env = "HOPRD_INIT",
199 action = ArgAction::Count
200 )]
201 pub init: u8,
202
203 #[arg(
204 long = "forceInit",
205 help = "initialize a database, even if it already exists",
206 env = "HOPRD_FORCE_INIT",
207 action = ArgAction::Count
208 )]
209 pub force_init: u8,
210
211 #[arg(
212 long = "privateKey",
213 hide = true,
214 help = "A private key to be used for the node",
215 env = "HOPRD_PRIVATE_KEY",
216 value_name = "PRIVATE_KEY"
217 )]
218 pub private_key: Option<String>,
219
220 #[arg(
221 long = "testAnnounceLocalAddresses",
222 env = "HOPRD_TEST_ANNOUNCE_LOCAL_ADDRESSES",
223 help = "For testing local testnets. Announce local addresses",
224 hide = true,
225 action = ArgAction::Count
226 )]
227 pub test_announce_local_addresses: u8,
228
229 #[arg(
230 long = "testPreferLocalAddresses",
231 env = "HOPRD_TEST_PREFER_LOCAL_ADDRESSES",
232 help = "For testing local testnets. Prefer local peers to remote",
233 hide = true,
234 action = ArgAction::Count
235 )]
236 pub test_prefer_local_addresses: u8,
237
238 #[arg(
239 long = "probeRecheckThreshold",
240 help = "Timeframe in seconds after which it is reasonable to recheck the nearest neighbor",
241 value_name = "SECONDS",
242 value_parser = clap::value_parser ! (u64),
243 env = "HOPRD_PROBE_RECHECK_THRESHOLD",
244 )]
245 pub probe_recheck_threshold: Option<u64>,
246
247 #[arg(
248 long = "networkQualityThreshold",
249 help = "Minimum quality of a peer connection to be considered usable",
250 value_name = "THRESHOLD",
251 value_parser = clap::value_parser ! (f64),
252 env = "HOPRD_NETWORK_QUALITY_THRESHOLD"
253 )]
254 pub network_quality_threshold: Option<f64>,
255
256 #[arg(
257 long = "configurationFilePath",
258 required = false,
259 help = "Path to a file containing the entire HOPRd configuration",
260 value_name = "CONFIG_FILE_PATH",
261 value_parser = clap::value_parser ! (String),
262 env = "HOPRD_CONFIGURATION_FILE_PATH"
263 )]
264 pub configuration_file_path: Option<String>,
265
266 #[arg(
267 long = "safeTransactionServiceProvider",
268 value_name = "HOPRD_SAFE_TX_SERVICE_PROVIDER",
269 help = "Base URL for safe transaction service",
270 env = "HOPRD_SAFE_TRANSACTION_SERVICE_PROVIDER"
271 )]
272 pub safe_transaction_service_provider: Option<String>,
273
274 #[arg(
275 long = "safeAddress",
276 value_name = "HOPRD_SAFE_ADDR",
277 help = "Address of Safe that safeguards tokens",
278 env = "HOPRD_SAFE_ADDRESS"
279 )]
280 pub safe_address: Option<String>,
281
282 #[arg(
283 long = "moduleAddress",
284 value_name = "HOPRD_MODULE_ADDR",
285 help = "Address of the node management module",
286 env = "HOPRD_MODULE_ADDRESS"
287 )]
288 pub module_address: Option<String>,
289
290 #[arg(
291 long = "protocolConfig",
292 value_name = "HOPRD_PROTOCOL_CONFIG_PATH",
293 help = "Path to the protocol-config.json file",
294 env = "HOPRD_PROTOCOL_CONFIG_PATH"
295 )]
296 pub protocol_config_path: Option<String>,
297}