secop_core/
config.rs

1// -----------------------------------------------------------------------------
2// Rust SECoP playground
3//
4// This program is free software; you can redistribute it and/or modify it under
5// the terms of the GNU General Public License as published by the Free Software
6// Foundation; either version 2 of the License, or (at your option) any later
7// version.
8//
9// This program is distributed in the hope that it will be useful, but WITHOUT
10// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
12// details.
13//
14// You should have received a copy of the GNU General Public License along with
15// this program; if not, write to the Free Software Foundation, Inc.,
16// 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17//
18// Module authors:
19//   Georg Brandl <g.brandl@fz-juelich.de>
20//
21// -----------------------------------------------------------------------------
22//
23//! Configuration file handling.
24
25use std::path::Path;
26use hashbrown::{HashMap, HashSet};
27use serde_derive::{Serialize, Deserialize};
28use serde_json::Value;
29use toml;
30
31use crate::types::TypeDesc;
32
33
34#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
35#[serde(rename_all = "lowercase")]
36pub enum Visibility {
37    None,
38    User,
39    Advanced,
40    Expert,
41}
42
43impl Default for Visibility {
44    fn default() -> Self { Visibility::User }
45}
46
47#[derive(Deserialize, Debug)]
48pub struct ServerConfig {
49    #[serde(skip)] // provided by us
50    pub equipment_id: String,
51    pub description: String,
52    pub modules: HashMap<String, ModuleConfig>,
53}
54
55#[derive(Deserialize, Debug, Clone)]
56pub struct ModuleConfig {
57    pub class: String,
58    pub description: String,
59    pub group: Option<String>,
60    #[serde(default)]
61    pub parameters: HashMap<String, Value>,
62    #[serde(default)]
63    pub visibility: Visibility,
64}
65
66
67pub fn load_config(filename: impl AsRef<Path>) -> Result<ServerConfig, String> {
68    let data = std::fs::read(&filename).map_err(|e| e.to_string())?;
69    let mut obj: ServerConfig = toml::from_slice(&data).map_err(|e| e.to_string())?;
70    obj.equipment_id = filename.as_ref()
71                               .file_stem()
72                               .map_or("unknown".into(), |s| s.to_string_lossy().into_owned());
73
74    // Check module names and groups for lowercase-uniqueness.
75    let mut lc_names = HashSet::new();
76    let mut lc_groups = HashSet::new();
77    for modcfg in obj.modules.values() {
78        if let Some(group) = modcfg.group.as_ref() {
79            lc_groups.insert(group.to_string());
80        }
81    }
82    for name in obj.modules.keys() {
83        let lc_name = name.to_lowercase();
84        if lc_groups.contains(&lc_name) || !lc_names.insert(lc_name) {
85            return Err(format!("module name {} is not unique amoung modules and groups", name))
86        }
87    }
88
89    // TODO: check presence of mandatory params
90
91    Ok(obj)
92}
93
94
95// TODO: check if this is necessary vs. initialized parameters
96impl ModuleConfig {
97    pub fn extract_param<T: TypeDesc>(&self, param: &str, td: &T) -> Option<T::Repr> {
98        self.parameters.get(param).and_then(|v| td.from_json(v).ok())
99    }
100}