blvm_sdk/composition/
config.rs1use crate::composition::types::*;
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::path::Path;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct NodeConfig {
13 #[serde(default)]
15 pub node: NodeMetadata,
16 #[serde(default)]
18 pub modules: HashMap<String, ModuleConfig>,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct NodeMetadata {
24 pub name: String,
26 #[serde(default)]
28 pub version: Option<String>,
29 pub network: String,
31}
32
33impl Default for NodeMetadata {
34 fn default() -> Self {
35 Self {
36 name: "custom-node".to_string(),
37 version: None,
38 network: "mainnet".to_string(),
39 }
40 }
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct ModuleConfig {
46 #[serde(default = "default_true")]
48 pub enabled: bool,
49 #[serde(default)]
51 pub version: Option<String>,
52 #[serde(default)]
54 pub config: HashMap<String, toml::Value>,
55}
56
57fn default_true() -> bool {
58 true
59}
60
61impl NodeConfig {
62 pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
64 let contents = std::fs::read_to_string(path.as_ref()).map_err(CompositionError::IoError)?;
65
66 let config: NodeConfig = toml::from_str(&contents).map_err(|e| {
67 CompositionError::InvalidConfiguration(format!("Failed to parse TOML: {e}"))
68 })?;
69
70 Ok(config)
71 }
72
73 pub fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
75 let toml_string = toml::to_string_pretty(self).map_err(|e| {
76 CompositionError::SerializationError(format!("Failed to serialize config: {e}"))
77 })?;
78
79 std::fs::write(path.as_ref(), toml_string).map_err(CompositionError::IoError)?;
80
81 Ok(())
82 }
83
84 pub fn to_spec(&self) -> Result<NodeSpec> {
86 let network = match self.node.network.as_str() {
87 "mainnet" => NetworkType::Mainnet,
88 "testnet" => NetworkType::Testnet,
89 "regtest" => NetworkType::Regtest,
90 _ => {
91 return Err(CompositionError::InvalidConfiguration(format!(
92 "Unknown network type: {}",
93 self.node.network
94 )))
95 }
96 };
97
98 let modules: Result<Vec<ModuleSpec>> = self
99 .modules
100 .iter()
101 .filter(|(_, cfg)| cfg.enabled)
102 .map(|(name, cfg)| {
103 let config: HashMap<String, serde_json::Value> = cfg
105 .config
106 .iter()
107 .map(|(k, v)| {
108 let json_value = toml_to_json_value(v);
109 (k.clone(), json_value)
110 })
111 .collect();
112
113 Ok(ModuleSpec {
114 name: name.clone(),
115 version: cfg.version.clone(),
116 enabled: cfg.enabled,
117 config,
118 })
119 })
120 .collect();
121
122 Ok(NodeSpec {
123 name: self.node.name.clone(),
124 version: self.node.version.clone(),
125 network,
126 modules: modules?,
127 })
128 }
129
130 pub fn template() -> Self {
132 let mut modules = HashMap::new();
133
134 modules.insert(
136 "lightning".to_string(),
137 ModuleConfig {
138 enabled: false,
139 version: Some("0.1.0".to_string()),
140 config: HashMap::new(),
141 },
142 );
143
144 modules.insert(
145 "privacy".to_string(),
146 ModuleConfig {
147 enabled: false,
148 version: Some("0.2.0".to_string()),
149 config: HashMap::new(),
150 },
151 );
152
153 Self {
154 node: NodeMetadata {
155 name: "my-custom-node".to_string(),
156 version: Some("1.0.0".to_string()),
157 network: "mainnet".to_string(),
158 },
159 modules,
160 }
161 }
162}
163
164fn toml_to_json_value(value: &toml::Value) -> serde_json::Value {
166 match value {
167 toml::Value::String(s) => serde_json::Value::String(s.clone()),
168 toml::Value::Integer(i) => serde_json::Value::Number((*i).into()),
169 toml::Value::Float(f) => serde_json::Value::Number(
170 serde_json::Number::from_f64(*f).unwrap_or_else(|| serde_json::Number::from(0)),
171 ),
172 toml::Value::Boolean(b) => serde_json::Value::Bool(*b),
173 toml::Value::Datetime(dt) => serde_json::Value::String(dt.to_string()),
174 toml::Value::Array(arr) => {
175 serde_json::Value::Array(arr.iter().map(toml_to_json_value).collect())
176 }
177 toml::Value::Table(table) => {
178 let map: serde_json::Map<String, serde_json::Value> = table
179 .iter()
180 .map(|(k, v)| (k.clone(), toml_to_json_value(v)))
181 .collect();
182 serde_json::Value::Object(map)
183 }
184 }
185}