use serde::{Deserialize, Serialize};
use super::IdentityConfig;
use crate::mmp::{DEFAULT_LOG_INTERVAL_SECS, DEFAULT_OWD_WINDOW_SIZE, MmpConfig, MmpMode};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LimitsConfig {
#[serde(default = "LimitsConfig::default_max_connections")]
pub max_connections: usize,
#[serde(default = "LimitsConfig::default_max_peers")]
pub max_peers: usize,
#[serde(default = "LimitsConfig::default_max_links")]
pub max_links: usize,
#[serde(default = "LimitsConfig::default_max_pending_inbound")]
pub max_pending_inbound: usize,
}
impl Default for LimitsConfig {
fn default() -> Self {
Self {
max_connections: 256,
max_peers: 128,
max_links: 256,
max_pending_inbound: 1000,
}
}
}
impl LimitsConfig {
fn default_max_connections() -> usize {
256
}
fn default_max_peers() -> usize {
128
}
fn default_max_links() -> usize {
256
}
fn default_max_pending_inbound() -> usize {
1000
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RateLimitConfig {
#[serde(default = "RateLimitConfig::default_handshake_burst")]
pub handshake_burst: u32,
#[serde(default = "RateLimitConfig::default_handshake_rate")]
pub handshake_rate: f64,
#[serde(default = "RateLimitConfig::default_handshake_timeout_secs")]
pub handshake_timeout_secs: u64,
#[serde(default = "RateLimitConfig::default_handshake_resend_interval_ms")]
pub handshake_resend_interval_ms: u64,
#[serde(default = "RateLimitConfig::default_handshake_resend_backoff")]
pub handshake_resend_backoff: f64,
#[serde(default = "RateLimitConfig::default_handshake_max_resends")]
pub handshake_max_resends: u32,
}
impl Default for RateLimitConfig {
fn default() -> Self {
Self {
handshake_burst: 100,
handshake_rate: 10.0,
handshake_timeout_secs: 30,
handshake_resend_interval_ms: 1000,
handshake_resend_backoff: 2.0,
handshake_max_resends: 5,
}
}
}
impl RateLimitConfig {
fn default_handshake_burst() -> u32 {
100
}
fn default_handshake_rate() -> f64 {
10.0
}
fn default_handshake_timeout_secs() -> u64 {
30
}
fn default_handshake_resend_interval_ms() -> u64 {
1000
}
fn default_handshake_resend_backoff() -> f64 {
2.0
}
fn default_handshake_max_resends() -> u32 {
5
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RetryConfig {
#[serde(default = "RetryConfig::default_max_retries")]
pub max_retries: u32,
#[serde(default = "RetryConfig::default_base_interval_secs")]
pub base_interval_secs: u64,
#[serde(default = "RetryConfig::default_max_backoff_secs")]
pub max_backoff_secs: u64,
}
impl Default for RetryConfig {
fn default() -> Self {
Self {
max_retries: 5,
base_interval_secs: 5,
max_backoff_secs: 300,
}
}
}
impl RetryConfig {
fn default_max_retries() -> u32 {
5
}
fn default_base_interval_secs() -> u64 {
5
}
fn default_max_backoff_secs() -> u64 {
300
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CacheConfig {
#[serde(default = "CacheConfig::default_coord_size")]
pub coord_size: usize,
#[serde(default = "CacheConfig::default_coord_ttl_secs")]
pub coord_ttl_secs: u64,
#[serde(default = "CacheConfig::default_identity_size")]
pub identity_size: usize,
}
impl Default for CacheConfig {
fn default() -> Self {
Self {
coord_size: 50_000,
coord_ttl_secs: 300,
identity_size: 10_000,
}
}
}
impl CacheConfig {
fn default_coord_size() -> usize {
50_000
}
fn default_coord_ttl_secs() -> u64 {
300
}
fn default_identity_size() -> usize {
10_000
}
}
mod discovery;
pub use discovery::{DiscoveryConfig, NostrDiscoveryConfig, NostrDiscoveryPolicy};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TreeConfig {
#[serde(default = "TreeConfig::default_announce_min_interval_ms")]
pub announce_min_interval_ms: u64,
#[serde(default = "TreeConfig::default_parent_hysteresis")]
pub parent_hysteresis: f64,
#[serde(default = "TreeConfig::default_hold_down_secs")]
pub hold_down_secs: u64,
#[serde(default = "TreeConfig::default_reeval_interval_secs")]
pub reeval_interval_secs: u64,
#[serde(default = "TreeConfig::default_flap_threshold")]
pub flap_threshold: u32,
#[serde(default = "TreeConfig::default_flap_window_secs")]
pub flap_window_secs: u64,
#[serde(default = "TreeConfig::default_flap_dampening_secs")]
pub flap_dampening_secs: u64,
}
impl Default for TreeConfig {
fn default() -> Self {
Self {
announce_min_interval_ms: 500,
parent_hysteresis: 0.2,
hold_down_secs: 30,
reeval_interval_secs: 60,
flap_threshold: 4,
flap_window_secs: 60,
flap_dampening_secs: 120,
}
}
}
impl TreeConfig {
fn default_announce_min_interval_ms() -> u64 {
500
}
fn default_parent_hysteresis() -> f64 {
0.2
}
fn default_hold_down_secs() -> u64 {
30
}
fn default_reeval_interval_secs() -> u64 {
60
}
fn default_flap_threshold() -> u32 {
4
}
fn default_flap_window_secs() -> u64 {
60
}
fn default_flap_dampening_secs() -> u64 {
120
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RoutingConfig {
#[serde(default)]
pub mode: RoutingMode,
#[serde(default = "RoutingConfig::default_learned_ttl_secs")]
pub learned_ttl_secs: u64,
#[serde(default = "RoutingConfig::default_max_learned_routes_per_dest")]
pub max_learned_routes_per_dest: usize,
#[serde(default = "RoutingConfig::default_learned_fallback_explore_interval")]
pub learned_fallback_explore_interval: u64,
}
impl Default for RoutingConfig {
fn default() -> Self {
Self {
mode: RoutingMode::default(),
learned_ttl_secs: 300,
max_learned_routes_per_dest: 4,
learned_fallback_explore_interval: 16,
}
}
}
impl RoutingConfig {
fn default_learned_ttl_secs() -> u64 {
300
}
fn default_max_learned_routes_per_dest() -> usize {
4
}
fn default_learned_fallback_explore_interval() -> u64 {
16
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum RoutingMode {
#[default]
Tree,
ReplyLearned,
}
impl std::fmt::Display for RoutingMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RoutingMode::Tree => write!(f, "tree"),
RoutingMode::ReplyLearned => write!(f, "reply_learned"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BloomConfig {
#[serde(default = "BloomConfig::default_update_debounce_ms")]
pub update_debounce_ms: u64,
#[serde(default = "BloomConfig::default_max_inbound_fpr")]
pub max_inbound_fpr: f64,
}
impl Default for BloomConfig {
fn default() -> Self {
Self {
update_debounce_ms: 500,
max_inbound_fpr: 0.10,
}
}
}
impl BloomConfig {
fn default_update_debounce_ms() -> u64 {
500
}
fn default_max_inbound_fpr() -> f64 {
0.10
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionConfig {
#[serde(default = "SessionConfig::default_ttl")]
pub default_ttl: u8,
#[serde(default = "SessionConfig::default_pending_packets_per_dest")]
pub pending_packets_per_dest: usize,
#[serde(default = "SessionConfig::default_pending_max_destinations")]
pub pending_max_destinations: usize,
#[serde(default = "SessionConfig::default_idle_timeout_secs")]
pub idle_timeout_secs: u64,
#[serde(default = "SessionConfig::default_coords_warmup_packets")]
pub coords_warmup_packets: u8,
#[serde(default = "SessionConfig::default_coords_response_interval_ms")]
pub coords_response_interval_ms: u64,
}
impl Default for SessionConfig {
fn default() -> Self {
Self {
default_ttl: 64,
pending_packets_per_dest: 16,
pending_max_destinations: 256,
idle_timeout_secs: 90,
coords_warmup_packets: 5,
coords_response_interval_ms: 2000,
}
}
}
impl SessionConfig {
fn default_ttl() -> u8 {
64
}
fn default_pending_packets_per_dest() -> usize {
16
}
fn default_pending_max_destinations() -> usize {
256
}
fn default_idle_timeout_secs() -> u64 {
90
}
fn default_coords_warmup_packets() -> u8 {
5
}
fn default_coords_response_interval_ms() -> u64 {
2000
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionMmpConfig {
#[serde(default)]
pub mode: MmpMode,
#[serde(default = "SessionMmpConfig::default_log_interval_secs")]
pub log_interval_secs: u64,
#[serde(default = "SessionMmpConfig::default_owd_window_size")]
pub owd_window_size: usize,
}
impl Default for SessionMmpConfig {
fn default() -> Self {
Self {
mode: MmpMode::default(),
log_interval_secs: DEFAULT_LOG_INTERVAL_SECS,
owd_window_size: DEFAULT_OWD_WINDOW_SIZE,
}
}
}
impl SessionMmpConfig {
fn default_log_interval_secs() -> u64 {
DEFAULT_LOG_INTERVAL_SECS
}
fn default_owd_window_size() -> usize {
DEFAULT_OWD_WINDOW_SIZE
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ControlConfig {
#[serde(default = "ControlConfig::default_enabled")]
pub enabled: bool,
#[serde(default = "ControlConfig::default_socket_path")]
pub socket_path: String,
}
impl Default for ControlConfig {
fn default() -> Self {
Self {
enabled: true,
socket_path: Self::default_socket_path(),
}
}
}
impl ControlConfig {
fn default_enabled() -> bool {
true
}
fn default_socket_path() -> String {
#[cfg(unix)]
{
super::resolve_default_socket("control.sock")
}
#[cfg(windows)]
{
"21210".to_string()
}
}
}
const DEFAULT_PACKET_CHANNEL_CAPACITY: usize = 4096;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BuffersConfig {
#[serde(default = "BuffersConfig::default_packet_channel")]
pub packet_channel: usize,
#[serde(default = "BuffersConfig::default_tun_channel")]
pub tun_channel: usize,
#[serde(default = "BuffersConfig::default_dns_channel")]
pub dns_channel: usize,
}
impl Default for BuffersConfig {
fn default() -> Self {
Self {
packet_channel: DEFAULT_PACKET_CHANNEL_CAPACITY,
tun_channel: 1024,
dns_channel: 64,
}
}
}
impl BuffersConfig {
fn default_packet_channel() -> usize {
DEFAULT_PACKET_CHANNEL_CAPACITY
}
fn default_tun_channel() -> usize {
1024
}
fn default_dns_channel() -> usize {
64
}
}
const DEFAULT_REKEY_AFTER_MESSAGES: u64 = 1 << 48;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RekeyConfig {
#[serde(default = "RekeyConfig::default_enabled")]
pub enabled: bool,
#[serde(default = "RekeyConfig::default_after_secs")]
pub after_secs: u64,
#[serde(default = "RekeyConfig::default_after_messages")]
pub after_messages: u64,
}
impl Default for RekeyConfig {
fn default() -> Self {
Self {
enabled: true,
after_secs: 120,
after_messages: DEFAULT_REKEY_AFTER_MESSAGES,
}
}
}
impl RekeyConfig {
fn default_enabled() -> bool {
true
}
fn default_after_secs() -> u64 {
120
}
fn default_after_messages() -> u64 {
DEFAULT_REKEY_AFTER_MESSAGES
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EcnConfig {
#[serde(default = "EcnConfig::default_enabled")]
pub enabled: bool,
#[serde(default = "EcnConfig::default_loss_threshold")]
pub loss_threshold: f64,
#[serde(default = "EcnConfig::default_etx_threshold")]
pub etx_threshold: f64,
}
impl Default for EcnConfig {
fn default() -> Self {
Self {
enabled: true,
loss_threshold: 0.05,
etx_threshold: 3.0,
}
}
}
impl EcnConfig {
fn default_enabled() -> bool {
true
}
fn default_loss_threshold() -> f64 {
0.05
}
fn default_etx_threshold() -> f64 {
3.0
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeConfig {
#[serde(default)]
pub identity: IdentityConfig,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub leaf_only: bool,
#[serde(default = "NodeConfig::default_tick_interval_secs")]
pub tick_interval_secs: u64,
#[serde(default = "NodeConfig::default_base_rtt_ms")]
pub base_rtt_ms: u64,
#[serde(default = "NodeConfig::default_heartbeat_interval_secs")]
pub heartbeat_interval_secs: u64,
#[serde(default = "NodeConfig::default_link_dead_timeout_secs")]
pub link_dead_timeout_secs: u64,
#[serde(default = "NodeConfig::default_fast_link_dead_timeout_secs")]
pub fast_link_dead_timeout_secs: u64,
#[serde(default)]
pub limits: LimitsConfig,
#[serde(default)]
pub rate_limit: RateLimitConfig,
#[serde(default)]
pub retry: RetryConfig,
#[serde(default)]
pub cache: CacheConfig,
#[serde(default)]
pub discovery: DiscoveryConfig,
#[serde(default)]
pub tree: TreeConfig,
#[serde(default)]
pub routing: RoutingConfig,
#[serde(default)]
pub bloom: BloomConfig,
#[serde(default)]
pub session: SessionConfig,
#[serde(default)]
pub buffers: BuffersConfig,
#[serde(default)]
pub control: ControlConfig,
#[serde(default)]
pub mmp: MmpConfig,
#[serde(default)]
pub session_mmp: SessionMmpConfig,
#[serde(default)]
pub ecn: EcnConfig,
#[serde(default)]
pub rekey: RekeyConfig,
#[serde(default = "NodeConfig::default_system_files_enabled")]
pub system_files_enabled: bool,
#[serde(default)]
pub log_level: Option<String>,
}
impl Default for NodeConfig {
fn default() -> Self {
Self {
identity: IdentityConfig::default(),
leaf_only: false,
tick_interval_secs: 1,
base_rtt_ms: 100,
heartbeat_interval_secs: 10,
link_dead_timeout_secs: 30,
fast_link_dead_timeout_secs: 5,
limits: LimitsConfig::default(),
rate_limit: RateLimitConfig::default(),
retry: RetryConfig::default(),
cache: CacheConfig::default(),
discovery: DiscoveryConfig::default(),
tree: TreeConfig::default(),
routing: RoutingConfig::default(),
bloom: BloomConfig::default(),
session: SessionConfig::default(),
buffers: BuffersConfig::default(),
control: ControlConfig::default(),
mmp: MmpConfig::default(),
session_mmp: SessionMmpConfig::default(),
ecn: EcnConfig::default(),
rekey: RekeyConfig::default(),
system_files_enabled: true,
log_level: None,
}
}
}
impl NodeConfig {
pub fn log_level(&self) -> tracing::Level {
match self
.log_level
.as_deref()
.map(|s| s.to_lowercase())
.as_deref()
{
Some("trace") => tracing::Level::TRACE,
Some("debug") => tracing::Level::DEBUG,
Some("warn") | Some("warning") => tracing::Level::WARN,
Some("error") => tracing::Level::ERROR,
_ => tracing::Level::INFO,
}
}
fn default_tick_interval_secs() -> u64 {
1
}
fn default_base_rtt_ms() -> u64 {
100
}
fn default_heartbeat_interval_secs() -> u64 {
10
}
fn default_link_dead_timeout_secs() -> u64 {
30
}
fn default_fast_link_dead_timeout_secs() -> u64 {
5
}
fn default_system_files_enabled() -> bool {
true
}
}
#[cfg(test)]
mod tests;