1use serde::{Deserialize, Serialize};
2use serde_with::{serde_as, DisplayFromStr};
3use validator::{Validate, ValidationError};
4
5pub use hopr_strategy::StrategyConfig;
6pub use hopr_transport::config::{
7 validate_external_host, HeartbeatConfig, HostConfig, HostType, NetworkConfig, ProtocolConfig, TransportConfig,
8};
9
10use hopr_primitive_types::prelude::*;
11use hopr_transport::config::SessionGlobalConfig;
12
13pub const DEFAULT_SAFE_TRANSACTION_SERVICE_PROVIDER: &str = "https://safe-transaction.prod.hoprtech.net/";
14pub const DEFAULT_HOST: &str = "0.0.0.0";
15pub const DEFAULT_PORT: u16 = 9091;
16
17fn validate_announced(v: &bool) -> Result<(), ValidationError> {
18 if *v {
19 Ok(())
20 } else {
21 Err(ValidationError::new(
22 "Announce option should be turned ON in 2.*, only public nodes are supported",
23 ))
24 }
25}
26
27#[inline]
28fn default_network() -> String {
29 "anvil-localhost".to_owned()
30}
31
32#[inline]
33fn just_true() -> bool {
34 true
35}
36
37#[derive(Debug, Clone, PartialEq, smart_default::SmartDefault, Serialize, Deserialize, Validate)]
38#[serde(deny_unknown_fields)]
39pub struct Chain {
40 #[validate(custom(function = "validate_announced"))]
41 #[serde(default = "just_true")]
42 #[default = true]
43 pub announce: bool,
44 #[serde(default = "default_network")]
45 #[default(default_network())]
46 pub network: String,
47 #[serde(default)]
48 pub provider: Option<String>,
49 #[serde(default)]
50 pub max_rpc_requests_per_sec: Option<u32>,
51 #[serde(default)]
52 pub protocols: hopr_chain_api::config::ProtocolsConfig,
53 #[serde(default = "just_true")]
54 #[default = true]
55 pub check_unrealized_balance: bool,
56 #[serde(default = "just_true")]
57 #[default = true]
58 pub keep_logs: bool,
59 #[serde(default = "just_true")]
60 #[default = true]
61 pub fast_sync: bool,
62}
63
64#[inline]
65fn default_invalid_address() -> Address {
66 Address::default()
67}
68
69#[inline]
70fn default_safe_transaction_service_provider() -> String {
71 DEFAULT_SAFE_TRANSACTION_SERVICE_PROVIDER.to_owned()
72}
73
74#[serde_as]
75#[derive(Debug, Clone, PartialEq, smart_default::SmartDefault, Serialize, Deserialize, Validate)]
76#[serde(deny_unknown_fields)]
77pub struct SafeModule {
78 #[validate(url)]
79 #[serde(default = "default_safe_transaction_service_provider")]
80 #[default(default_safe_transaction_service_provider())]
81 pub safe_transaction_service_provider: String,
82 #[serde_as(as = "DisplayFromStr")]
83 #[serde(default = "default_invalid_address")]
84 #[default(default_invalid_address())]
85 pub safe_address: Address,
86 #[serde_as(as = "DisplayFromStr")]
87 #[serde(default = "default_invalid_address")]
88 #[default(default_invalid_address())]
89 pub module_address: Address,
90}
91
92#[allow(dead_code)]
93fn validate_directory_exists(s: &str) -> Result<(), ValidationError> {
94 if std::path::Path::new(s).is_dir() {
95 Ok(())
96 } else {
97 Err(ValidationError::new("Invalid directory path specified"))
98 }
99}
100
101#[derive(Debug, Clone, PartialEq, smart_default::SmartDefault, Serialize, Deserialize, Validate)]
102#[serde(deny_unknown_fields)]
103pub struct Db {
104 #[serde(default)]
106 pub data: String,
107 #[serde(default = "just_true")]
108 #[default = true]
109 pub initialize: bool,
110 #[serde(default)]
111 pub force_initialize: bool,
112}
113
114#[derive(Debug, Clone, PartialEq, smart_default::SmartDefault, Serialize, Deserialize, Validate)]
115pub struct HoprLibConfig {
116 #[validate(nested)]
118 #[validate(custom(function = "validate_external_host"))]
119 #[serde(default = "default_host")]
120 #[default(default_host())]
121 pub host: HostConfig,
122 #[validate(nested)]
124 #[serde(default)]
125 pub db: Db,
126 #[validate(nested)]
131 #[serde(default = "hopr_strategy::hopr_default_strategies")]
132 #[default(hopr_strategy::hopr_default_strategies())]
133 pub strategy: StrategyConfig,
134 #[validate(nested)]
136 #[serde(default)]
137 pub heartbeat: HeartbeatConfig,
138 #[validate(nested)]
140 #[serde(default)]
141 pub network_options: NetworkConfig,
142 #[validate(nested)]
144 #[serde(default)]
145 pub transport: TransportConfig,
146 #[validate(nested)]
148 #[serde(default)]
149 pub protocol: ProtocolConfig,
150 #[validate(nested)]
152 #[serde(default)]
153 pub session: SessionGlobalConfig,
154 #[validate(nested)]
156 #[serde(default)]
157 pub chain: Chain,
158 #[validate(nested)]
160 #[serde(default)]
161 pub safe_module: SafeModule,
162}
163
164#[inline]
167fn default_host() -> HostConfig {
168 HostConfig {
169 address: HostType::IPv4(DEFAULT_HOST.to_owned()),
170 port: DEFAULT_PORT,
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn test_config_should_be_serializable_using_serde() -> Result<(), Box<dyn std::error::Error>> {
180 let cfg = HoprLibConfig::default();
181
182 let yaml = serde_yaml::to_string(&cfg)?;
183 let cfg_after_serde: HoprLibConfig = serde_yaml::from_str(&yaml)?;
184 assert_eq!(cfg, cfg_after_serde);
185
186 Ok(())
187 }
188}