ferripfs-config 0.1.0

IPFS node configuration types, compatible with Kubo config format
Documentation
// Ported from: kubo/config/profile.go
// Kubo version: v0.39.0
// Original: https://github.com/ipfs/kubo/blob/v0.39.0/config/profile.go
//
// Original work: Copyright (c) Protocol Labs, Inc.
// Port: Copyright (c) 2026 ferripfs contributors
// SPDX-License-Identifier: MIT OR Apache-2.0

//! Configuration profiles for different use cases.

use crate::types::OptionalInteger;
use crate::{Config, ConnMgr, Discovery, Flag, Mdns};

/// Available configuration profiles
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Profile {
    /// Recommended for nodes with public IPv4 address
    Server,
    /// Enable local network discovery
    LocalDiscovery,
    /// Reduce resource usage for testing
    Test,
    /// Reduce resource usage for low-power devices
    Lowpower,
    /// Disable address announcement
    AnnounceOff,
    /// Enable address announcement (default)
    AnnounceOn,
    /// Use random ports
    Randomports,
    /// Use legacy CIDv0 by default
    LegacyCidV0,
    /// Use CIDv1 by default (for testing)
    TestCidV1,
}

impl Profile {
    /// Parse profile name
    pub fn from_name(name: &str) -> Option<Self> {
        match name.to_lowercase().as_str() {
            "server" => Some(Profile::Server),
            "local-discovery" => Some(Profile::LocalDiscovery),
            "test" => Some(Profile::Test),
            "lowpower" => Some(Profile::Lowpower),
            "announce-off" => Some(Profile::AnnounceOff),
            "announce-on" => Some(Profile::AnnounceOn),
            "randomports" => Some(Profile::Randomports),
            "legacy-cid-v0" => Some(Profile::LegacyCidV0),
            "test-cid-v1" => Some(Profile::TestCidV1),
            _ => None,
        }
    }

    /// Get profile name
    pub fn name(&self) -> &'static str {
        match self {
            Profile::Server => "server",
            Profile::LocalDiscovery => "local-discovery",
            Profile::Test => "test",
            Profile::Lowpower => "lowpower",
            Profile::AnnounceOff => "announce-off",
            Profile::AnnounceOn => "announce-on",
            Profile::Randomports => "randomports",
            Profile::LegacyCidV0 => "legacy-cid-v0",
            Profile::TestCidV1 => "test-cid-v1",
        }
    }

    /// Get profile description
    pub fn description(&self) -> &'static str {
        match self {
            Profile::Server => "Recommended for nodes with public IPv4 address. Disables local discovery, enables DHT server mode.",
            Profile::LocalDiscovery => "Enables local network discovery via mDNS.",
            Profile::Test => "Reduces resource usage for testing. Uses in-memory datastore, disables discovery.",
            Profile::Lowpower => "Reduces resource usage for low-power devices. Reduces connection limits.",
            Profile::AnnounceOff => "Disables address announcement to the DHT.",
            Profile::AnnounceOn => "Enables address announcement to the DHT (default).",
            Profile::Randomports => "Uses random ports for swarm listening.",
            Profile::LegacyCidV0 => "Uses CIDv0 by default when adding content.",
            Profile::TestCidV1 => "Uses CIDv1 with raw leaves by default.",
        }
    }

    /// Apply profile to configuration
    pub fn apply(&self, config: &mut Config) {
        match self {
            Profile::Server => {
                // Disable local discovery
                config.discovery = Discovery {
                    mdns: Mdns { enabled: false },
                };
                // Increase connection limits
                config.swarm.conn_mgr = ConnMgr {
                    low_water: Some(OptionalInteger(Some(100))),
                    high_water: Some(OptionalInteger(Some(400))),
                    grace_period: None,
                    ..Default::default()
                };
            }
            Profile::LocalDiscovery => {
                config.discovery = Discovery {
                    mdns: Mdns { enabled: true },
                };
            }
            Profile::Test => {
                // Disable discovery
                config.discovery = Discovery {
                    mdns: Mdns { enabled: false },
                };
                // Empty bootstrap
                config.bootstrap = vec![];
                // Reduce connection limits
                config.swarm.conn_mgr = ConnMgr {
                    low_water: Some(OptionalInteger(Some(2))),
                    high_water: Some(OptionalInteger(Some(10))),
                    ..Default::default()
                };
            }
            Profile::Lowpower => {
                // Reduce connection limits
                config.swarm.conn_mgr = ConnMgr {
                    low_water: Some(OptionalInteger(Some(20))),
                    high_water: Some(OptionalInteger(Some(40))),
                    ..Default::default()
                };
            }
            Profile::AnnounceOff => {
                // Add filter to block all announcements
                config.addresses.no_announce = vec![
                    "/ip4/0.0.0.0/ipcidr/0".to_string(),
                    "/ip6/::/ipcidr/0".to_string(),
                ];
            }
            Profile::AnnounceOn => {
                // Clear no_announce filters
                config.addresses.no_announce = vec![];
            }
            Profile::Randomports => {
                // Use port 0 for random assignment
                config.addresses.swarm = vec![
                    "/ip4/0.0.0.0/tcp/0".to_string(),
                    "/ip6/::/tcp/0".to_string(),
                    "/ip4/0.0.0.0/udp/0/quic-v1".to_string(),
                    "/ip6/::/udp/0/quic-v1".to_string(),
                ];
            }
            Profile::LegacyCidV0 => {
                config.import.cid_version = Some(OptionalInteger(Some(0)));
            }
            Profile::TestCidV1 => {
                config.import.cid_version = Some(OptionalInteger(Some(1)));
                config.import.unixfs_raw_leaves = Some(Flag::True);
            }
        }
    }
}

/// List all available profiles
pub fn list_profiles() -> Vec<Profile> {
    vec![
        Profile::Server,
        Profile::LocalDiscovery,
        Profile::Test,
        Profile::Lowpower,
        Profile::AnnounceOff,
        Profile::AnnounceOn,
        Profile::Randomports,
        Profile::LegacyCidV0,
        Profile::TestCidV1,
    ]
}

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

    #[test]
    fn test_profile_from_name() {
        assert_eq!(Profile::from_name("server"), Some(Profile::Server));
        assert_eq!(Profile::from_name("test"), Some(Profile::Test));
        assert_eq!(Profile::from_name("unknown"), None);
    }

    #[test]
    fn test_profile_apply_server() {
        let mut config = Config::default();
        Profile::Server.apply(&mut config);
        assert!(!config.discovery.mdns.enabled);
    }

    #[test]
    fn test_profile_apply_test() {
        let mut config = Config::default();
        Profile::Test.apply(&mut config);
        assert!(config.bootstrap.is_empty());
    }

    #[test]
    fn test_list_profiles() {
        let profiles = list_profiles();
        assert!(profiles.len() >= 8);
    }
}