irontide-session-core 1.0.2

BitTorrent session machinery: registries, queue, resume, apply, persistence (base layer)
Documentation
//! `Settings` → runtime-config conversions (M242).
//!
//! These were inherent `impl Settings` methods in `settings.rs`. Since
//! `Settings` is being extracted to the `irontide-settings` crate, they become
//! an extension trait implemented for `Settings` here, so existing call sites
//! (`settings.to_dht_config()` etc.) keep working with one `use` import and the
//! extracted settings crate stays free of session-only deps (dht/nat/utp/i2p).

use irontide_settings::Settings;

/// Conversions from [`Settings`] to the per-subsystem runtime configs.
pub trait SettingsConvertExt {
    /// Build the IPv4 DHT config, merging saved nodes ahead of the defaults.
    fn to_dht_config(&self) -> irontide_dht::DhtConfig;
    /// Build the IPv6 DHT config, merging saved nodes ahead of the defaults.
    fn to_dht_config_v6(&self) -> irontide_dht::DhtConfig;
    /// Build the NAT (`UPnP` / NAT-PMP) port-mapping config.
    fn to_nat_config(&self) -> irontide_nat::NatConfig;
    /// Build the IPv4 uTP socket config bound to `port`.
    fn to_utp_config(&self, port: u16) -> irontide_utp::UtpConfig;
    /// Build the IPv6 uTP socket config bound to `port`.
    fn to_utp_config_v6(&self, port: u16) -> irontide_utp::UtpConfig;
    /// Build the I2P SAM tunnel config from the I2P-related settings.
    fn to_sam_tunnel_config(&self) -> crate::i2p::SamTunnelConfig;
}

impl SettingsConvertExt for Settings {
    fn to_dht_config(&self) -> irontide_dht::DhtConfig {
        let default = irontide_dht::DhtConfig::default();
        let mut bootstrap = self.dht_saved_nodes.clone();
        bootstrap.extend(default.bootstrap_nodes.iter().cloned());
        irontide_dht::DhtConfig {
            bootstrap_nodes: bootstrap,
            own_id: self.dht_node_id,
            queries_per_second: self.dht_queries_per_second,
            query_timeout: std::time::Duration::from_secs(self.dht_query_timeout_secs),
            enforce_node_id: self.dht_enforce_node_id,
            restrict_routing_ips: self.dht_restrict_routing_ips,
            dht_max_items: self.dht_max_items,
            dht_item_lifetime_secs: self.dht_item_lifetime_secs,
            state_dir: self.resume_data_dir.clone(),
            read_only_mode: self.dht_read_only,
            ..default
        }
    }

    fn to_dht_config_v6(&self) -> irontide_dht::DhtConfig {
        let default = irontide_dht::DhtConfig::default_v6();
        let mut bootstrap = self.dht_saved_nodes.clone();
        bootstrap.extend(default.bootstrap_nodes.iter().cloned());
        irontide_dht::DhtConfig {
            bootstrap_nodes: bootstrap,
            queries_per_second: self.dht_queries_per_second,
            query_timeout: std::time::Duration::from_secs(self.dht_query_timeout_secs),
            enforce_node_id: self.dht_enforce_node_id,
            restrict_routing_ips: self.dht_restrict_routing_ips,
            dht_max_items: self.dht_max_items,
            dht_item_lifetime_secs: self.dht_item_lifetime_secs,
            state_dir: self.resume_data_dir.clone(),
            read_only_mode: self.dht_read_only,
            ..default
        }
    }

    fn to_nat_config(&self) -> irontide_nat::NatConfig {
        irontide_nat::NatConfig {
            enable_upnp: self.enable_upnp,
            enable_natpmp: self.enable_natpmp,
            upnp_lease_duration: self.upnp_lease_duration,
            natpmp_lifetime: self.natpmp_lifetime,
        }
    }

    fn to_utp_config(&self, port: u16) -> irontide_utp::UtpConfig {
        irontide_utp::UtpConfig {
            bind_addr: std::net::SocketAddr::from(([0, 0, 0, 0], port)),
            max_connections: self.utp_max_connections,
            dscp: self.peer_dscp,
        }
    }

    fn to_utp_config_v6(&self, port: u16) -> irontide_utp::UtpConfig {
        irontide_utp::UtpConfig {
            bind_addr: std::net::SocketAddr::from((std::net::Ipv6Addr::UNSPECIFIED, port)),
            max_connections: self.utp_max_connections,
            dscp: self.peer_dscp,
        }
    }

    fn to_sam_tunnel_config(&self) -> crate::i2p::SamTunnelConfig {
        crate::i2p::SamTunnelConfig {
            inbound_quantity: self.i2p_inbound_quantity,
            outbound_quantity: self.i2p_outbound_quantity,
            inbound_length: self.i2p_inbound_length,
            outbound_length: self.i2p_outbound_length,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn dht_config_inherits_security_settings() {
        let s = Settings {
            dht_enforce_node_id: false,
            ..Settings::default()
        };
        let dht = s.to_dht_config();
        assert!(!dht.enforce_node_id);
        assert!(dht.restrict_routing_ips);

        let dht_v6 = s.to_dht_config_v6();
        assert!(!dht_v6.enforce_node_id);
        assert!(dht_v6.restrict_routing_ips);
    }

    #[test]
    fn utp_config_includes_dscp() {
        let s = Settings {
            peer_dscp: 0x0A,
            ..Settings::default()
        };
        let utp = s.to_utp_config(6881);
        assert_eq!(utp.dscp, 0x0A);

        let utp_v6 = s.to_utp_config_v6(6881);
        assert_eq!(utp_v6.dscp, 0x0A);
    }
}