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 = "enableLogsSnapshot",
171 env = "HOPRD_ENABLE_LOGS_SNAPSHOT",
172 help = "Enables downloading logs snapshot at node start. If this is set to true, the node will attempt to \
173 download logs snapshot from the configured `logsSnapshotUrl`.",
174 value_name = "ENABLE_LOGS_SNAPSHOT",
175 action = ArgAction::Count
176 )]
177 pub enable_logs_snapshot: u8,
178
179 #[arg(
180 long = "logsSnapshotUrl",
181 env = "HOPRD_LOGS_SNAPSHOT_URL",
182 help = "URL to download logs snapshot from. If none is provided or configured in the configuration file, the \
183 node will not attempt to download any logs snapshot.",
184 value_name = "LOGS_SNAPSHOT_URL"
185 )]
186 pub logs_snapshot_url: Option<String>,
187
188 #[arg(
189 long = "maxBlockRange",
190 help = "Maximum number of blocks that can be fetched in a batch request from the RPC provider.",
191 env = "HOPRD_MAX_BLOCK_RANGE",
192 value_name = "MAX_BLOCK_RANGE",
193 value_parser = clap::value_parser ! (u64)
194 )]
195 pub max_block_range: Option<u64>,
196
197 #[arg(
198 long = "maxRequestsPerSec",
199 help = "Maximum number of RPC requests that can be performed per second.",
200 env = "HOPRD_MAX_RPC_REQUESTS_PER_SEC",
201 value_name = "MAX_RPC_REQUESTS_PER_SEC",
202 value_parser = clap::value_parser ! (u32)
203 )]
204 pub max_rpc_requests_per_sec: Option<u32>,
205
206 #[arg(
207 long,
208 help = "A custom RPC provider to be used for the node to connect to blockchain",
209 env = "HOPRD_PROVIDER",
210 value_name = "PROVIDER"
211 )]
212 pub provider: Option<String>,
213
214 #[arg(
215 long,
216 help = "initialize a database if it doesn't already exist",
217 env = "HOPRD_INIT",
218 action = ArgAction::Count
219 )]
220 pub init: u8,
221
222 #[arg(
223 long = "forceInit",
224 help = "initialize a database, even if it already exists",
225 env = "HOPRD_FORCE_INIT",
226 action = ArgAction::Count
227 )]
228 pub force_init: u8,
229
230 #[arg(
231 long = "privateKey",
232 hide = true,
233 help = "A private key to be used for the node",
234 env = "HOPRD_PRIVATE_KEY",
235 value_name = "PRIVATE_KEY"
236 )]
237 pub private_key: Option<String>,
238
239 #[arg(
240 long = "testAnnounceLocalAddresses",
241 env = "HOPRD_TEST_ANNOUNCE_LOCAL_ADDRESSES",
242 help = "For testing local testnets. Announce local addresses",
243 hide = true,
244 action = ArgAction::Count
245 )]
246 pub test_announce_local_addresses: u8,
247
248 #[arg(
249 long = "testPreferLocalAddresses",
250 env = "HOPRD_TEST_PREFER_LOCAL_ADDRESSES",
251 help = "For testing local testnets. Prefer local peers to remote",
252 hide = true,
253 action = ArgAction::Count
254 )]
255 pub test_prefer_local_addresses: u8,
256
257 #[arg(
258 long = "probeRecheckThreshold",
259 help = "Timeframe in seconds after which it is reasonable to recheck the nearest neighbor",
260 value_name = "SECONDS",
261 value_parser = clap::value_parser ! (u64),
262 env = "HOPRD_PROBE_RECHECK_THRESHOLD",
263 )]
264 pub probe_recheck_threshold: Option<u64>,
265
266 #[arg(
267 long = "networkQualityThreshold",
268 help = "Minimum quality of a peer connection to be considered usable",
269 value_name = "THRESHOLD",
270 value_parser = clap::value_parser ! (f64),
271 env = "HOPRD_NETWORK_QUALITY_THRESHOLD"
272 )]
273 pub network_quality_threshold: Option<f64>,
274
275 #[arg(
276 long = "configurationFilePath",
277 required = false,
278 help = "Path to a file containing the entire HOPRd configuration",
279 value_name = "CONFIG_FILE_PATH",
280 value_parser = clap::value_parser ! (String),
281 env = "HOPRD_CONFIGURATION_FILE_PATH"
282 )]
283 pub configuration_file_path: Option<String>,
284
285 #[arg(
286 long = "safeTransactionServiceProvider",
287 value_name = "HOPRD_SAFE_TX_SERVICE_PROVIDER",
288 help = "Base URL for safe transaction service",
289 env = "HOPRD_SAFE_TRANSACTION_SERVICE_PROVIDER"
290 )]
291 pub safe_transaction_service_provider: Option<String>,
292
293 #[arg(
294 long = "safeAddress",
295 value_name = "HOPRD_SAFE_ADDR",
296 help = "Address of Safe that safeguards tokens",
297 env = "HOPRD_SAFE_ADDRESS"
298 )]
299 pub safe_address: Option<String>,
300
301 #[arg(
302 long = "moduleAddress",
303 value_name = "HOPRD_MODULE_ADDR",
304 help = "Address of the node management module",
305 env = "HOPRD_MODULE_ADDRESS"
306 )]
307 pub module_address: Option<String>,
308
309 #[arg(
310 long = "protocolConfig",
311 value_name = "HOPRD_PROTOCOL_CONFIG_PATH",
312 help = "Path to the protocol-config.json file",
313 env = "HOPRD_PROTOCOL_CONFIG_PATH"
314 )]
315 pub protocol_config_path: Option<String>,
316}