A library for ATProtocol identities.
1//! Configuration management for AT Protocol identity operations.
2//!
3//! Environment variable utilities, DNS nameserver configuration, and TLS certificate
4//! bundle management with structured error handling.
5
6use crate::errors::ConfigError;
7use anyhow::Result;
8
9/// Certificate bundle paths for TLS verification.
10/// Contains a collection of file paths to certificate bundles.
11#[derive(Clone)]
12pub struct CertificateBundles(Vec<String>);
13
14/// DNS nameserver IP addresses for domain resolution.
15/// Contains a collection of IP addresses for custom DNS resolution.
16#[derive(Clone)]
17pub struct DnsNameservers(Vec<std::net::IpAddr>);
18
19/// Gets a required environment variable value.
20/// Returns an error if the variable is not set.
21pub fn require_env(name: &str) -> Result<String, ConfigError> {
22 std::env::var(name).map_err(|_| ConfigError::MissingEnvironmentVariable {
23 name: name.to_string(),
24 })
25}
26
27/// Gets an optional environment variable value.
28/// Returns empty string if the variable is not set.
29pub fn optional_env(name: &str) -> String {
30 std::env::var(name).unwrap_or("".to_string())
31}
32
33/// Gets an environment variable value with a fallback default.
34/// Returns the default value if the variable is not set.
35pub fn default_env(name: &str, default_value: &str) -> String {
36 std::env::var(name).unwrap_or(default_value.to_string())
37}
38
39/// Gets the application version from git hash or package version.
40/// Returns the git hash if available, otherwise falls back to cargo package version.
41pub fn version() -> Result<String, ConfigError> {
42 option_env!("GIT_HASH")
43 .or(option_env!("CARGO_PKG_VERSION"))
44 .map(|val| val.to_string())
45 .ok_or(ConfigError::VersionNotAvailable)
46}
47
48impl TryFrom<String> for CertificateBundles {
49 type Error = anyhow::Error;
50 fn try_from(value: String) -> Result<Self, Self::Error> {
51 Ok(Self(
52 value
53 .split(';')
54 .filter_map(|s| {
55 if s.is_empty() {
56 None
57 } else {
58 Some(s.to_string())
59 }
60 })
61 .collect::<Vec<String>>(),
62 ))
63 }
64}
65impl AsRef<Vec<String>> for CertificateBundles {
66 fn as_ref(&self) -> &Vec<String> {
67 &self.0
68 }
69}
70
71impl TryFrom<String> for DnsNameservers {
72 type Error = anyhow::Error;
73 fn try_from(value: String) -> Result<Self, Self::Error> {
74 // Allow empty value for default DNS configuration
75 if value.is_empty() {
76 return Ok(Self(Vec::new()));
77 }
78
79 let nameservers = value
80 .split(';')
81 .map(|s| s.trim())
82 .filter(|s| !s.is_empty())
83 .map(|s| {
84 s.parse::<std::net::IpAddr>().map_err(|_| {
85 anyhow::Error::from(ConfigError::InvalidNameserverIP {
86 value: s.to_string(),
87 })
88 })
89 })
90 .collect::<Result<Vec<std::net::IpAddr>, _>>()?;
91
92 Ok(Self(nameservers))
93 }
94}
95
96impl AsRef<Vec<std::net::IpAddr>> for DnsNameservers {
97 fn as_ref(&self) -> &Vec<std::net::IpAddr> {
98 &self.0
99 }
100}