Skip to content

Commit

Permalink
tmp commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jaytaph committed Nov 19, 2023
1 parent c7e9625 commit 7dbabcd
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 0 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ log = "0.4.20"
domain-lookup-tree = "0.1"
hickory-resolver = "0.24.0"
simple_logger = "4.2.0"
shared_singleton = "0.1.0"

[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
Expand Down
58 changes: 58 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,59 @@ use serde_json::Value;
use std::collections::HashMap;
use std::mem;
use std::str::FromStr;
use std::sync::RwLock;
use wildmatch::WildMatch;
use lazy_static::lazy_static;

const SETTINGS_JSON: &str = include_str!("./config/settings.json");

struct GlobalStorage {
config_store: Option<ConfigStore>,
}

impl GlobalStorage {
pub fn config_store(&mut self) -> &mut ConfigStore {
match self.config_store {
Some(ref mut store) => store,
None => {
let store = ConfigStore::from_storage(Box::new(storage::memory_storage::MemoryStorageAdapter::new()), true).unwrap();
self.config_store = Some(store);
self.config_store.as_mut().unwrap()
}
}
}
}

lazy_static! {
static ref GLOBAL_STORAGE: RwLock<GlobalStorage> = RwLock::new(GlobalStorage {
config_store: None,
});
}

#[macro_export]
macro_rules! config {
(string $key:expr) => {
let lock = GLOBAL_STORAGE.config_store().read();
let v = GLOBAL_STORAGE.config_store().get($key).to_string();
drop(lock);
v
};
(bool $key:expr) => {
GLOBAL_STORAGE.config_store().get($key).to_bool()
};
(uint $key:expr) => {
GLOBAL_STORAGE.config_store().get($key).to_uint()
};
(sint $key:expr) => {
GLOBAL_STORAGE.config_store().get($key).to_sint()
};
(map $key:expr) => {
GLOBAL_STORAGE.config_store().get($key).to_map()
};
}

unsafe impl Send for GlobalStorage {}

#[derive(Debug, Deserialize)]
struct JsonEntry {
key: String,
Expand Down Expand Up @@ -194,4 +243,13 @@ mod test {
Setting::String("wont accept strings".into()),
);
}

#[test]
fn find_settings() {
let enabled = config!(bool "dns.local_resolver.enabled");
assert_eq!(enabled, true);

let max_entries = config!(uint "dns.local_resolver.max_entries");
assert_eq!(max_entries, 100);
}
}
147 changes: 147 additions & 0 deletions src/config/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::types::{Error, Result};
use core::fmt::Display;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::str::FromStr;
use log::warn;

/// A setting can be either a signed integer, unsigned integer, string, map or boolean.
/// Maps could be created by using comma separated strings maybe
Expand All @@ -14,6 +15,92 @@ pub enum Setting {
Map(Vec<String>),
}

impl Setting {
pub fn to_bool(&self) -> bool {
if ! matches!(self, Setting::Bool(_)) {
warn!("setting is not a boolean");
}

match self {
Setting::Bool(value) => *value,
Setting::SInt(value) => *value != 0,
Setting::UInt(value) => *value != 0,
Setting::String(value) => is_bool_value(value),
Setting::Map(values) => !values.is_empty(),
}
}

pub fn to_sint(&self) -> isize {
if ! matches!(self, Setting::SInt(_)) {
warn!("setting is not an signed integer");
}

match self {
Setting::SInt(value) => *value,
Setting::UInt(value) => *value as isize,
Setting::Bool(value) => *value as isize,
Setting::String(value) => is_bool_value(value) as isize,
Setting::Map(values) => values.len() as isize,
}
}

pub fn to_uint(&self) -> usize {
if ! matches!(self, Setting::UInt(_)) {
warn!("setting is not an unsigned integer");
}

match self {
Setting::UInt(value) => *value,
Setting::SInt(value) => *value as usize,
Setting::Bool(value) => *value as usize,
Setting::String(value) => is_bool_value(value) as usize,
Setting::Map(values) => values.len(),
}
}

pub fn to_string(&self) -> String {
if ! matches!(self, Setting::String(_)) {
warn!("setting is not a string");
}

match self {
Setting::SInt(value) => value.to_string(),
Setting::UInt(value) => value.to_string(),
Setting::String(value) => value.clone(),
Setting::Bool(value) => value.to_string(),
Setting::Map(values) => {
let mut result = String::new();
for value in values {
result.push_str(value);
result.push(',');
}
result.pop();
result
}
}
}

pub fn to_map(&self) -> Vec<String> {
if ! matches!(self, Setting::Map(_)) {
warn!("setting is not a map");
}

match self {
Setting::Map(values) => values.clone(),
_ => Vec::new(),
}
}
}

fn is_bool_value(s: &str) -> bool {
let us = s.to_uppercase();
if ["YES", "ON", "TRUE", "1"].contains(&us.as_str()) {
return true;
}

return false
}

impl Serialize for Setting {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
Expand Down Expand Up @@ -122,21 +209,46 @@ mod test {
fn setting() {
let s = Setting::from_str("b:true").unwrap();
assert_eq!(s, Setting::Bool(true));
assert_eq!(true, s.to_bool());
assert_eq!(1, s.to_sint());
assert_eq!(1, s.to_uint());
assert_eq!("true", s.to_string());
assert_eq!(Vec::<String>::new(), s.to_map());

let s = Setting::from_str("i:-1").unwrap();
assert_eq!(s, Setting::SInt(-1));
assert_eq!(true, s.to_bool());
assert_eq!(-1, s.to_sint());
assert_eq!(18446744073709551615, s.to_uint());
assert_eq!("-1", s.to_string());
assert_eq!(Vec::<String>::new(), s.to_map());

let s = Setting::from_str("i:1").unwrap();
assert_eq!(s, Setting::SInt(1));
assert_eq!(true, s.to_bool());
assert_eq!(1, s.to_sint());
assert_eq!(1, s.to_uint());
assert_eq!("1", s.to_string());
assert_eq!(Vec::<String>::new(), s.to_map());

let s = Setting::from_str("s:hello world").unwrap();
assert_eq!(s, Setting::String("hello world".into()));
assert_eq!(false, s.to_bool());
assert_eq!(0, s.to_sint());
assert_eq!(0, s.to_uint());
assert_eq!("hello world", s.to_string());
assert_eq!(Vec::<String>::new(), s.to_map());

let s = Setting::from_str("m:foo,bar,baz").unwrap();
assert_eq!(
s,
Setting::Map(vec!["foo".into(), "bar".into(), "baz".into()])
);
assert_eq!(true, s.to_bool());
assert_eq!(3, s.to_sint());
assert_eq!(3, s.to_uint());
assert_eq!("foo,bar,baz", s.to_string());
assert_eq!(vec!["foo", "bar", "baz"], s.to_map());

let s = Setting::from_str("notexist:true");
assert!(matches!(s, Err(Error::Config(_))));
Expand All @@ -149,5 +261,40 @@ mod test {

let s = Setting::from_str("u:-1");
assert!(matches!(s, Err(Error::Config(_))));

let s = Setting::from_str("s:true").unwrap();
assert_eq!(true, s.to_bool());
assert_eq!(1, s.to_sint());
assert_eq!(1, s.to_uint());

let s = Setting::from_str("s:false").unwrap();
assert_eq!(false, s.to_bool());
assert_eq!(0, s.to_sint());
assert_eq!(0, s.to_uint());

let s = Setting::from_str("s:1").unwrap();
assert_eq!(true, s.to_bool());
assert_eq!(1, s.to_sint());
assert_eq!(1, s.to_uint());

let s = Setting::from_str("s:0").unwrap();
assert_eq!(false, s.to_bool());
assert_eq!(0, s.to_sint());
assert_eq!(0, s.to_uint());

let s = Setting::from_str("s:on").unwrap();
assert_eq!(true, s.to_bool());
assert_eq!(1, s.to_sint());
assert_eq!(1, s.to_uint());

let s = Setting::from_str("s:yes").unwrap();
assert_eq!(true, s.to_bool());
assert_eq!(1, s.to_sint());
assert_eq!(1, s.to_uint());

let s = Setting::from_str("s:off").unwrap();
assert_eq!(false, s.to_bool());
assert_eq!(0, s.to_sint());
assert_eq!(0, s.to_uint());
}
}

0 comments on commit 7dbabcd

Please sign in to comment.