Skip to main content

rings_node/native/
config.rs

1use std::env;
2use std::fs;
3use std::io;
4use std::path::PathBuf;
5
6use serde::Deserialize;
7use serde::Serialize;
8
9use crate::error::Error;
10use crate::error::Result;
11use crate::prelude::rings_core::ecc::SecretKey;
12use crate::prelude::SessionSk;
13use crate::processor::ProcessorConfig;
14use crate::processor::ProcessorConfigSerialized;
15use crate::util::ensure_parent_dir;
16use crate::util::expand_home;
17
18lazy_static::lazy_static! {
19  static ref DEFAULT_DATA_STORAGE_CONFIG: StorageConfig = StorageConfig {
20    path: get_storage_location(".rings", "data"),
21    capacity: DEFAULT_STORAGE_CAPACITY,
22  };
23  static ref DEFAULT_MEASURE_STORAGE_CONFIG: StorageConfig = StorageConfig {
24    path: get_storage_location(".rings", "measure"),
25    capacity: DEFAULT_STORAGE_CAPACITY,
26  };
27}
28
29pub const DEFAULT_NETWORK_ID: u32 = 1;
30pub const DEFAULT_INTERNAL_API_PORT: u16 = 50000;
31pub const DEFAULT_EXTERNAL_API_ADDR: &str = "127.0.0.1:50001";
32pub const DEFAULT_ENDPOINT_URL: &str = "http://127.0.0.1:50000";
33pub const DEFAULT_ICE_SERVERS: &str = "stun://stun.l.google.com:19302";
34pub const DEFAULT_STABILIZE_INTERVAL: u64 = 3;
35pub const DEFAULT_STORAGE_CAPACITY: u32 = 200000000;
36
37pub fn get_storage_location<P>(prefix: P, path: P) -> String
38where P: AsRef<std::path::Path> {
39    let home_dir = env::var_os("HOME").map(PathBuf::from);
40    let expect = match home_dir {
41        Some(dir) => dir.join(prefix).join(path),
42        None => std::path::Path::new("data").join(prefix).join(path),
43    };
44    expect.to_str().unwrap().to_string()
45}
46
47#[derive(Debug, Clone, Deserialize, Serialize)]
48pub struct Config {
49    pub network_id: u32,
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub ecdsa_key: Option<SecretKey>,
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub session_manager: Option<String>,
54    pub session_sk: Option<String>,
55    pub internal_api_port: u16,
56    pub external_api_addr: String,
57    pub endpoint_url: String,
58    pub ice_servers: String,
59    pub stabilize_interval: u64,
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub external_ip: Option<String>,
62    pub data_storage: StorageConfig,
63    pub measure_storage: StorageConfig,
64}
65
66impl TryFrom<Config> for ProcessorConfigSerialized {
67    type Error = Error;
68    fn try_from(config: Config) -> Result<Self> {
69        // Support old version
70        let session_sk: String = if let Some(sk) = config.ecdsa_key {
71            tracing::warn!("Field `ecdsa_key` is deprecated, use `session_sk` instead.");
72            SessionSk::new_with_seckey(&sk)
73                .expect("create session sk failed")
74                .dump()
75                .expect("dump session sk failed")
76        } else if let Some(ssk) = config.session_manager {
77            tracing::warn!("Field `session_manager` is deprecated, use `session_sk` instead.");
78            ssk
79        } else {
80            let ssk_file = config.session_sk.expect("session_sk is not set.");
81            let ssk_file_expand_home = expand_home(&ssk_file)?;
82            fs::read_to_string(ssk_file_expand_home).unwrap_or_else(|e| {
83                tracing::warn!("Read session_sk file failed: {e:?}. Handling it as raw session_sk string. This mode is deprecated. please use a file path.");
84                ssk_file
85            })
86        };
87
88        let mut cs = Self::new(
89            config.network_id,
90            config.ice_servers,
91            session_sk,
92            config.stabilize_interval,
93        );
94
95        cs = if let Some(ext_ip) = config.external_ip {
96            cs.external_address(ext_ip)
97        } else {
98            cs
99        };
100
101        Ok(cs)
102    }
103}
104
105impl TryFrom<Config> for ProcessorConfig {
106    type Error = Error;
107    fn try_from(config: Config) -> Result<Self> {
108        ProcessorConfigSerialized::try_from(config).and_then(Self::try_from)
109    }
110}
111
112impl Config {
113    pub fn new<P>(session_sk: P) -> Self
114    where P: AsRef<std::path::Path> {
115        let session_sk = session_sk.as_ref().to_string_lossy().to_string();
116        Self {
117            network_id: DEFAULT_NETWORK_ID,
118            ecdsa_key: None,
119            session_manager: None,
120            session_sk: Some(session_sk),
121            internal_api_port: DEFAULT_INTERNAL_API_PORT,
122            external_api_addr: DEFAULT_EXTERNAL_API_ADDR.to_string(),
123            endpoint_url: DEFAULT_ENDPOINT_URL.to_string(),
124            ice_servers: DEFAULT_ICE_SERVERS.to_string(),
125            stabilize_interval: DEFAULT_STABILIZE_INTERVAL,
126            external_ip: None,
127            data_storage: DEFAULT_DATA_STORAGE_CONFIG.clone(),
128            measure_storage: DEFAULT_MEASURE_STORAGE_CONFIG.clone(),
129        }
130    }
131
132    pub fn write_fs<P>(&self, path: P) -> Result<String>
133    where P: AsRef<std::path::Path> {
134        let path = expand_home(path)?;
135        ensure_parent_dir(&path)?;
136        let f =
137            fs::File::create(path.as_path()).map_err(|e| Error::CreateFileError(e.to_string()))?;
138        let f_writer = io::BufWriter::new(f);
139        serde_yaml::to_writer(f_writer, self).map_err(|_| Error::EncodeError)?;
140        Ok(path.to_str().unwrap().to_owned())
141    }
142
143    pub fn read_fs<P>(path: P) -> Result<Config>
144    where P: AsRef<std::path::Path> {
145        let path = expand_home(path)?;
146        tracing::debug!("Read config from: {:?}", path);
147        let f = fs::File::open(path).map_err(|e| Error::OpenFileError(e.to_string()))?;
148        let f_rdr = io::BufReader::new(f);
149        serde_yaml::from_reader(f_rdr).map_err(|_| Error::EncodeError)
150    }
151}
152
153#[derive(Debug, Clone, Deserialize, Serialize)]
154pub struct StorageConfig {
155    pub path: String,
156    pub capacity: u32,
157}
158
159impl StorageConfig {
160    pub fn new(path: &str, capacity: u32) -> Self {
161        Self {
162            path: path.to_string(),
163            capacity,
164        }
165    }
166}
167
168#[cfg(test)]
169mod tests {
170    use super::*;
171
172    #[test]
173    fn test_deserialization_with_missed_field() {
174        let yaml = r#"
175network_id: 1
176session_sk: session_sk
177internal_api_port: 50000
178external_api_addr: 127.0.0.1:50001
179endpoint_url: http://127.0.0.1:50000
180ice_servers: stun://stun.l.google.com:19302
181stabilize_interval: 3
182external_ip: null
183data_storage:
184  path: /Users/foo/.rings/data
185  capacity: 200000000
186measure_storage:
187  path: /Users/foo/.rings/measure
188  capacity: 200000000
189"#;
190        let cfg: Config = serde_yaml::from_str(yaml).unwrap();
191        assert_eq!(cfg.network_id, 1);
192    }
193}