shoal_core/server/
conf.rs1use std::{path::PathBuf, str::FromStr};
4
5use config::{Config, ConfigError};
6use glommio::{
7 io::{DmaFile, DmaStreamReaderBuilder, DmaStreamWriter, DmaStreamWriterBuilder, OpenOptions},
8 CpuSet,
9};
10use serde::{Deserialize, Serialize};
11use tracing::level_filters::LevelFilter;
12use uuid::Uuid;
13
14use super::ServerError;
15
16#[derive(Serialize, Deserialize, Default, Clone)]
18pub struct Compute {
19 cores: Option<usize>,
21 memory: Option<usize>,
23}
24
25impl Compute {
26 pub fn cpus(&self) -> Result<CpuSet, ServerError> {
28 let online = CpuSet::online()?;
30 if let Some(cores) = self.cores {
32 let cores = online.into_iter().take(cores).collect::<CpuSet>();
34 Ok(cores)
35 } else {
36 Ok(online)
37 }
38 }
39}
40
41fn default_interface() -> String {
43 "127.0.0.1".to_owned()
44}
45
46fn default_port() -> usize {
48 12000
49}
50
51#[derive(Serialize, Deserialize, Clone)]
53pub struct Networking {
54 #[serde(default = "default_interface")]
56 pub interface: String,
57 #[serde(default = "default_port")]
59 pub port: usize,
60}
61
62impl Default for Networking {
63 fn default() -> Self {
65 Networking {
66 interface: default_interface(),
67 port: default_port(),
68 }
69 }
70}
71
72impl Networking {
73 pub fn to_addr(&self) -> String {
75 println!("listening on {}:{}", self.interface, self.port);
76 format!("{}:{}", self.interface, self.port)
77 }
78}
79
80fn default_fs_intent_path() -> PathBuf {
82 PathBuf::from_str("/opt/shoal/intents")
83 .expect("Failed to build default filesystem storage path")
84}
85
86fn default_fs_archives_path() -> PathBuf {
88 PathBuf::from_str("/opt/shoal/archives")
89 .expect("Failed to build default filesystem storage path")
90}
91
92fn default_fs_map_path() -> PathBuf {
94 PathBuf::from_str("/opt/shoal/maps").expect("Failed to build default filesystem storage path")
95}
96
97#[derive(Serialize, Deserialize, Clone)]
99pub struct FileSystemStorage {
100 #[serde(default = "default_fs_intent_path")]
102 pub intent: PathBuf,
103 #[serde(default = "default_fs_archives_path")]
105 pub archives: PathBuf,
106 #[serde(default = "default_fs_map_path")]
108 pub maps: PathBuf,
109}
110
111impl Default for FileSystemStorage {
112 fn default() -> Self {
113 FileSystemStorage {
114 intent: default_fs_intent_path(),
115 archives: default_fs_archives_path(),
116 maps: default_fs_map_path(),
117 }
118 }
119}
120
121impl FileSystemStorage {
122 pub async fn get_new_archive_path(
124 &self,
125 ) -> Result<(Uuid, DmaFile, DmaStreamWriter), ServerError> {
126 let mut path = self.archives.clone();
128 let id = Uuid::new_v4();
130 path.push(id.to_string());
132 let file = OpenOptions::new()
134 .create_new(true)
135 .read(true)
136 .write(true)
137 .dma_open(&path)
138 .await?;
139 let writer = DmaStreamWriterBuilder::new(file.dup()?).build();
141 Ok((id, file, writer))
142 }
143
144 pub fn get_archive_path(&self, id: &Uuid) -> PathBuf {
150 let mut path = self.archives.clone();
152 path.push(id.to_string());
154 path
155 }
156
157 pub fn get_archive_intent_path(&self, shard_name: &str) -> PathBuf {
159 let mut path = self.maps.clone();
161 path.push(format!("{}-intents", &shard_name));
163 path
164 }
165
166 pub fn get_temp_archive_intent_path(&self, shard_name: &str) -> PathBuf {
168 let mut path = self.maps.clone();
170 path.push(format!("{}-intents-temp", &shard_name));
172 path
173 }
174
175 pub fn get_temp_archive_map_path(&self, shard_name: &str) -> PathBuf {
177 let mut path = self.maps.clone();
179 path.push(format!("{shard_name}-temp"));
181 path
182 }
183
184 pub fn get_archive_map_path(&self, shard_name: &str) -> PathBuf {
186 let mut path = self.maps.clone();
188 path.push(format!("{shard_name}"));
190 path
191 }
192}
193
194#[derive(Serialize, Deserialize, Clone, Default)]
196pub struct Storage {
197 #[serde(default)]
199 pub fs: FileSystemStorage,
200}
201
202#[derive(Serialize, Deserialize, Clone, Default)]
204pub enum TraceLevel {
205 Trace,
207 Debug,
209 #[default]
211 Info,
212 Warn,
214 Error,
216 Off,
218}
219
220impl TraceLevel {
221 pub fn to_filter(&self) -> LevelFilter {
223 match self {
224 TraceLevel::Trace => LevelFilter::TRACE,
225 TraceLevel::Debug => LevelFilter::DEBUG,
226 TraceLevel::Info => LevelFilter::INFO,
227 TraceLevel::Warn => LevelFilter::WARN,
228 TraceLevel::Error => LevelFilter::ERROR,
229 TraceLevel::Off => LevelFilter::OFF,
230 }
231 }
232}
233
234#[derive(Serialize, Deserialize, Clone, Default)]
236pub struct Tracing {
237 #[serde(default)]
239 pub level: TraceLevel,
240}
241
242#[derive(Serialize, Deserialize, Clone)]
244pub struct Conf {
245 #[serde(default)]
247 pub compute: Compute,
248 #[serde(default)]
250 pub networking: Networking,
251 #[serde(default)]
253 pub storage: Storage,
254 #[serde(default)]
256 pub tracing: Tracing,
257}
258
259impl Conf {
260 pub fn new(path: &str) -> Result<Self, ConfigError> {
262 let conf = Config::builder()
264 .add_source(config::File::with_name(path).required(false))
266 .add_source(config::Environment::with_prefix("shoal"))
268 .build()?;
269 conf.try_deserialize()
270 }
271}