use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr};
use validator::{Validate, ValidationError};
pub use hopr_strategy::StrategyConfig;
pub use hopr_transport::config::{
validate_external_host, HeartbeatConfig, HostConfig, HostType, NetworkConfig, ProtocolConfig, TransportConfig,
};
use hopr_primitive_types::prelude::*;
use hopr_transport::config::SessionGlobalConfig;
pub const DEFAULT_SAFE_TRANSACTION_SERVICE_PROVIDER: &str = "https://safe-transaction.prod.hoprtech.net/";
pub const DEFAULT_HOST: &str = "0.0.0.0";
pub const DEFAULT_PORT: u16 = 9091;
fn validate_announced(v: &bool) -> Result<(), ValidationError> {
if *v {
Ok(())
} else {
Err(ValidationError::new(
"Announce option should be turned ON in 2.*, only public nodes are supported",
))
}
}
#[inline]
fn default_network() -> String {
"anvil-localhost".to_owned()
}
#[inline]
fn just_true() -> bool {
true
}
#[derive(Debug, Clone, PartialEq, smart_default::SmartDefault, Serialize, Deserialize, Validate)]
#[serde(deny_unknown_fields)]
pub struct Chain {
#[validate(custom(function = "validate_announced"))]
#[serde(default = "just_true")]
#[default = true]
pub announce: bool,
#[serde(default = "default_network")]
#[default(default_network())]
pub network: String,
#[serde(default)]
pub provider: Option<String>,
#[serde(default)]
pub max_rpc_requests_per_sec: Option<u32>,
#[serde(default)]
pub protocols: hopr_chain_api::config::ProtocolsConfig,
#[serde(default = "just_true")]
#[default = true]
pub check_unrealized_balance: bool,
#[serde(default = "just_true")]
#[default = true]
pub keep_logs: bool,
#[serde(default = "just_true")]
#[default = true]
pub fast_sync: bool,
}
#[inline]
fn default_invalid_address() -> Address {
Address::default()
}
#[inline]
fn default_safe_transaction_service_provider() -> String {
DEFAULT_SAFE_TRANSACTION_SERVICE_PROVIDER.to_owned()
}
#[serde_as]
#[derive(Debug, Clone, PartialEq, smart_default::SmartDefault, Serialize, Deserialize, Validate)]
#[serde(deny_unknown_fields)]
pub struct SafeModule {
#[validate(url)]
#[serde(default = "default_safe_transaction_service_provider")]
#[default(default_safe_transaction_service_provider())]
pub safe_transaction_service_provider: String,
#[serde_as(as = "DisplayFromStr")]
#[serde(default = "default_invalid_address")]
#[default(default_invalid_address())]
pub safe_address: Address,
#[serde_as(as = "DisplayFromStr")]
#[serde(default = "default_invalid_address")]
#[default(default_invalid_address())]
pub module_address: Address,
}
#[allow(dead_code)]
fn validate_directory_exists(s: &str) -> Result<(), ValidationError> {
if std::path::Path::new(s).is_dir() {
Ok(())
} else {
Err(ValidationError::new("Invalid directory path specified"))
}
}
#[derive(Debug, Clone, PartialEq, smart_default::SmartDefault, Serialize, Deserialize, Validate)]
#[serde(deny_unknown_fields)]
pub struct Db {
#[serde(default)]
pub data: String,
#[serde(default = "just_true")]
#[default = true]
pub initialize: bool,
#[serde(default)]
pub force_initialize: bool,
}
#[derive(Debug, Clone, PartialEq, smart_default::SmartDefault, Serialize, Deserialize, Validate)]
pub struct HoprLibConfig {
#[validate(nested)]
#[validate(custom(function = "validate_external_host"))]
#[serde(default = "default_host")]
#[default(default_host())]
pub host: HostConfig,
#[validate(nested)]
#[serde(default)]
pub db: Db,
#[validate(nested)]
#[serde(default = "hopr_strategy::hopr_default_strategies")]
#[default(hopr_strategy::hopr_default_strategies())]
pub strategy: StrategyConfig,
#[validate(nested)]
#[serde(default)]
pub heartbeat: HeartbeatConfig,
#[validate(nested)]
#[serde(default)]
pub network_options: NetworkConfig,
#[validate(nested)]
#[serde(default)]
pub transport: TransportConfig,
#[validate(nested)]
#[serde(default)]
pub protocol: ProtocolConfig,
#[validate(nested)]
#[serde(default)]
pub session: SessionGlobalConfig,
#[validate(nested)]
#[serde(default)]
pub chain: Chain,
#[validate(nested)]
#[serde(default)]
pub safe_module: SafeModule,
}
#[inline]
fn default_host() -> HostConfig {
HostConfig {
address: HostType::IPv4(DEFAULT_HOST.to_owned()),
port: DEFAULT_PORT,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_config_should_be_serializable_using_serde() -> Result<(), Box<dyn std::error::Error>> {
let cfg = HoprLibConfig::default();
let yaml = serde_yaml::to_string(&cfg)?;
let cfg_after_serde: HoprLibConfig = serde_yaml::from_str(&yaml)?;
assert_eq!(cfg, cfg_after_serde);
Ok(())
}
}