Skip to main content

ferripfs_config/
profile.rs

1// Ported from: kubo/config/profile.go
2// Kubo version: v0.39.0
3// Original: https://github.com/ipfs/kubo/blob/v0.39.0/config/profile.go
4//
5// Original work: Copyright (c) Protocol Labs, Inc.
6// Port: Copyright (c) 2026 ferripfs contributors
7// SPDX-License-Identifier: MIT OR Apache-2.0
8
9//! Configuration profiles for different use cases.
10
11use crate::types::OptionalInteger;
12use crate::{Config, ConnMgr, Discovery, Flag, Mdns};
13
14/// Available configuration profiles
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum Profile {
17    /// Recommended for nodes with public IPv4 address
18    Server,
19    /// Enable local network discovery
20    LocalDiscovery,
21    /// Reduce resource usage for testing
22    Test,
23    /// Reduce resource usage for low-power devices
24    Lowpower,
25    /// Disable address announcement
26    AnnounceOff,
27    /// Enable address announcement (default)
28    AnnounceOn,
29    /// Use random ports
30    Randomports,
31    /// Use legacy CIDv0 by default
32    LegacyCidV0,
33    /// Use CIDv1 by default (for testing)
34    TestCidV1,
35}
36
37impl Profile {
38    /// Parse profile name
39    pub fn from_name(name: &str) -> Option<Self> {
40        match name.to_lowercase().as_str() {
41            "server" => Some(Profile::Server),
42            "local-discovery" => Some(Profile::LocalDiscovery),
43            "test" => Some(Profile::Test),
44            "lowpower" => Some(Profile::Lowpower),
45            "announce-off" => Some(Profile::AnnounceOff),
46            "announce-on" => Some(Profile::AnnounceOn),
47            "randomports" => Some(Profile::Randomports),
48            "legacy-cid-v0" => Some(Profile::LegacyCidV0),
49            "test-cid-v1" => Some(Profile::TestCidV1),
50            _ => None,
51        }
52    }
53
54    /// Get profile name
55    pub fn name(&self) -> &'static str {
56        match self {
57            Profile::Server => "server",
58            Profile::LocalDiscovery => "local-discovery",
59            Profile::Test => "test",
60            Profile::Lowpower => "lowpower",
61            Profile::AnnounceOff => "announce-off",
62            Profile::AnnounceOn => "announce-on",
63            Profile::Randomports => "randomports",
64            Profile::LegacyCidV0 => "legacy-cid-v0",
65            Profile::TestCidV1 => "test-cid-v1",
66        }
67    }
68
69    /// Get profile description
70    pub fn description(&self) -> &'static str {
71        match self {
72            Profile::Server => "Recommended for nodes with public IPv4 address. Disables local discovery, enables DHT server mode.",
73            Profile::LocalDiscovery => "Enables local network discovery via mDNS.",
74            Profile::Test => "Reduces resource usage for testing. Uses in-memory datastore, disables discovery.",
75            Profile::Lowpower => "Reduces resource usage for low-power devices. Reduces connection limits.",
76            Profile::AnnounceOff => "Disables address announcement to the DHT.",
77            Profile::AnnounceOn => "Enables address announcement to the DHT (default).",
78            Profile::Randomports => "Uses random ports for swarm listening.",
79            Profile::LegacyCidV0 => "Uses CIDv0 by default when adding content.",
80            Profile::TestCidV1 => "Uses CIDv1 with raw leaves by default.",
81        }
82    }
83
84    /// Apply profile to configuration
85    pub fn apply(&self, config: &mut Config) {
86        match self {
87            Profile::Server => {
88                // Disable local discovery
89                config.discovery = Discovery {
90                    mdns: Mdns { enabled: false },
91                };
92                // Increase connection limits
93                config.swarm.conn_mgr = ConnMgr {
94                    low_water: Some(OptionalInteger(Some(100))),
95                    high_water: Some(OptionalInteger(Some(400))),
96                    grace_period: None,
97                    ..Default::default()
98                };
99            }
100            Profile::LocalDiscovery => {
101                config.discovery = Discovery {
102                    mdns: Mdns { enabled: true },
103                };
104            }
105            Profile::Test => {
106                // Disable discovery
107                config.discovery = Discovery {
108                    mdns: Mdns { enabled: false },
109                };
110                // Empty bootstrap
111                config.bootstrap = vec![];
112                // Reduce connection limits
113                config.swarm.conn_mgr = ConnMgr {
114                    low_water: Some(OptionalInteger(Some(2))),
115                    high_water: Some(OptionalInteger(Some(10))),
116                    ..Default::default()
117                };
118            }
119            Profile::Lowpower => {
120                // Reduce connection limits
121                config.swarm.conn_mgr = ConnMgr {
122                    low_water: Some(OptionalInteger(Some(20))),
123                    high_water: Some(OptionalInteger(Some(40))),
124                    ..Default::default()
125                };
126            }
127            Profile::AnnounceOff => {
128                // Add filter to block all announcements
129                config.addresses.no_announce = vec![
130                    "/ip4/0.0.0.0/ipcidr/0".to_string(),
131                    "/ip6/::/ipcidr/0".to_string(),
132                ];
133            }
134            Profile::AnnounceOn => {
135                // Clear no_announce filters
136                config.addresses.no_announce = vec![];
137            }
138            Profile::Randomports => {
139                // Use port 0 for random assignment
140                config.addresses.swarm = vec![
141                    "/ip4/0.0.0.0/tcp/0".to_string(),
142                    "/ip6/::/tcp/0".to_string(),
143                    "/ip4/0.0.0.0/udp/0/quic-v1".to_string(),
144                    "/ip6/::/udp/0/quic-v1".to_string(),
145                ];
146            }
147            Profile::LegacyCidV0 => {
148                config.import.cid_version = Some(OptionalInteger(Some(0)));
149            }
150            Profile::TestCidV1 => {
151                config.import.cid_version = Some(OptionalInteger(Some(1)));
152                config.import.unixfs_raw_leaves = Some(Flag::True);
153            }
154        }
155    }
156}
157
158/// List all available profiles
159pub fn list_profiles() -> Vec<Profile> {
160    vec![
161        Profile::Server,
162        Profile::LocalDiscovery,
163        Profile::Test,
164        Profile::Lowpower,
165        Profile::AnnounceOff,
166        Profile::AnnounceOn,
167        Profile::Randomports,
168        Profile::LegacyCidV0,
169        Profile::TestCidV1,
170    ]
171}
172
173#[cfg(test)]
174mod tests {
175    use super::*;
176
177    #[test]
178    fn test_profile_from_name() {
179        assert_eq!(Profile::from_name("server"), Some(Profile::Server));
180        assert_eq!(Profile::from_name("test"), Some(Profile::Test));
181        assert_eq!(Profile::from_name("unknown"), None);
182    }
183
184    #[test]
185    fn test_profile_apply_server() {
186        let mut config = Config::default();
187        Profile::Server.apply(&mut config);
188        assert!(!config.discovery.mdns.enabled);
189    }
190
191    #[test]
192    fn test_profile_apply_test() {
193        let mut config = Config::default();
194        Profile::Test.apply(&mut config);
195        assert!(config.bootstrap.is_empty());
196    }
197
198    #[test]
199    fn test_list_profiles() {
200        let profiles = list_profiles();
201        assert!(profiles.len() >= 8);
202    }
203}