-
-
Notifications
You must be signed in to change notification settings - Fork 172
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added initial config store #249
Conversation
src/config.rs
Outdated
description: String, | ||
} | ||
|
||
trait StorageAdapter { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any adapter that implements this can be used as a storage engine for the configuration store.
/// Configuration store is the place where the gosub engine can find all configurable options | ||
pub struct ConfigStore { | ||
/// A hashmap of all settings so we can search o(1) time | ||
settings: HashMap<String, Setting>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Settings are only the setting values.. they are not stored in SettingsInfo, which is only the template data for the configuration
/// A hashmap of all setting descriptions | ||
settings_info: HashMap<String, SettingInfo>, | ||
/// Keys of all settings so we can iterate keys easily | ||
setting_keys: Vec<String>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if we need this, but if we need to iterate all keys, we need to store them in a vec as well.
|
||
// preload the settings if requested | ||
if preload { | ||
let all_settings = store.storage.get_all_settings(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to preload all settings from a storage engine, or lazy load them when needed. It depends a bit on the latency of the storage engine (ie: remote configuration would take a long time)
src/config.rs
Outdated
} | ||
|
||
/// Returns a list of keys that mathces the given search string (can use *) | ||
fn find_setting_keys(&self, search: &str) -> Vec<String> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This allows you to use "dns.resolv*" and it will match every key that starts with this. Easy for filtering
src/config.rs
Outdated
|
||
// Panic if we can't find the setting, and we don't have a default | ||
if default.is_none() { | ||
panic!("Setting {} not found", key); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What should we do if we cannot find the config, and there is no default given?
Should we even use a default, as we have defaults in the settingsinfo per config setting anyway
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed this into returning the default value as defined in the setting info for that key. This means we do not pass a default value when getting the key.
src/config/settings.rs
Outdated
// m:foo,bar,baz | ||
|
||
/// Converts a string to a setting or None when the string is invalid | ||
pub(crate) fn from_string(p0: &str) -> Option<Setting> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A setting can have different types. bools, ints, strings etc. This tries to accomodate that
@@ -0,0 +1,46 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This config file is imported into the engine lib binary, but it allows for a more flexible setup than incode configuration.
default.unwrap() | ||
} | ||
|
||
pub fn set(&mut self, key: &str, value: Setting) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do not do a check to see if the setting type is actually allowed.
For instance, you can set a bool (b:true
) on a uint typed setting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this has been fixed as well.. it will check the type you add against the type of the default setting.
Map(Vec<String>), | ||
} | ||
|
||
impl Serialize for Setting { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
serialize / deserialize are needed for using serde_json in the json-adapter. It will convert a Setting directory to a string
src/config/storage/json_storage.rs
Outdated
|
||
impl StorageAdapter for JsonStorageAdapter { | ||
fn get_setting(&self, key: &str) -> Option<Setting> { | ||
match self.elements.get(key) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
basically the json adapter reads the whole json during init, and not during every get_setting call.. This would create a secondary layer of caching and doesn't reflect any changes that are done on disk. We might want to reread the whole json on each json file, OR do something smarter like checking access/modify time
|
||
let json = serde_json::to_string_pretty(&self.elements).expect("failed to serialize"); | ||
|
||
file.set_len(0).expect("failed to truncate file"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we truncate the current file, since this is the file that is guarded by the mutex
|
||
let mut adapter = JsonStorageAdapter { | ||
path: path.to_string(), | ||
file_mutex: Arc::new(Mutex::new(file)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A mutex is used so we can easily use this is a multi-threaded environment. But we should lock at get/set_setting, not in the read/write functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with suggestions.
src/config.rs
Outdated
|
||
impl ConfigStore { | ||
/// Creates a new store with the given storage adapter and preloads the store if needed | ||
pub fn new(storage: Box<dyn StorageAdapter>, preload: bool) -> Self { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect we can avoid using Box<dyn ...>
if we replace it with a generic struct parameter. But in this specific case I doubt it would make a difference, since this is not (presumably) critical path code.
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add this line to the Makefile
for this command:
diff --git a/Makefile b/Makefile
index e25ba44..7a362d3 100644
--- a/Makefile
+++ b/Makefile
@@ -36,6 +36,7 @@ test_fmt:
test_commands:
cargo run --bin html5-parser-test >/dev/null
cargo run --bin parser-test >/dev/null
+ cargo run --bin config-store list >/dev/null
help: ## Display available commands
echo "Available make commands:"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Co-authored-by: Eric Walker <[email protected]>
This reverts commit b58cdd0.
@@ -101,11 +101,11 @@ fn main() { | |||
} | |||
} | |||
Commands::Set { key, value } => { | |||
store.set(&key, Setting::from_str(&value).expect("incorrect value")); | |||
store.set(&key, Setting::from_string(&value).expect("incorrect value")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious why this was reverted. The name from_str
is common in Rust, while the name from_string
looks like someone didn't know about from_str
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@emwalker this is due to an warning that is emitted by rust itself... it clashes with a standard from_str
that is found in a ::std trait and could cause conflicts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, gotcha. Perhaps that means we should be implementing that trait instead of defining from_string
. It would not be hard.
impl FromStr for Setting {
fn from_str(value: &str) -> Self {
todo!()
}
}
Initial attempt on setting up a general config store.
It can serve from multiple backends (jsonfile, memory, sqlite).