cdk_mintd/env_vars/
mod.rs1#![allow(missing_docs)]
2mod common;
8mod database;
9mod info;
10mod limits;
11mod ln;
12mod mint_info;
13mod onchain;
14
15mod auth;
16#[cfg(feature = "bdk")]
17mod bdk;
18#[cfg(feature = "cln")]
19mod cln;
20#[cfg(feature = "fakewallet")]
21mod fake_wallet;
22#[cfg(feature = "grpc-processor")]
23mod grpc_processor;
24#[cfg(feature = "ldk-node")]
25mod ldk_node;
26#[cfg(feature = "lnbits")]
27mod lnbits;
28#[cfg(feature = "lnd")]
29mod lnd;
30#[cfg(feature = "management-rpc")]
31mod management_rpc;
32#[cfg(feature = "prometheus")]
33mod prometheus;
34
35use std::env;
36use std::str::FromStr;
37
38use anyhow::{anyhow, bail, Result};
39pub use auth::*;
40#[cfg(feature = "bdk")]
41pub use bdk::*;
42#[cfg(feature = "cln")]
43pub use cln::*;
44pub use common::*;
45pub use database::*;
46#[cfg(feature = "fakewallet")]
47pub use fake_wallet::*;
48#[cfg(feature = "grpc-processor")]
49pub use grpc_processor::*;
50#[cfg(feature = "ldk-node")]
51pub use ldk_node::*;
52pub use limits::*;
53pub use ln::*;
54#[cfg(feature = "lnbits")]
55pub use lnbits::*;
56#[cfg(feature = "lnd")]
57pub use lnd::*;
58#[cfg(feature = "management-rpc")]
59pub use management_rpc::*;
60pub use mint_info::*;
61pub use onchain::*;
62#[cfg(feature = "prometheus")]
63pub use prometheus::*;
64
65use crate::config::{DatabaseEngine, Ln, LnBackend, OnchainBackend, Settings};
66
67impl Settings {
68 pub fn from_env(&mut self) -> Result<Self> {
69 if let Ok(database) = env::var(DATABASE_ENV_VAR) {
70 let engine = DatabaseEngine::from_str(&database).map_err(|err| anyhow!(err))?;
71 self.database.engine = engine;
72 }
73
74 if self.database.engine == DatabaseEngine::Postgres {
76 self.database.postgres = Some(
77 self.database
78 .postgres
79 .clone()
80 .unwrap_or_default()
81 .from_env(),
82 );
83 }
84
85 self.auth_database = Some(crate::config::AuthDatabase {
87 postgres: Some(
88 self.auth_database
89 .clone()
90 .unwrap_or_default()
91 .postgres
92 .unwrap_or_default()
93 .from_env(),
94 ),
95 });
96
97 self.info = self.info.clone().from_env();
98 self.mint_info = self.mint_info.clone().from_env();
99 match self.ln.len() {
103 0 => {
104 let ln = Ln::default().from_env();
105 if ln.ln_backend != LnBackend::None {
106 self.ln.push(ln);
107 }
108 }
109 1 => {
110 self.ln[0] = self.ln[0].clone().from_env();
111 }
112 _ => {
113 tracing::warn!(
114 "CDK_MINTD_LN_* environment variables ignored: multiple [[ln]] entries configured"
115 );
116 }
117 }
118 self.onchain = Some(self.onchain.clone().unwrap_or_default().from_env());
119 self.limits = self.limits.clone().from_env();
120
121 {
122 let auth = self.auth.clone().unwrap_or_default().from_env();
124
125 if auth.auth_enabled {
127 self.auth = Some(auth);
128 } else {
129 self.auth = None;
130 }
131 }
132
133 #[cfg(feature = "management-rpc")]
134 {
135 self.mint_management_rpc = Some(
136 self.mint_management_rpc
137 .clone()
138 .unwrap_or_default()
139 .from_env(),
140 );
141 }
142
143 #[cfg(feature = "prometheus")]
144 {
145 self.prometheus = Some(self.prometheus.clone().unwrap_or_default().from_env());
146 }
147
148 #[cfg(feature = "cln")]
149 {
150 let cln = self.cln.clone().unwrap_or_default().from_env();
151 if cln.rpc_path.as_os_str().is_empty() {
152 self.cln = None;
153 } else {
154 self.cln = Some(cln);
155 }
156 }
157
158 #[cfg(feature = "lnbits")]
159 {
160 let lnbits = self.lnbits.clone().unwrap_or_default().from_env();
161 if lnbits.admin_api_key.is_empty() {
162 self.lnbits = None;
163 } else {
164 self.lnbits = Some(lnbits);
165 }
166 }
167
168 #[cfg(feature = "fakewallet")]
169 {
170 let fake_wallet_supported_units_from_env =
172 env::var(ENV_FAKE_WALLET_SUPPORTED_UNITS).is_ok();
173 let fake_wallet = self.fake_wallet.clone().unwrap_or_default().from_env();
174 let supported_units_configured =
175 fake_wallet.supported_units != vec![cdk::nuts::CurrencyUnit::Sat];
176
177 if fake_wallet_supported_units_from_env || supported_units_configured {
178 self.expand_single_fake_wallet_ln_entry(&fake_wallet);
179 }
180
181 self.fake_wallet = Some(fake_wallet);
182 }
183
184 #[cfg(feature = "lnd")]
185 {
186 let lnd = self.lnd.clone().unwrap_or_default().from_env();
187 if lnd.address.is_empty() {
188 self.lnd = None;
189 } else {
190 self.lnd = Some(lnd);
191 }
192 }
193
194 #[cfg(feature = "ldk-node")]
195 {
196 let ldk_node = self.ldk_node.clone().unwrap_or_default().from_env();
197 if ldk_node.bitcoin_network.is_none() && ldk_node.esplora_url.is_none() {
198 self.ldk_node = None;
199 } else {
200 self.ldk_node = Some(ldk_node);
201 }
202 }
203
204 #[cfg(feature = "grpc-processor")]
205 {
206 let grpc_processor = self.grpc_processor.clone().unwrap_or_default().from_env();
207 let grpc_processor_configured = self
208 .ln
209 .iter()
210 .any(|ln| ln.ln_backend == LnBackend::GrpcProcessor);
211 if grpc_processor.supported_units.is_empty() && !grpc_processor_configured {
212 self.grpc_processor = None;
213 } else {
214 self.grpc_processor = Some(grpc_processor);
215 }
216 }
217
218 #[cfg(feature = "bdk")]
219 {
220 let bdk = self.bdk.clone().unwrap_or_default().from_env();
221 if bdk.network.is_none() && bdk.mnemonic.is_none() {
222 self.bdk = None;
223 } else {
224 self.bdk = Some(bdk);
225 }
226 }
227
228 for ln in &self.ln {
229 match ln.ln_backend {
230 #[cfg(feature = "cln")]
231 LnBackend::Cln => {}
232 #[cfg(feature = "lnbits")]
233 LnBackend::LNbits => {}
234 #[cfg(feature = "fakewallet")]
235 LnBackend::FakeWallet => {}
236 #[cfg(feature = "lnd")]
237 LnBackend::Lnd => {}
238 #[cfg(feature = "ldk-node")]
239 LnBackend::LdkNode => {}
240 #[cfg(feature = "grpc-processor")]
241 LnBackend::GrpcProcessor => {}
242 LnBackend::None => {}
243 #[allow(unreachable_patterns)]
244 _ => bail!("Selected Ln backend is not enabled in this build"),
245 }
246 }
247
248 let has_lightning_backend = self.ln.iter().any(|ln| ln.ln_backend != LnBackend::None);
249 let has_onchain_backend = self
250 .onchain
251 .as_ref()
252 .map(|onchain| onchain.onchain_backend != OnchainBackend::None)
253 .unwrap_or(false);
254 if !has_lightning_backend && !has_onchain_backend {
255 bail!("At least one payment backend (Lightning or On-chain) must be set");
256 }
257
258 self.validate_backend_pairing()
259 .map_err(|err| anyhow!(err))?;
260
261 Ok(self.clone())
262 }
263
264 #[cfg(feature = "fakewallet")]
265 fn expand_single_fake_wallet_ln_entry(&mut self, fake_wallet: &crate::config::FakeWallet) {
266 let fake_wallet_ln_index = self
267 .ln
268 .iter()
269 .enumerate()
270 .filter_map(|(index, ln)| (ln.ln_backend == LnBackend::FakeWallet).then_some(index))
271 .collect::<Vec<_>>();
272
273 if fake_wallet_ln_index.len() != 1 {
274 return;
275 }
276
277 let mut units = Vec::new();
278 for unit in &fake_wallet.supported_units {
279 if !units.contains(unit) {
280 units.push(unit.clone());
281 }
282 }
283
284 if units.is_empty() {
285 return;
286 }
287
288 let index = fake_wallet_ln_index[0];
289 let base_ln = self.ln[index].clone();
290 let expanded_ln = units.into_iter().map(|unit| Ln {
291 unit,
292 ..base_ln.clone()
293 });
294
295 self.ln.splice(index..=index, expanded_ln);
296 }
297}