1use std::time::Duration;
2
3use hopr_api::types::primitive::prelude::*;
4pub use hopr_transport::{
5 TagAllocatorConfig,
6 config::{
7 HoprPacketPipelineConfig, HoprProtocolConfig, HostConfig, HostType, MixerConfig, ProbeConfig,
8 SessionGlobalConfig, TransitLatencyConfig, TransportConfig, looks_like_domain,
9 },
10};
11use validator::{Validate, ValidationError};
12
13pub const DEFAULT_HOST: &str = "0.0.0.0";
14pub const DEFAULT_PORT: u16 = 9091;
15
16#[inline]
17fn default_invalid_address() -> Address {
18 Address::default()
19}
20
21#[cfg_attr(feature = "serde", cfg_eval::cfg_eval, serde_with::serde_as)]
22#[derive(Debug, Clone, PartialEq, smart_default::SmartDefault, Validate)]
23#[cfg_attr(
24 feature = "serde",
25 derive(serde::Serialize, serde::Deserialize),
26 serde(deny_unknown_fields)
27)]
28pub struct SafeModule {
29 #[cfg_attr(
30 feature = "serde",
31 serde_as(as = "serde_with::DisplayFromStr"),
32 serde(default = "default_invalid_address")
33 )]
34 #[default(default_invalid_address())]
35 pub safe_address: Address,
36 #[cfg_attr(
37 feature = "serde",
38 serde_as(as = "serde_with::DisplayFromStr"),
39 serde(default = "default_invalid_address")
40 )]
41 #[default(default_invalid_address())]
42 pub module_address: Address,
43}
44
45#[cfg(feature = "session-server")]
46#[inline]
47fn default_incoming_session_capacity() -> usize {
48 256
49}
50
51#[allow(dead_code)]
52fn validate_directory_exists(s: &str) -> Result<(), ValidationError> {
53 if std::path::Path::new(s).is_dir() {
54 Ok(())
55 } else {
56 Err(ValidationError::new("Invalid directory path specified"))
57 }
58}
59
60#[derive(Debug, Clone, PartialEq, smart_default::SmartDefault, Validate)]
61#[cfg_attr(
62 feature = "serde",
63 derive(serde::Serialize, serde::Deserialize),
64 serde(deny_unknown_fields)
65)]
66pub struct HoprLibConfig {
67 #[validate(nested)]
69 #[default(default_host())]
70 #[cfg_attr(feature = "serde", serde(default = "default_host"))]
71 pub host: HostConfig,
72 #[cfg_attr(feature = "serde", serde(default))]
74 pub publish: bool,
75 #[validate(nested)]
77 #[cfg_attr(feature = "serde", serde(default))]
78 pub protocol: HoprProtocolConfig,
79 #[validate(nested)]
81 #[cfg_attr(feature = "serde", serde(default))]
82 pub safe_module: SafeModule,
83 #[default(default_out_index_sync_period())]
91 #[validate(custom(function = "validate_out_index_sync_period"))]
92 #[cfg_attr(
93 feature = "serde",
94 serde(default = "default_out_index_sync_period", with = "humantime_serde")
95 )]
96 pub out_index_sync_period: Duration,
97 #[cfg(feature = "session-server")]
101 #[default(default_incoming_session_capacity())]
102 #[cfg_attr(feature = "serde", serde(default = "default_incoming_session_capacity"))]
103 pub incoming_session_capacity: usize,
104 #[cfg(debug_assertions)]
108 #[cfg_attr(feature = "serde", serde(default))]
109 pub disable_protocol_checks: bool,
110}
111
112const MINIMUM_OUT_SYNC_PERIOD: Duration = Duration::from_secs(1);
113
114fn validate_out_index_sync_period(lifetime: &Duration) -> Result<(), ValidationError> {
115 if lifetime < &MINIMUM_OUT_SYNC_PERIOD {
116 Err(ValidationError::new("out_index_sync_period is too low"))
117 } else {
118 Ok(())
119 }
120}
121
122fn default_out_index_sync_period() -> Duration {
123 Duration::from_secs(15)
124}
125
126#[inline]
129fn default_host() -> HostConfig {
130 HostConfig {
131 address: HostType::IPv4(DEFAULT_HOST.to_owned()),
132 port: DEFAULT_PORT,
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 #[cfg(feature = "serde")]
139 #[test]
140 fn test_config_should_be_serializable_using_serde() -> Result<(), Box<dyn std::error::Error>> {
141 let cfg = super::HoprLibConfig::default();
142
143 let yaml = serde_saphyr::to_string(&cfg)?;
144 let cfg_after_serde: super::HoprLibConfig = serde_saphyr::from_str(&yaml)?;
145 assert_eq!(cfg, cfg_after_serde);
146
147 Ok(())
148 }
149
150 #[cfg(feature = "serde")]
151 #[test]
152 fn explicit_mixer_section_round_trips() -> anyhow::Result<()> {
153 use std::time::Duration;
154
155 let mut cfg = super::HoprLibConfig::default();
156 cfg.protocol.mixer = super::MixerConfig {
157 min_delay: Duration::from_millis(5),
158 delay_range: Duration::from_millis(50),
159 capacity: 1_000,
160 ..Default::default()
161 };
162 insta::assert_yaml_snapshot!(cfg.protocol.mixer);
163
164 let yaml = serde_saphyr::to_string(&cfg.protocol.mixer)?;
165 let parsed: super::MixerConfig = serde_saphyr::from_str(&yaml)?;
166 assert_eq!(cfg.protocol.mixer, parsed);
167
168 Ok(())
169 }
170}