switchboard_container_utils/
env.rs

1use std::sync::OnceLock;
2
3use serde::Deserialize;
4use std::{fs, sync::Arc};
5use switchboard_common::SbError;
6
7pub fn get_qvn_env() -> &'static QvnEnvironment {
8    static ENV: OnceLock<QvnEnvironment> = OnceLock::new();
9    ENV.get_or_init(|| QvnEnvironment::parse().unwrap())
10}
11
12fn default_heartbeat_interval() -> i64 {
13    30
14}
15fn default_mode() -> String {
16    "default".to_string()
17}
18
19fn read_and_trim_file(file_path: &str) -> Result<String, SbError> {
20    // Check if the file exists
21    if !std::path::Path::new(file_path).exists() {
22        return Err(SbError::CustomError {
23            message: "File not found".to_string(),
24            source: Arc::new(std::io::Error::new(
25                std::io::ErrorKind::NotFound,
26                format!("File not found: {}", file_path),
27            )),
28        });
29    }
30
31    // Read the file to a String
32    let content = fs::read_to_string(file_path).map_err(|e| SbError::CustomError {
33        message: "Failed to read file".to_string(),
34        source: Arc::new(e),
35    })?;
36
37    // Trim the content and return it
38    Ok(content.trim().to_string())
39}
40
41#[derive(Deserialize, Debug, Default)]
42#[serde(default)]
43pub struct QvnEnvironment {
44    pub chain: String,
45    pub chain_id: String, // will convert to u64 basedon CHAIN
46    pub quote_key: String,
47    pub rpc_url: String,
48    #[serde(default = "default_heartbeat_interval")]
49    pub heartbeat_interval: i64,
50
51    #[serde(default = "default_mode")]
52    pub mode: String,
53
54    // Required to post a quote for verification
55    pub ipfs_url: String,
56    pub ipfs_key: String,
57    pub ipfs_secret: String,
58
59    #[serde(default)]
60    pub queue: String, // optional
61
62    // One of the keypair configs required
63    #[serde(default)]
64    pub payer_secret: String,
65    #[serde(default)]
66    pub fs_payer_secret_path: String,
67    #[serde(default)]
68    pub google_payer_secret_path: String,
69    #[serde(default)]
70    pub google_application_credentials: String,
71
72    // EVM
73    #[serde(default)]
74    pub contract_address: String, // evm only
75    #[serde(default)]
76    pub funding_threshold: String, // evm only
77    #[serde(default)]
78    pub funding_amount: String, // evm only
79}
80impl QvnEnvironment {
81    pub fn parse() -> Result<Self, SbError> {
82        match envy::from_env::<QvnEnvironment>() {
83            Ok(env) => Ok(env),
84            Err(error) => Err(SbError::CustomMessage(format!(
85                "failed to decode environment variables: {}",
86                error
87            ))),
88        }
89    }
90
91    pub fn get_payer(&self) -> Result<String, SbError> {
92        if !self.payer_secret.is_empty() {
93            return Ok(self.payer_secret.clone().trim().to_string());
94        }
95
96        if !self.fs_payer_secret_path.is_empty() {
97            return read_and_trim_file(&self.fs_payer_secret_path);
98        }
99
100        Ok(String::new())
101    }
102}
103
104impl std::fmt::Display for QvnEnvironment {
105    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106        write!(f, "=====Node Environment=====\n")?;
107        write!(f, "CHAIN:                    {}\n", self.chain)?;
108        write!(f, "RPC_URL:                  {}\n", self.rpc_url)?;
109
110        if self.queue.len() != 0 {
111            write!(f, "QUEUE:                    {}\n", self.queue)?;
112        }
113        write!(f, "QUOTE:                    {}\n", self.quote_key)?;
114        write!(
115            f,
116            "GOOGLE_PAYER_SECRET_PATH: {}\n",
117            self.google_payer_secret_path
118        )?;
119        write!(f, "CONTRACT_ADDRESS:         {}\n", self.contract_address)?;
120        write!(f, "CHAIN_ID:                 {}\n", self.chain_id)?;
121        write!(f, "FUNDING_THRESHOLD:        {}\n", self.funding_threshold)?;
122        write!(f, "FUNDING_AMOUNT:           {}\n", self.funding_amount)?;
123        write!(f, "=========================\n")?;
124        Ok(())
125    }
126}