Skip to content

Commit

Permalink
tmp commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jaytaph committed Nov 21, 2023
1 parent 9832174 commit b1f5705
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 59 deletions.
79 changes: 34 additions & 45 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,49 +1,51 @@
pub mod settings;
pub mod storage;

use std::cell::Cell;
use crate::config::settings::{Setting, SettingInfo};
use crate::types::Result;
use serde_derive::Deserialize;
use serde_json::Value;
use std::collections::HashMap;
use std::{fmt, mem};
use std::str::FromStr;
use std::sync::atomic::AtomicUsize;
use wildmatch::WildMatch;
use crate::config::storage::memory_storage::MemoryStorageAdapter;
use crate::config::storage::nop_storage::NopStorage;

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

// Heavily inspired by the log crate
struct AtomicUsize {
v: Cell<usize>,
}

static mut CONFIG_STORE: &dyn Store = &MemoryStorageAdapter::new();
static mut CONFIG_STORE: &dyn Store = &NopStorage{};
static CONFIG_STORE_STATE: AtomicUsize = AtomicUsize::new(0);

const UNINITIALIZED: usize = 0;
const INITIALIZING: usize = 1;
const INITIALIZED: usize = 2;
const UNINITIALIZED: usize = 0; // The config_store is not initialized yet. No calls to config!() are allowed (will panic)
const INITIALIZING: usize = 1; // The config_store is currently being initialized. No config!() is allowed, and the next call to config_store() will block until the store is initialized
const INITIALIZED: usize = 2; // The config_store is initialized config!() is ok. New setting of the config store will fail

/// Store is the interface for storing and retrieving settings
/// This can be used to store settings in a database, json file, etc
pub trait Store: Sync + Send {
fn get_setting(&self, key: &str) -> Option<Setting>;
fn set_setting(&mut self, key: &str, value: Setting);
fn get_all_settings(&self) -> Result<HashMap<String, Setting>>;
/// Retrieves a setting from the storage
fn get(&self, key: &str) -> Option<Setting>;
/// Stores a given setting to the storage
fn set(&mut self, key: &str, value: Setting);
/// Retrieves all the settings in the storage in one go. This is used for preloading the settings
/// into the ConfigStore and is more performant normally than calling get_setting manually for each
/// setting.
fn all(&self) -> crate::types::Result<HashMap<String, Setting>>;
}

impl<T> Store for &'_ T where T: Store + ?Sized,
{
fn get_setting(&self, key: &str) -> Option<Setting> {
(**self).get_setting(key)
fn get(&self, key: &str) -> Option<Setting> {
(**self).get(key)
}

fn set_setting(&mut self, key: &str, value: Setting) {
(**self).set_setting(key, value)
fn set(&mut self, key: &str, value: Setting) {
(mut **self).set(key, value)
}

fn get_all_settings(&self) -> Result<HashMap<String, Setting>> {
(**self).get_all_settings()
fn all(&self) -> crate::types::Result<HashMap<String, Setting>> {
(**self).all()
}
}

Expand Down Expand Up @@ -95,8 +97,8 @@ impl std::error::Error for SetStoreError {}

pub fn config_store() -> &'static dyn Store {
if CONFIG_STORE_STATE.load(std::sync::atomic::Ordering::SeqCst) != INITIALIZED {
static MEMORY_STORE: MemoryStorageAdapter = MemoryStorageAdapter::new();
&MEMORY_STORE
static NOP_STORE: NopStorage = NopStorage{};
&NOP_STORE
} else {
unsafe { CONFIG_STORE }
}
Expand All @@ -107,19 +109,19 @@ pub fn config_store() -> &'static dyn Store {
#[macro_export]
macro_rules! config {
(string $key:expr) => {
CONFIG_STORE.get($key).to_string()
config_store().get($key).unwrap().to_string()
};
(bool $key:expr) => {
CONFIG_STORE.get($key).to_bool()
config_store().get($key).unwrap().to_bool()
};
(uint $key:expr) => {
CONFIG_STORE.get($key).to_uint()
config_store().get($key).unwrap().to_uint()
};
(sint $key:expr) => {
CONFIG_STORE.get($key).to_sint()
config_store().get($key).unwrap().to_sint()
};
(map $key:expr) => {
CONFIG_STORE.get($key).to_map()
config_store().get($key).unwrap().to_map()
};
}

Expand All @@ -132,19 +134,6 @@ struct JsonEntry {
description: String,
}

/// StorageAdapter is the interface for storing and retrieving settings
/// This can be used to store settings in a database, json file, etc
// pub trait Store {
// /// Retrieves a setting from the storage
// fn get_setting(&self, key: &str) -> Option<Setting>;
// /// Stores a given setting to the storage
// fn set_setting(&mut self, key: &str, value: Setting);
// /// Retrieves all the settings in the storage in one go. This is used for preloading the settings
// /// into the ConfigStore and is more performant normally than calling get_setting manually for each
// /// setting.
// fn get_all_settings(&self) -> Result<HashMap<String, Setting>>;
// }

/// 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
Expand All @@ -159,7 +148,7 @@ pub struct ConfigStore {

impl ConfigStore {
/// Creates a new store with the given storage adapter and preloads the store if needed
pub fn from_storage(storage: Box<dyn Store>, preload: bool) -> Result<Self> {
pub fn from_storage(storage: Box<dyn Store>, preload: bool) -> crate::types::Result<Self> {
let mut store = ConfigStore {
settings: HashMap::new(),
settings_info: HashMap::new(),
Expand All @@ -172,7 +161,7 @@ impl ConfigStore {

// preload the settings if requested
if preload {
let all_settings = store.storage.get_all_settings()?;
let all_settings = store.storage.all()?;
for (key, value) in all_settings {
store.settings.insert(key, value);
}
Expand Down Expand Up @@ -221,7 +210,7 @@ impl ConfigStore {
}

// Setting not found, try and load it from the storage adapter
if let Some(setting) = self.storage.get_setting(key) {
if let Some(setting) = self.storage.get(key) {
self.settings.insert(key.to_string(), setting.clone());
return setting.clone();
}
Expand All @@ -243,11 +232,11 @@ impl ConfigStore {
}

self.settings.insert(key.to_string(), value.clone());
self.storage.set_setting(key, value);
self.storage.set(key, value);
}

/// Populates the settings in the store from the settings.json file
fn populate_settings(&mut self) -> Result<()> {
fn populate_settings(&mut self) -> crate::types::Result<()> {
let json_data: Value =
serde_json::from_str(SETTINGS_JSON).expect("Failed to parse settings.json");

Expand Down
1 change: 1 addition & 0 deletions src/config/storage.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod json_storage;
pub mod memory_storage;
pub mod sqlite_storage;
pub mod nop_storage;
6 changes: 3 additions & 3 deletions src/config/storage/json_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,17 @@ impl TryFrom<&String> for JsonStorageAdapter {
}

impl Store for JsonStorageAdapter {
fn get_setting(&self, key: &str) -> Option<Setting> {
fn get(&self, key: &str) -> Option<Setting> {
self.elements.get(key).cloned()
}

fn set_setting(&mut self, key: &str, value: Setting) {
fn set(&mut self, key: &str, value: Setting) {
self.elements.insert(key.to_string(), value);

self.write_file()
}

fn get_all_settings(&self) -> Result<HashMap<String, Setting>> {
fn all(&self) -> Result<HashMap<String, Setting>> {
Ok(self.elements.clone())
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/config/storage/memory_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ impl MemoryStorageAdapter {
}

impl Store for MemoryStorageAdapter {
fn get_setting(&self, key: &str) -> Option<Setting> {
fn get(&self, key: &str) -> Option<Setting> {
let v = self.store.get(key);
v.cloned()
}

fn set_setting(&mut self, key: &str, value: Setting) {
fn set(&mut self, key: &str, value: Setting) {
self.store.insert(key.to_string(), value);
}

fn get_all_settings(&self) -> Result<HashMap<String, Setting>> {
fn all(&self) -> Result<HashMap<String, Setting>> {
Ok(self.store.clone())
}
}
23 changes: 23 additions & 0 deletions src/config/storage/nop_storage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use crate::config::settings::Setting;
use crate::config::Store;
use crate::types::Result;
use std::collections::HashMap;
use log::warn;

pub struct NopStorage;

impl Store for NopStorage {
fn get(&self, key: &str) -> Option<Setting> {
warn!("config store is not yet initialized");
None
}

fn set(&mut self, key: &str, value: Setting) {
warn!("config store is not yet initialized");
}

fn all(&self) -> Result<HashMap<String, Setting>> {
warn!("config store is not yet initialized");
Ok(HashMap::new())
}
}
23 changes: 15 additions & 8 deletions src/config/storage/sqlite_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use crate::types::{Error, Result};
use log::warn;
use std::collections::HashMap;
use std::str::FromStr;
use std::sync::Mutex;

pub struct SqliteStorageAdapter {
connection: sqlite::Connection,
connection: Mutex<sqlite::Connection>,
}

impl TryFrom<&String> for SqliteStorageAdapter {
Expand All @@ -22,14 +23,16 @@ impl TryFrom<&String> for SqliteStorageAdapter {
)";
conn.execute(query)?;

Ok(SqliteStorageAdapter { connection: conn })
Ok(SqliteStorageAdapter { connection: Mutex::new(conn) })
}
}

impl Store for SqliteStorageAdapter {
fn get_setting(&self, key: &str) -> Option<Setting> {
fn get(&self, key: &str) -> Option<Setting> {
let db_lock = self.connection.lock().unwrap();

let query = "SELECT * FROM settings WHERE key = :key";
let mut statement = self.connection.prepare(query).unwrap();
let mut statement = db_lock.prepare(query).unwrap();
statement.bind((":key", key)).unwrap();

match Setting::from_str(key) {
Expand All @@ -41,9 +44,11 @@ impl Store for SqliteStorageAdapter {
}
}

fn set_setting(&mut self, key: &str, value: Setting) {
fn set(&mut self, key: &str, value: Setting) {
let db_lock = self.connection.lock().unwrap();

let query = "INSERT OR REPLACE INTO settings (key, value) VALUES (:key, :value)";
let mut statement = self.connection.prepare(query).unwrap();
let mut statement = db_lock.prepare(query).unwrap();
statement.bind((":key", key)).unwrap();
statement
.bind((":value", value.to_string().as_str()))
Expand All @@ -52,9 +57,11 @@ impl Store for SqliteStorageAdapter {
statement.next().unwrap();
}

fn get_all_settings(&self) -> Result<HashMap<String, Setting>> {
fn all(&self) -> Result<HashMap<String, Setting>> {
let db_lock = self.connection.lock().unwrap();

let query = "SELECT * FROM settings";
let mut statement = self.connection.prepare(query).unwrap();
let mut statement = db_lock.prepare(query).unwrap();

let mut settings = HashMap::new();
while let sqlite::State::Row = statement.next().unwrap() {
Expand Down

0 comments on commit b1f5705

Please sign in to comment.