roezio: first config draft; missing write

Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
Maxime “pep” Buquet 2022-08-24 17:53:30 +02:00
parent 5dcccad90b
commit 0b5ed75e90
Signed by: pep
GPG key ID: DEDA74AEECA9D0F2
4 changed files with 184 additions and 0 deletions

View file

@ -18,6 +18,8 @@ lazy_static = "1"
enum-set = "0.0"
clap = { version = "3.2.17", features = ["derive"] }
directories = "4.0.1"
configparser = "3.0.1"
jid = "0.9.4"
[lib]
crate-type = ["cdylib"]

177
src/config.rs Normal file
View file

@ -0,0 +1,177 @@
// Copyright (C) 2018-2099 The crate authors.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::error::Error;
use std::cell::LazyCell;
use std::collections::HashMap;
use std::fmt;
use std::path::PathBuf;
use configparser::ini::Ini;
use jid::Jid;
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub(crate) enum ConfigValue {
Bool(bool),
UInt(u64),
Int(i64),
String(String),
}
impl ConfigValue {
pub(crate) fn to_bool<S: Into<String>>(_val: S) -> Result<ConfigValue, Error> {
Ok(ConfigValue::Bool(true))
}
pub(crate) fn to_uint<S: Into<String>>(_val: S) -> Result<ConfigValue, Error> {
Ok(ConfigValue::UInt(0u64))
}
pub(crate) fn to_int<S: Into<String>>(_val: S) -> Result<ConfigValue, Error> {
Ok(ConfigValue::Int(0i64))
}
pub(crate) fn to_string<S: Into<String>>(_val: S) -> Result<ConfigValue, Error> {
Ok(ConfigValue::String(String::new()))
}
}
impl fmt::Display for ConfigValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
ConfigValue::Bool(b) => b.to_string(),
ConfigValue::UInt(i) => i.to_string(),
ConfigValue::Int(i) => i.to_string(),
ConfigValue::String(s) => s.to_string(),
}
)
}
}
const DEFAULT_CONFIG: LazyCell<HashMap<&str, HashMap<&str, ConfigValue>>> =
LazyCell::new(|| HashMap::new());
pub(crate) struct Config<'a> {
filename: PathBuf,
defaults: LazyCell<HashMap<&'a str, HashMap<&'a str, ConfigValue>>>,
ini: Ini,
}
impl Config<'static> {
/// Create a new Config object
pub(crate) fn new<P: Into<PathBuf>>(filename: P) -> Self {
// TODO: read ini file.
Config {
filename: filename.into(),
defaults: DEFAULT_CONFIG,
ini: Ini::new(),
}
}
/// Sets a key/value pair in memory and updates the config file.
pub(crate) fn set(
&mut self,
key: &str,
value: ConfigValue,
section: Option<Jid>,
) -> Result<(), Error> {
let section: String = section
.map(|jid| jid.to_string())
.unwrap_or(String::from("default"));
self.write(key.clone(), value.clone(), section.as_str())?;
let _ = self.ini.set(section.as_str(), key, Some(value.to_string()));
Ok(())
}
fn write(&self, _key: &str, _value: ConfigValue, _section: &str) -> Result<(), Error> {
// TODO: Copy the file and parse it manually. If the key exists, edit it in place during
// parsing. If it doesn't, add it at the end of the section. Replace the original file
// atomically.
Ok(())
}
/// Fetches a value
pub(crate) fn get(
&self,
key: &str,
section: Option<Jid>,
) -> Result<Option<ConfigValue>, Error> {
let section: String = section
.map(|jid| jid.to_string())
.unwrap_or(String::from("default"));
let value = self.ini.get(&section, key);
let default = self
.defaults
.get(section.as_str())
.map(|section| section.get(key));
Ok(match (default, value) {
// Default exists, value exists
(Some(Some(def)), Some(val)) => Some(match def {
ConfigValue::Bool(_) => ConfigValue::to_bool(val.clone())?,
ConfigValue::UInt(_) => ConfigValue::to_uint(val.clone())?,
ConfigValue::Int(_) => ConfigValue::to_int(val.clone())?,
ConfigValue::String(_) => ConfigValue::to_string(val.clone())?,
}),
// Default exists, value doesn't
(Some(Some(def)), _) => Some(def.clone()),
// Default doesn't exist, value does
// XXX: How do we know what type to return?
(_, Some(val)) => Some(ConfigValue::to_string(val)?),
_ => None,
})
}
pub(crate) fn getbool(&self, key: &str, section: Option<Jid>) -> Result<Option<bool>, Error> {
match self.get(key, section)? {
Some(ConfigValue::Bool(v)) => Ok(Some(v)),
Some(v) => Err(Error::InvalidConfigValueType(v)),
None => Ok(None),
}
}
pub(crate) fn getuint(&self, key: &str, section: Option<Jid>) -> Result<Option<u64>, Error> {
match self.get(key, section)? {
Some(ConfigValue::UInt(v)) => Ok(Some(v)),
Some(v) => Err(Error::InvalidConfigValueType(v)),
None => Ok(None),
}
}
pub(crate) fn getint(&self, key: &str, section: Option<Jid>) -> Result<Option<i64>, Error> {
match self.get(key, section)? {
Some(ConfigValue::Int(v)) => Ok(Some(v)),
Some(v) => Err(Error::InvalidConfigValueType(v)),
None => Ok(None),
}
}
pub(crate) fn getstring(
&self,
key: &str,
section: Option<Jid>,
) -> Result<Option<String>, Error> {
match self.get(key, section)? {
Some(ConfigValue::String(v)) => Ok(Some(v)),
Some(v) => Err(Error::InvalidConfigValueType(v)),
None => Ok(None),
}
}
}

View file

@ -13,6 +13,8 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::config::ConfigValue;
use std::error::Error as StdError;
use std::fmt;
use std::io;
@ -21,6 +23,7 @@ use std::io;
pub(crate) enum Error {
IOError(io::Error),
UnableToCreateConfigDir,
InvalidConfigValueType(ConfigValue),
}
impl fmt::Display for Error {
@ -28,6 +31,7 @@ impl fmt::Display for Error {
match self {
Error::IOError(e) => write!(f, "io error: {}", e),
Error::UnableToCreateConfigDir => write!(f, "Unable to create config dir"),
Error::InvalidConfigValueType(err) => write!(f, "Invalid ConfigValue type: {}", err),
}
}
}

View file

@ -1,6 +1,7 @@
#![feature(once_cell)]
mod args;
mod config;
mod error;
mod logger;
mod theming;