rings_node/native/
config.rs1use 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 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}