solid_pod_rs_forge/
config.rs1#[derive(Debug, Clone)]
9pub struct ForgeConfig {
10 pub prefix: String,
13 pub token_ttl_secs: u64,
15 pub max_body_bytes: usize,
18 pub fetch_concurrency: usize,
20 pub fetch_timeout_secs: u64,
22 pub thread_cap: usize,
24 pub default_chain: String,
28 pub allow_mainnet: bool,
31 pub announce_relays: Vec<String>,
34}
35
36impl Default for ForgeConfig {
37 fn default() -> Self {
38 Self {
39 prefix: "/forge".to_string(),
40 token_ttl_secs: 3600,
41 max_body_bytes: 64 * 1024,
42 fetch_concurrency: 8,
43 fetch_timeout_secs: 8,
44 thread_cap: 500,
45 default_chain: "tbtc4".to_string(),
46 allow_mainnet: false,
47 announce_relays: Vec::new(),
48 }
49 }
50}
51
52const MAINNET_ALIASES: &[&str] = &["btc", "bitcoin", "mainnet", "main"];
55
56impl ForgeConfig {
57 #[must_use]
61 pub fn normalized_prefix(&self) -> String {
62 let trimmed = self.prefix.trim_matches('/');
63 if trimmed.is_empty() {
64 String::new()
65 } else {
66 format!("/{trimmed}")
67 }
68 }
69
70 #[must_use]
73 pub fn chain_allowed(&self, chain: &str) -> bool {
74 let lc = chain.to_ascii_lowercase();
75 if MAINNET_ALIASES.contains(&lc.as_str()) {
76 self.allow_mainnet
77 } else {
78 true
79 }
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn defaults_are_testnet_and_bounded() {
89 let c = ForgeConfig::default();
90 assert_eq!(c.prefix, "/forge");
91 assert_eq!(c.default_chain, "tbtc4");
92 assert!(!c.allow_mainnet);
93 assert_eq!(c.max_body_bytes, 64 * 1024);
94 assert_eq!(c.thread_cap, 500);
95 assert_eq!(c.fetch_concurrency, 8);
96 }
97
98 #[test]
99 fn mainnet_guard_fails_closed() {
100 let c = ForgeConfig::default();
101 for m in ["btc", "BTC", "Bitcoin", "mainnet", "main"] {
102 assert!(!c.chain_allowed(m), "{m} must be refused by default");
103 }
104 assert!(c.chain_allowed("tbtc4"));
105 assert!(c.chain_allowed("testnet"));
106 assert!(c.chain_allowed("signet"));
107 }
108
109 #[test]
110 fn mainnet_guard_opens_when_allowed() {
111 let c = ForgeConfig {
112 allow_mainnet: true,
113 ..Default::default()
114 };
115 assert!(c.chain_allowed("btc"));
116 assert!(c.chain_allowed("mainnet"));
117 }
118
119 #[test]
120 fn prefix_normalisation() {
121 let mk = |p: &str| ForgeConfig {
122 prefix: p.to_string(),
123 ..Default::default()
124 };
125 assert_eq!(mk("/forge").normalized_prefix(), "/forge");
126 assert_eq!(mk("forge").normalized_prefix(), "/forge");
127 assert_eq!(mk("/forge/").normalized_prefix(), "/forge");
128 assert_eq!(mk("/git/forge/").normalized_prefix(), "/git/forge");
129 assert_eq!(mk("/").normalized_prefix(), "");
130 assert_eq!(mk("").normalized_prefix(), "");
131 }
132}