the state before switching to dynamic dispatch for stores

This commit is contained in:
Sebastian Moser
2024-06-09 14:01:25 +02:00
parent 6887287c29
commit 33e75d9c25
9 changed files with 229 additions and 6 deletions

35
Cargo.lock generated
View File

@@ -1068,6 +1068,7 @@ dependencies = [
"nix", "nix",
"serde", "serde",
"serde_json", "serde_json",
"sysinfo",
"tokio", "tokio",
"toml", "toml",
"uuid", "uuid",
@@ -1105,6 +1106,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "ntapi"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "num-conv" name = "num-conv"
version = "0.1.0" version = "0.1.0"
@@ -1583,6 +1593,21 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "sysinfo"
version = "0.30.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "732ffa00f53e6b2af46208fba5718d9662a421049204e156328b66791ffa15ae"
dependencies = [
"cfg-if",
"core-foundation-sys",
"libc",
"ntapi",
"once_cell",
"rayon",
"windows",
]
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.10.1" version = "3.10.1"
@@ -2257,6 +2282,16 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
dependencies = [
"windows-core",
"windows-targets 0.52.5",
]
[[package]] [[package]]
name = "windows-core" name = "windows-core"
version = "0.52.0" version = "0.52.0"

View File

@@ -17,7 +17,7 @@ path = "src/platform/os/main.rs"
required-features = [ "os-target" ] required-features = [ "os-target" ]
[features] [features]
os-target = [ "clap", "home", "env_logger", "daemonize", "nix", "toml", "serde_json" ] os-target = [ "clap", "home", "env_logger", "daemonize", "nix", "toml", "serde_json", "sysinfo", "ciborium/default"]
wasm-target = [ "wasm-bindgen", "console_error_panic_hook", "wasm-bindgen-cli" ] wasm-target = [ "wasm-bindgen", "console_error_panic_hook", "wasm-bindgen-cli" ]
@@ -44,6 +44,7 @@ daemonize = { version = "0.5.0", optional = true }
nix = { version = "0.27.1", features = ["signal"], optional = true } nix = { version = "0.27.1", features = ["signal"], optional = true }
toml = { version = "0.8.13", features = ["parse"], optional = true } toml = { version = "0.8.13", features = ["parse"], optional = true }
serde_json = { version = "1.0.117", optional = true } serde_json = { version = "1.0.117", optional = true }
sysinfo = { version = "0.30.12", optional = true }
# bare dependencies # bare dependencies

View File

@@ -7,6 +7,11 @@ use std::io;
use colored::Colorize; use colored::Colorize;
use log::{trace, debug, info, warn, error}; use log::{trace, debug, info, warn, error};
#[macro_export]
macro_rules! mize_err {
($($arg:tt)*) => { MizeError::new().msg(format!( $($arg)*)) };
}
use crate::proto::MizeMessage; use crate::proto::MizeMessage;
pub type MizeResult<T> = Result<T, MizeError>; pub type MizeResult<T> = Result<T, MizeError>;

View File

@@ -130,7 +130,19 @@ impl<S: Store> Instance<S> {
//fn from(value: T) -> Self { //fn from(value: T) -> Self {
//} //}
//} //}
pub fn migrate_to_store<New: Store>(&mut self, new_store: New) -> MizeResult<Instance<New>> {
let old_store = self.store;
for id in old_store.id_iter()? {
let data = self.store.get_value_data_full(self.id_from_string(id))?;
let id_of_new_store = new_store.new_id()?;
new_store.set(self.id_from_string(id_of_new_store), data.to_owned())?;
};
self.store = new_store as S;
Ok(Instance { store: new_store, subs: self.subs, peers: self.peers, id_pool: self.id_pool })
}
} }
impl<S: Store> fmt::Debug for Instance<S> { impl<S: Store> fmt::Debug for Instance<S> {

View File

@@ -1,6 +1,12 @@
use std::iter::Map;
use std::option::Iter;
use crate::error::MizeResult; use crate::error::MizeResult;
use crate::item::{Item, ItemData}; use crate::item::{Item, ItemData};
use crate::id::MizeId; use crate::id::MizeId;
use crate::memstore::MemStore;
use crate::instance::Instance;
pub trait Store { pub trait Store {
// should have the ability to be multi threaded, if the underlying implementation supports // should have the ability to be multi threaded, if the underlying implementation supports
@@ -23,5 +29,7 @@ pub trait Store {
fn get_value_raw(&self, id: MizeId) -> MizeResult<Vec<u8>>; fn get_value_raw(&self, id: MizeId) -> MizeResult<Vec<u8>>;
fn get_value_data_full(&self, id: MizeId) -> MizeResult<ItemData>; fn get_value_data_full(&self, id: MizeId) -> MizeResult<ItemData>;
fn id_iter(&self) -> MizeResult<impl Iterator<Item=String> + '_>;
} }

View File

@@ -41,6 +41,11 @@ impl<S: Store> Item<'_, S> {
// this will call from the instance which gets the value from the store // this will call from the instance which gets the value from the store
self.instance.store.get_value_raw(self.id()) self.instance.store.get_value_raw(self.id())
} }
pub fn value_string(&self) -> MizeResult<String> {
let raw = self.value_raw()?;
String::from_utf8(raw.clone())
.mize_result_msg(format!("failed to convert raw value from item '{}' into a utf-8 string. raw value was: '{:02X?}'", self.id(), raw))
}
pub fn as_data_full(&self) -> MizeResult<ItemData> { pub fn as_data_full(&self) -> MizeResult<ItemData> {
self.instance.store.get_value_data_full(self.id()) self.instance.store.get_value_data_full(self.id())
} }
@@ -73,6 +78,10 @@ impl ItemData {
item_data_merge(&mut self.0, &other.0); item_data_merge(&mut self.0, &other.0);
} }
pub fn cbor(&self) -> &CborValue {
&self.0
}
pub fn null() -> CborValue { pub fn null() -> CborValue {
CborValue::Null CborValue::Null
} }
@@ -106,7 +115,7 @@ impl ItemData {
} }
fn item_data_get_path(data: &CborValue, path: Vec<String>) -> MizeResult<&CborValue> { pub fn item_data_get_path(data: &CborValue, path: Vec<String>) -> MizeResult<&CborValue> {
let mut path_iter = path.clone().into_iter(); let mut path_iter = path.clone().into_iter();
let path_el = match path_iter.nth(0) { let path_el = match path_iter.nth(0) {
Some(val) => val, Some(val) => val,
@@ -133,7 +142,7 @@ fn item_data_get_path(data: &CborValue, path: Vec<String>) -> MizeResult<&CborVa
item_data_get_path(sub_data, path_iter.collect()) item_data_get_path(sub_data, path_iter.collect())
} }
fn item_data_set_path(data: &mut CborValue, path: Vec<String>, data_to_set: &CborValue) -> MizeResult<()> { pub fn item_data_set_path(data: &mut CborValue, path: Vec<String>, data_to_set: &CborValue) -> MizeResult<()> {
//trace!("[ {} ] item_data_set_path()", "CALL".yellow()); //trace!("[ {} ] item_data_set_path()", "CALL".yellow());
//trace!("[ {} ] data: {}", "ARG".yellow(), data.clone().into_item_data()); //trace!("[ {} ] data: {}", "ARG".yellow(), data.clone().into_item_data());
//trace!("[ {} ] path: {:?}", "ARG".yellow(), path); //trace!("[ {} ] path: {:?}", "ARG".yellow(), path);
@@ -177,7 +186,7 @@ fn item_data_set_path(data: &mut CborValue, path: Vec<String>, data_to_set: &Cbo
return Err(MizeError::new().msg("unreachable")); return Err(MizeError::new().msg("unreachable"));
} }
fn item_data_merge(merge_into: &mut CborValue, other: &CborValue){ pub fn item_data_merge(merge_into: &mut CborValue, other: &CborValue){
// needs to be recursive // needs to be recursive
match (merge_into, other) { match (merge_into, other) {

View File

@@ -10,6 +10,7 @@ use crate::id::MizeId;
use crate::instance::store::Store; use crate::instance::store::Store;
use crate::error::{MizeError, MizeResult, IntoMizeResult}; use crate::error::{MizeError, MizeResult, IntoMizeResult};
use crate::item::{Item, ItemData}; use crate::item::{Item, ItemData};
use crate::instance::Instance;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MemStore { pub struct MemStore {
@@ -79,6 +80,12 @@ impl Store for MemStore {
return Ok(ret_data); return Ok(ret_data);
} }
fn id_iter(&self) -> MizeResult<impl Iterator<Item=String> + '_> {
let inner = self.inner.lock()?;
let keys: Vec<String> = inner.map.keys().map(|v| format!("{}", v)).collect();
return Ok(keys.into_iter());
}
} }
impl MemStore { impl MemStore {
@@ -94,7 +101,7 @@ fn id_to_u64(id: MizeId) -> MizeResult<u64> {
.mize_result_msg(format!("Could not parse the store_part of mizeid {} into a u64 for the MemStore", id)) .mize_result_msg(format!("Could not parse the store_part of mizeid {} into a u64 for the MemStore", id))
} }
fn get_raw_from_cbor<'a>(value: &'a CborValue, path: Vec<&String>) -> MizeResult<&'a [u8]> { pub fn get_raw_from_cbor<'a>(value: &'a CborValue, path: Vec<&String>) -> MizeResult<&'a [u8]> {
trace!("[ {} ] get_raw_from_cbor()", "CALL".yellow()); trace!("[ {} ] get_raw_from_cbor()", "CALL".yellow());
trace!("[ {} ] value: {:?}", "ARG".yellow(), value); trace!("[ {} ] value: {:?}", "ARG".yellow(), value);
trace!("[ {} ] path: {:?}", "ARG".yellow(), path); trace!("[ {} ] path: {:?}", "ARG".yellow(), path);

View File

@@ -0,0 +1,132 @@
use std::fs;
use std::path::{Path, PathBuf};
use std::fs::OpenOptions;
use sysinfo::{System, Pid, ProcessRefreshKind, RefreshKind};
use std::io::Write;
use ciborium::Value as CborValue;
use crate::item::IntoItemData;
use crate::memstore::MemStore;
use crate::{core::instance::store::Store, mize_err};
use crate::error::{IntoMizeResult, MizeResult, MizeError};
use crate::core::item::{ItemData, Item};
use crate::core::id::MizeId;
use crate::core::memstore::get_raw_from_cbor;
use crate::instance::Instance;
pub struct FileStore {
path: PathBuf,
}
impl FileStore {
pub fn new(path: String) -> MizeResult<FileStore> {
// create that path if it does not exist
fs::create_dir_all(Path::new(&path).join("store"))?;
// check for valid pid file
if let Some(pid) = valid_pid_file(&path)? {
// store already opened
return Err(mize_err!("MizeStore at path {} is already opened by process with pid {}", &path, pid));
} else {
// write our own pid file
let pid = std::process::id();
let mut file = OpenOptions::new().write(true).create(true).open(&path)?;
write!(file, "{}", pid)?;
}
Ok(FileStore { path: Path::new(&path).to_owned() })
}
}
impl Store for FileStore {
fn new_id(&self) -> MizeResult<String> {
let mut next_id: u64 = String::from_utf8(fs::read(self.path.join("next_id"))
.mize_result_msg(format!("could not read next_id at '{}'", self.path.display()))?)?
.parse()
.mize_result_msg(format!("could not parse next_id at '{}' to u64", self.path.display()))?;
let id_string = format!("{}", next_id);
next_id += 1;
fs::write(self.path.join("next_id"), format!("{}", next_id))?;
return Ok(id_string);
}
fn set<T: Into<ItemData>>(&self, id: MizeId, data: T) -> MizeResult<()> {
let file = OpenOptions::new().write(true).create(true).open(self.path.join("store").join(id.store_part()))?;
ciborium::into_writer(data.into().cbor(), file)?;
Ok(())
}
fn get_links(&self, item: Item<Self>) -> MizeResult<Vec<MizeId>> {
Ok(Vec::new())
}
fn get_backlinks(&self, item: Item<Self>) -> MizeResult<Vec<MizeId>> {
Ok(Vec::new())
}
fn get_value_raw(&self, id: MizeId) -> MizeResult<Vec<u8>> {
let file = OpenOptions::new().read(true).create(true).open(self.path.join("store").join(id.store_part()))?;
let cbor_val: CborValue = ciborium::from_reader(file)
.mize_result_msg(format!("could not read file '{}' from FileStore", self.path.join("store").join(id.store_part()).display()))?;
let path = id.path();
let mut id_iter = path.iter();
id_iter.next();
let id_without_first = id_iter.collect();
Ok(get_raw_from_cbor(&cbor_val, id_without_first)?.to_owned())
}
fn get_value_data_full(&self, id: MizeId) -> MizeResult<ItemData> {
let file = OpenOptions::new().read(true).create(true).open(self.path.join("store").join(id.store_part()))?;
let cbor_value: CborValue = ciborium::from_reader(file)
.mize_result_msg(format!("could not read file '{}' from FileStore", self.path.join("store").join(id.store_part()).display()))?;
let data: ItemData = cbor_value.into_item_data();
let tmp = id.path();
let mut path_iter = tmp.into_iter();
path_iter.next();
let new_path: Vec<String> = path_iter.map(|v| v.to_owned()).collect();
let ret_data = data.get_path(new_path)?;
return Ok(ret_data);
}
fn id_iter(&self) -> MizeResult<impl Iterator<Item=String> + '_> {
Ok(vec!["1".to_owned(), "2".to_owned()].into_iter())
}
}
fn valid_pid_file(path: &String) -> MizeResult<Option<u32>> {
let pid_file_path = Path::new(path).join("pid");
// if the pid file does not exist, there is no pid...
if !pid_file_path.exists() {
return Ok(None);
}
// read pid file
let pid: u32 = String::from_utf8(fs::read(&pid_file_path)
.mize_result_msg(format!("Could not read contents of pid file at '{}'", pid_file_path.display()))?)?
.parse()
.mize_result_msg(format!("Could not parse contents of pid file at '{}' to u32", pid_file_path.display()))?;
let refresh_kind = RefreshKind::new().with_processes(ProcessRefreshKind::everything());
let system = sysinfo::System::new_with_specifics(refresh_kind);
if let Some(_) = system.process(Pid::from(pid as usize)) {
return Ok(Some(pid));
} else {
return Ok(None);
}
}

View File

@@ -10,9 +10,16 @@ use crate::instance::store::Store;
use crate::instance::Instance; use crate::instance::Instance;
use crate::error::{IntoMizeResult, MizeError, MizeResult}; use crate::error::{IntoMizeResult, MizeError, MizeResult};
use crate::item::{ItemData, IntoItemData}; use crate::item::{ItemData, IntoItemData};
use crate::memstore::MemStore;
use self::fsstore::FileStore;
mod fsstore;
//mod web;
//mod unix-socket;
pub fn os_instance_init<S: Store>(instance: &mut Instance<S>) -> MizeResult<()> { pub fn os_instance_init<S: Store>(instance: Instance<MemStore>) -> MizeResult<Instance<FileStore>> {
// this is the code, that runs to initialize an Instance on a system with an os present. // this is the code, that runs to initialize an Instance on a system with an os present.
////// load MIZE_CONFIG_FILE as the instance, which is item 0 ////// load MIZE_CONFIG_FILE as the instance, which is item 0
@@ -51,7 +58,14 @@ pub fn os_instance_init<S: Store>(instance: &mut Instance<S>) -> MizeResult<()>
} }
}; };
////// if a config.store is set, upgrade to the filestore there
let store_path = instance.get("0/conifg/store")?.value_string()?;
if store_path != "" {
let file_store = FileStore::new(store_path)?;
let new_instance = &mut instance.migrate_to_store(file_store)?;
return Ok(new_instance);
}
return Ok(()); return Ok(());
} }