Refactor to chain realm specific config to global config

Now if a variable is not set in a realm config file (or the file does
not exist), the 'global' config file will also be searched in the
parent directory (ie: /storage/realms/config). If the variable is
still not found, the value from the default instance is returned.
This commit is contained in:
Bruce Leidl 2019-01-30 14:09:34 -05:00
parent 6215b58167
commit 0b2480f849

View File

@ -1,112 +1,172 @@
use std::path::Path; use std::path::Path;
use std::fs::File; use std::fs;
use std::io::Read;
use toml; use toml;
use crate::Result;
fn default_true() -> bool { lazy_static! {
true pub static ref GLOBAL_CONFIG: RealmConfig = RealmConfig::load_global_config();
} }
fn default_zone() -> String { fn default_zone() -> String {
"clear".to_owned() "clear".to_owned()
} }
fn default_realmfs() -> String {
"base".to_owned()
}
#[derive (Deserialize,Clone)] #[derive (Deserialize,Clone)]
pub struct RealmConfig { pub struct RealmConfig {
#[serde(default = "default_true", rename="use-shared-dir")] #[serde(rename="use-shared-dir")]
use_shared_dir: bool, use_shared_dir: Option<bool>,
#[serde(default, rename="use-ephemeral-home")] #[serde(rename="use-ephemeral-home")]
use_ephemeral_home: bool, use_ephemeral_home: Option<bool>,
#[serde(default = "default_true", rename="use-sound")] #[serde(rename="use-sound")]
use_sound: bool, use_sound: Option<bool>,
#[serde(default = "default_true", rename="use-x11")] #[serde(rename="use-x11")]
use_x11: bool, use_x11: Option<bool>,
#[serde(default = "default_true", rename="use-wayland")] #[serde(rename="use-wayland")]
use_wayland: bool, use_wayland: Option<bool>,
#[serde(default, rename="use-kvm")] #[serde(rename="use-kvm")]
use_kvm: bool, use_kvm: Option<bool>,
#[serde(default,rename="use-gpu")] #[serde(rename="use-gpu")]
use_gpu: bool, use_gpu: Option<bool>,
#[serde(default = "default_true", rename="use-network")] #[serde(rename="use-network")]
use_network: bool, use_network: Option<bool>,
#[serde(rename="network-zone")]
network_zone: Option<String>,
realmfs: Option<String>,
#[serde(rename="realmfs-write")]
realmfs_write: Option<bool>,
#[serde(skip)]
parent: Option<Box<RealmConfig>>,
#[serde(default = "default_zone", rename="network-zone")]
network_zone: String,
} }
impl RealmConfig { impl RealmConfig {
pub fn load_or_default(path: &Path) -> Result<RealmConfig> {
if path.exists() { pub fn load_or_default<P: AsRef<Path>>(path: P) -> RealmConfig {
let s = load_as_string(&path)?; match RealmConfig::load_config(path) {
let config = toml::from_str::<RealmConfig>(&s)?; Some(config) => config,
Ok(config) None => GLOBAL_CONFIG.clone()
} else {
Ok(RealmConfig::default())
} }
} }
fn load_global_config() -> RealmConfig {
if let Some(mut global) = RealmConfig::load_config("/storage/realms/config") {
global.parent = Some(Box::new(RealmConfig::default()));
return global;
}
RealmConfig::default()
}
fn load_config<P: AsRef<Path>>(path: P) -> Option<RealmConfig> {
if path.as_ref().exists() {
match fs::read_to_string(path.as_ref()) {
Ok(s) => return toml::from_str::<RealmConfig>(&s).ok(),
Err(e) => warn!("Error reading config file: {}", e),
}
}
None
}
pub fn default() -> RealmConfig { pub fn default() -> RealmConfig {
RealmConfig { RealmConfig {
use_shared_dir: true, use_shared_dir: Some(true),
use_ephemeral_home: false, use_ephemeral_home: Some(false),
use_sound: true, use_sound: Some(true),
use_x11: true, use_x11: Some(true),
use_wayland: true, use_wayland: Some(true),
use_kvm: false, use_kvm: Some(false),
use_gpu: false, use_gpu: Some(false),
use_network: true, use_network: Some(true),
network_zone: default_zone(), network_zone: Some(default_zone()),
realmfs: Some(default_realmfs()),
realmfs_write: Some(false),
parent: None,
} }
} }
pub fn kvm(&self) -> bool { pub fn kvm(&self) -> bool {
self.use_kvm self.bool_value(|c| c.use_kvm)
} }
pub fn gpu(&self) -> bool { pub fn gpu(&self) -> bool {
self.use_gpu self.bool_value(|c| c.use_gpu)
} }
pub fn shared_dir(&self) -> bool { pub fn shared_dir(&self) -> bool {
self.use_shared_dir self.bool_value(|c| c.use_shared_dir)
} }
pub fn emphemeral_home(&self) -> bool { pub fn emphemeral_home(&self) -> bool {
self.use_ephemeral_home self.bool_value(|c| c.use_ephemeral_home)
} }
pub fn sound(&self) -> bool { pub fn sound(&self) -> bool {
self.use_sound self.bool_value(|c| c.use_sound)
} }
pub fn x11(&self) -> bool { pub fn x11(&self) -> bool {
self.use_x11 self.bool_value(|c| c.use_x11)
} }
pub fn wayland(&self) -> bool { pub fn wayland(&self) -> bool {
self.use_wayland self.bool_value(|c| c.use_network)
} }
pub fn network(&self) -> bool { pub fn network(&self) -> bool {
self.use_network self.bool_value(|c| c.use_network)
} }
pub fn network_zone(&self) -> &str { pub fn network_zone(&self) -> &str {
&self.network_zone self.str_value(|c| c.network_zone.as_ref())
}
pub fn realmfs(&self) -> &str {
self.str_value(|c| c.realmfs.as_ref())
}
pub fn realmfs_write(&self) -> bool {
self.bool_value(|c| c.realmfs_write)
}
fn str_value<F>(&self, get: F) -> &str
where F: Fn(&RealmConfig) -> Option<&String>
{
if let Some(ref val) = get(self) {
return val
}
if let Some(ref parent) = self.parent {
if let Some(val) = get(parent) {
return val;
}
}
""
}
fn bool_value<F>(&self, get: F) -> bool
where F: Fn(&RealmConfig) -> Option<bool>
{
if let Some(val) = get(self) {
return val
}
if let Some(ref parent) = self.parent {
return get(parent).unwrap_or(false);
}
false
} }
} }
fn load_as_string(path: &Path) -> Result<String> {
let mut f = File::open(path)?;
let mut buffer = String::new();
f.read_to_string(&mut buffer)?;
Ok(buffer)
}