diff --git a/src/core/config.rs b/src/core/config.rs deleted file mode 100644 index ec92373..0000000 --- a/src/core/config.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::mize_err; -use crate::MizeResult; -use std::collections::HashMap; -use std::env; -use std::sync::{Arc, RwLock}; - -use crate::item::ItemData; -use crate::Mize; -use crate::MizeError; - -type ConfigThunk = Box ItemData + Send + Sync>; - -pub struct ConfigOpt { - pub name: String, - pub val: Option, - pub thunk: Option, -} - -#[derive(Clone)] -pub struct ConfigOptNameAndMize { - pub name: String, - pub mize: Mize, -} - -impl ConfigOptNameAndMize { - pub fn default_val(self, val: ItemData) -> ConfigOptNameAndMize { - let mut config_opts = self.mize.config_opts.lock().unwrap(); - let opt = config_opts.get_mut(&self.name).unwrap(); - opt.val = Some(val); - self.clone() - } - pub fn fun(self, thunk: ConfigThunk) -> Self { - let mut config_opts = self.mize.config_opts.lock().unwrap(); - let opt = config_opts.get_mut(&self.name).unwrap(); - opt.thunk = Some(thunk); - self.clone() - } -} - -pub fn gather_config(mize: &mut Mize) -> MizeResult<()> { - let mut config_opts = mize.config_opts.lock().unwrap(); - let parts = mize.parts.lock().unwrap(); - - for part in parts.values() { - part.as_deref().unwrap().opts(&mut mize.clone()); - } - - Ok(()) -} diff --git a/src/core/error.rs b/src/core/error.rs deleted file mode 100644 index 39761f9..0000000 --- a/src/core/error.rs +++ /dev/null @@ -1,367 +0,0 @@ -use colored::Colorize; -#[cfg(feature = "target-js")] -use wasm_bindgen::JsValue; -use core::result::Result; -use core::result::Result::Ok; -use std::collections::HashMap; -use std::fmt::format; -use std::fmt::Debug; -use std::fmt::Display; -use std::io; -use std::string::FromUtf8Error; -use tracing::{debug, error, info, trace, warn}; - -//use crate::proto::MizeMessage; - -#[macro_export] -macro_rules! mize_err { - ($($arg:tt)*) => { MizeError::new().msg(format!( $($arg)*)) }; -} - -pub type MizeResult = Result; - -pub trait MizeResultTrait { - fn critical(self) -> T; - fn as_std(self) -> Result; -} - -pub trait IntoMizeResult { - fn mres(self) -> MizeResult; - fn mres_msg(self, msg: S) -> MizeResult - where - S: std::fmt::Display; -} - -#[derive(Debug, Clone)] -pub struct MizeError { - pub category: Vec, - pub code: u32, - pub messages: Vec, - //pub caused_by_msg: Option, - pub code_location: Option, - pub backtrace: String, -} - -/* -#[derive(Debug, Clone)] -pub struct CausedByMessage { - // peer: &Connection, // TODO: add later - msg: Box, -} -*/ - -#[derive(Debug, Clone)] -pub struct MizeCodeLocation { - file: String, - line: u32, - column: u32, -} - -impl Display for MizeCodeLocation { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "file: {} line: {} column: {}", - self.file, self.line, self.column - ) - } -} - -impl From<&std::panic::Location<'_>> for MizeCodeLocation { - fn from(panic_location: &std::panic::Location) -> MizeCodeLocation { - let file = panic_location.file().to_string(); - let line = panic_location.line(); - let column = panic_location.column(); - MizeCodeLocation { file, line, column } - } -} - -impl MizeError { - #[track_caller] - pub fn code(code: u32) -> MizeError { - let caller_location = std::panic::Location::caller(); - - get_error_by_code(code, caller_location) - } - - pub fn set_code(mut self, code: u32) -> MizeError { - self.code = code; - return self; - } - - #[track_caller] - pub fn new() -> MizeError { - let caller_location = std::panic::Location::caller(); - - return MizeError { - category: Vec::new(), - code: 0, - messages: Vec::new(), - code_location: Some(caller_location.into()), - backtrace: format!("{}", std::backtrace::Backtrace::capture()), - }; - } - - pub fn msg(mut self, msg: E) -> MizeError - where - E: std::fmt::Display, - { - self.messages.push(format!("{}", msg)); - return self; - } - - pub fn category(mut self, category: T) -> MizeError - where - T: Into, - { - self.category.push(category.into()); - return self; - } - - fn send(self) -> MizeError { - self - } - - fn add_to_err_item(self) -> MizeError { - self - } - - pub fn log(self) -> MizeError { - println!("[ {} ] MizeError encountered!", "ERROR".red()); - - if let Some(ref location) = self.code_location { - println!("[ {} ] {}", "LOCATION".yellow(), location); - }; - - println!("[ {} ] {}", "BACKTRACE".yellow(), self.backtrace); - - for msg in &self.messages { - println!("[ {} ] {}", "MSG".yellow(), msg); - } - - self - } - - pub fn handle(self) -> MizeError { - return self.send().add_to_err_item().log(); - } - - pub fn critical(self) { - let mut msg_iter = self.messages.iter(); - match msg_iter.next() { - None => { - error!("{} MizeError with code: {}", "CRITICAL".red(), self.code); - } - Some(msg) => { - error!( - "{} MizeError with code: {} - {}", - "CRITICAL".red(), - self.code, - msg - ); - } - } - for msg in msg_iter { - error!("{} {}", "MSG".red(), msg) - } - if let Some(location) = self.code_location { - error!("{} {}", "LOCATION".red(), location) - } - panic!(); - } - - pub fn location(mut self, location: MizeCodeLocation) -> MizeError { - self.code_location = Some(location); - - self - } -} - -/* -pub trait MizeResultExtension { - fn extra_msg(self, msg: E) -> Result - where E: std::fmt::Display - ; - fn handle(self) -> Result; - - fn is_critical(self) -> T; -} - -impl MizeResultExtension for Result { - fn msg(mut self, msg: E) -> Result - where E: std::fmt::Display - { - match self { - Err(ref mut e) => { - e.msg.push(format!("{}", msg)); - return self; - }, - Ok(something) => Ok(something), - } - } - fn handle(self) -> Result { - match self { - Err(e) => { - Err(e.send().add_to_err_item().write_to_stderr()) - }, - Ok(something) => Ok(something) - } - } - fn is_critical(self) -> T { - self.expect("Aborting because of a critical Error") - } -} -*/ - -/* -impl From for MizeError { - #[track_caller] - fn from(utf_err: FromUtf8Error) -> MizeError{ - let caller_location = std::panic::Location::caller(); - - let mut err = MizeError::code(109).msg(format!("From std::string::FromUtf8Error: {}", utf_err)); - err.code_location = Some(caller_location.into()); - return err; - } -} -*/ - -impl From for MizeError { - #[track_caller] - fn from(value: T) -> Self { - let caller_location = std::panic::Location::caller(); - MizeError::new() - .msg(format!( - "From {}: {}", - std::any::type_name_of_val(&value), - value - )) - .location(caller_location.into()) - } -} - -impl MizeResultTrait for MizeResult { - fn critical(self) -> T { - match self { - Ok(val) => val, - Err(err) => { - err.critical(); - unreachable!() - } - } - } - fn as_std(self) -> Result { - match self { - Ok(val) => Ok(val), - Err(err) => Err(MizeErrorWhichImplementsError { inner: err }), - } - } -} - -impl IntoMizeResult for Result -where - E: std::fmt::Display, -{ - #[track_caller] - fn mres(self) -> MizeResult { - let caller_location = std::panic::Location::caller(); - - match self { - Ok(val) => MizeResult::Ok(val), - Err(err) => MizeResult::Err(MizeError::new().category("misc").msg(format!( - "From {}: {}", - std::any::type_name_of_val(&err), - err - ))), - } - } - #[track_caller] - fn mres_msg(self, msg: S) -> MizeResult - where - S: std::fmt::Display, - { - let caller_location = std::panic::Location::caller(); - match self { - Ok(val) => MizeResult::Ok(val), - Err(err) => MizeResult::Err( - MizeError::new() - .category("misc") - .msg(format!("{}", msg)) - .msg(format!( - "From {}: {}", - std::any::type_name_of_val(&err), - err - )), - ), - } - } -} - -fn get_error_by_code(code: u32, caller_location: &std::panic::Location) -> MizeError { - let err = MizeError { - category: Vec::new(), - code: 0, - messages: Vec::new(), - code_location: Some(caller_location.into()), - backtrace: format!("{}", std::backtrace::Backtrace::capture()), - }; - - match code { - 109 => err - .set_code(109) - .category("decoding") - .msg("conversion from utf8 failed"), - 108 => err - .set_code(108) - .category("decoding") - .msg("serde deserialisation failed"), - _ => err, - } -} - -#[derive(Debug, Clone)] -pub struct MizeErrorWhichImplementsError { - inner: MizeError, -} - -impl Display for MizeErrorWhichImplementsError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "MizeError envountered!"); - - if let Some(ref location) = self.inner.code_location { - write!(f, "[ {} ] {}", "LOCATION".yellow(), location); - }; - - write!(f, "[ {} ] {}", "BACKTRACE".yellow(), self.inner.backtrace); - - for msg in &self.inner.messages { - write!(f, "[ {} ] {}", "MSG".yellow(), msg); - } - Ok(()) - } -} - -impl From for MizeErrorWhichImplementsError { - fn from(value: MizeError) -> Self { - MizeErrorWhichImplementsError { inner: value } - } -} - -impl std::error::Error for MizeErrorWhichImplementsError {} - -// i hate rust sometimes. -// why can't i impl IntoMizeResult for any type. and the extra concrete impl of it for JsValue overrides the more generic one. -#[cfg(feature = "target-js")] -pub trait IntoMizeResultJsValue { - fn mres(self) -> MizeResult; -} - -#[cfg(feature = "target-js")] -impl IntoMizeResultJsValue for Result { - fn mres(self) -> MizeResult { - match self { - Ok(value) => Ok(value), - Err(err) => Err(mize_err!("From JsValue: {:?}", err)), - } - } -} diff --git a/src/core/id.rs b/src/core/id.rs deleted file mode 100644 index 6d02a49..0000000 --- a/src/core/id.rs +++ /dev/null @@ -1,199 +0,0 @@ -use core::fmt; -use interner::{ - shared::{SharedPool, SharedString, SharedVecString}, - Pooled, -}; -use std::collections::hash_map::RandomState; -use std::path::Path; -use std::{collections::binary_heap::Iter, fmt::write, hash::Hash}; - -use crate::error::{MizeError, MizeResult, MizeResultTrait}; -use crate::{ - instance::{store::Store, Mize}, - mize_err, -}; - -#[derive(Debug, Clone, Hash, Eq, PartialEq)] -pub struct MizeId { - pub path: SharedVecString, - pub namespace: Namespace, -} - -#[derive(Debug, Clone, Hash, Eq, PartialEq)] -pub struct Namespace(pub SharedString); - -impl Namespace { - pub fn as_string(&self) -> SharedString { - self.0.clone() - } - pub fn as_real_string(&self) -> String { - let a = self.as_string(); - let b = a.to_string(); - return b; - } -} - -pub trait IntoMizeId { - fn to_mize_id(self, instance: &Mize) -> MizeResult; -} - -impl MizeId { - pub fn store_part(&self) -> &str { - self.path - .iter() - .nth(0) - .expect("an empty MizeId found, that should absolutely not be possible!!!!") - .as_str() - } - - pub fn nth_part(&self, n: usize) -> MizeResult<&str> { - match self.path.iter().nth(n) { - Some(val) => Ok(val.as_str()), - None => Err(mize_err!("id does not have {} parts", n)), - } - } - - pub fn path(&self) -> SharedVecString { - self.path.clone() - } - - pub fn after_store_part(&self) -> Vec { - let tmp = self.path(); - let mut path_iter = tmp.into_iter(); - path_iter.next(); - let new_path: Vec = path_iter.map(|v| v.to_owned()).collect(); - - return new_path; - } - - pub fn namespace(&self) -> Namespace { - self.namespace.clone() - } - - pub fn namespace_str(&self) -> &str { - &self.namespace.0 - } -} - -impl fmt::Display for MizeId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.path.join("/")) - } -} - -impl IntoMizeId for &str { - fn to_mize_id(self, instance: &Mize) -> MizeResult { - instance.id_from_string(self.to_owned()) - } -} - -impl IntoMizeId for String { - fn to_mize_id(self, instance: &Mize) -> MizeResult { - instance.id_from_string(self) - } -} -impl IntoMizeId for &String { - fn to_mize_id(self, instance: &Mize) -> MizeResult { - instance.id_from_string(self.to_owned()) - } -} -impl IntoMizeId for Vec { - fn to_mize_id(self, instance: &Mize) -> MizeResult { - instance.id_from_vec_string(self) - } -} -impl IntoMizeId for Vec<&String> { - fn to_mize_id(self, instance: &Mize) -> MizeResult { - let owned = self - .into_iter() - .map(|s| s.to_owned()) - .collect::>(); - instance.id_from_vec_string(owned) - } -} -impl IntoMizeId for &[&str] { - fn to_mize_id(self, instance: &Mize) -> MizeResult { - let mut vec: Vec = Vec::new(); - for i in self { - vec.push((*i).to_owned()) - } - instance.id_from_vec_string(vec) - } -} -impl IntoMizeId for Vec<&str> { - fn to_mize_id(self, instance: &Mize) -> MizeResult { - let mut vec: Vec = Vec::new(); - for i in self { - vec.push((*i).to_owned()) - } - instance.id_from_vec_string(vec) - } -} -impl IntoMizeId for MizeId { - fn to_mize_id(self, instance: &Mize) -> MizeResult { - Ok(self) - } -} - -// would only work with a global id_pool -// for now use Instance::new_id() -//impl> From for MizeId { -//fn from(value: T) -> Self { -//let string = value.into(); -//let path: Vec = string.split("/").map(|v| v.to_owned()).collect(); -//return MizeId { MIZE_ID_POOL.get(path) } -//} -//} - -#[cfg(test)] -mod test { - use crate::instance::Mize; - - use super::*; - - #[test] - fn test_id() -> MizeResult<()> { - let instance = Mize::empty()?; - - let id_one = instance.new_id("0/config/hi")?; - assert_eq!(instance.get_namespace()?, id_one.namespace()); - assert_eq!("0", id_one.store_part()); - assert_eq!( - vec!["config".to_owned(), "hi".to_owned()], - id_one.after_store_part() - ); - - let id_two = instance.new_id("test.ns:hello/config/hi")?; - assert_eq!( - instance.namespace_from_string("test.ns".to_owned())?, - id_two.namespace() - ); - assert_eq!("hello", id_two.store_part()); - assert_eq!( - vec!["config".to_owned(), "hi".to_owned()], - id_one.after_store_part() - ); - - let id_three = instance.new_id("0/")?; - assert_eq!(instance.get_namespace()?, id_three.namespace()); - assert_eq!("0", id_three.store_part()); - assert_eq!(Vec::::new(), id_three.after_store_part()); - - let id_four = instance.new_id("test.ns:0/")?; - assert_eq!( - instance.namespace_from_string("test.ns".to_owned())?, - id_four.namespace() - ); - assert_eq!("0", id_four.store_part()); - assert_eq!(Vec::::new(), id_four.after_store_part()); - - let id_fife = instance.new_id("0")?; - assert_eq!(instance.get_namespace()?, id_fife.namespace()); - assert_eq!("0", id_fife.store_part()); - assert_eq!(Vec::::new(), id_fife.after_store_part()); - - //TODO: add the parsing form mize:// urls.... - - Ok(()) - } -} diff --git a/src/core/instance/connection.rs b/src/core/instance/connection.rs deleted file mode 100644 index 32c9e47..0000000 --- a/src/core/instance/connection.rs +++ /dev/null @@ -1,57 +0,0 @@ -use flume::{Receiver, Sender}; -use tracing::{debug, error, info, trace, warn}; - -use crate::error::{IntoMizeResult, MizeError, MizeResult}; -use crate::id::Namespace; -use crate::mize_err; -use crate::proto::MizeMessage; - -use super::Mize; -use crate::item::{get_raw_from_cbor, Item, ItemData}; - -// only created with Instance::new_connection() -#[derive(Clone, Debug)] -pub struct Connection { - pub tx: Sender, - pub id: u64, - pub ns: Option, -} - -pub trait ConnListener: Send + Sync { - fn listen(self, instance: Mize) -> MizeResult<()>; -} - -impl Connection { - pub fn send(&self, msg: MizeMessage) -> MizeResult<()> { - Ok(self.tx.send(msg)?) - } -} - -pub fn value_raw_con_by_id(item: &mut Item) -> MizeResult { - if item.id().nth_part(3)? == "peer" { - return value_raw_from_peer(item); - } else { - return Err(mize_err!("id with path: '{}' is not supported", item.id())); - } -} - -pub fn value_raw_from_peer(item: &mut Item) -> MizeResult { - let id = item.id(); - - let conn_id_str = id.nth_part(2)?; - let conn_id: u64 = conn_id_str.parse()?; - let tmp_path = id.path(); - let mut new_id_str = tmp_path.into_iter(); - let skipped = new_id_str.skip(4); - let new_id = item.instance.new_id(skipped.collect::>())?; - - let connection = item.instance.get_connection(conn_id)?; - - let msg = MizeMessage::new_get(new_id.clone(), connection.id); - - connection.tx.send(msg)?; - - let data = item.instance.give_msg_wait(new_id)?; - - return Ok(data); -} diff --git a/src/core/instance/mod.rs b/src/core/instance/mod.rs deleted file mode 100644 index 47b67de..0000000 --- a/src/core/instance/mod.rs +++ /dev/null @@ -1,1071 +0,0 @@ -use async_trait::async_trait; -use colored::Colorize; -use core::fmt; -use flume::{bounded, unbounded, Receiver, Sender}; -use interner::shared::{StringPool, VecStringPool}; -use mize_macros::mize_part; -use std::any::Any; -use std::collections::HashMap; -use std::fs::create_dir; -use std::fs::File; -use std::ops::{Deref, DerefMut}; -use std::path::{Path, PathBuf}; -use std::sync::{Arc, Mutex}; -use std::thread::panicking; -use std::{thread, vec}; -use tracing::{debug, error, info, trace, warn, Instrument}; -use uuid::Uuid; - -use crate::config::ConfigOptNameAndMize; -use crate::config::{gather_config, ConfigOpt}; -use crate::error::{IntoMizeResult, MizeError, MizeResult, MizeResultTrait}; -use crate::id::{IntoMizeId, MizeId, Namespace}; -use crate::instance::store::Store; -use crate::instance::subscription::Subscription; -use crate::instance::updater::Operation; -use crate::instance::updater::{updater_thread, updater_thread_async}; -use crate::item::{Item, ItemData}; -use crate::memstore::MemStore; -use crate::mize_err; -use crate::proto::MizeMessage; - -use self::connection::{ConnListener, Connection}; -use self::updater::handle_operation; - -#[cfg(feature = "async")] -use tokio::runtime::Handle; -#[cfg(feature = "async")] -use tokio::runtime::Runtime; - -use core::future::Future; -use std::thread::JoinHandle; - -pub mod connection; -pub mod msg_thread; -pub mod store; -pub mod subscription; -pub mod updater; - -#[cfg(test)] -mod tests; - -static MSG_CHANNEL_SIZE: usize = 200; - -static BUILD_TIME_CONFIG: &str = include_str!(std::env!("MIZE_BUILD_CONFIG")); - -/// The Instance type is the heart of the mize system -#[derive(Clone)] -pub struct Mize { - // a bit a lot of Mutexes isn't it??? - pub(crate) store: Arc>>, - connections: Arc>>, - next_con_id: Arc>, - subs: Arc>>>, - pub(crate) id_pool: Arc>, - pub(crate) namespace_pool: Arc>, - - pub(crate) listeners: Arc< - Mutex MizeResult<()> + Send + Sync>>>, - >, - - pub parts: Arc>>>>, - //pub(crate) platform: Arc>>, // should we do that instead of all the #cfg(faturs=targt-smth) in lib.rs - part_names: Arc>>, // exists, so that we know the ordering in which parts were loaded - - pub(crate) config_opts: Arc>>, - - // the namespace the instance operates in - pub(crate) namespace: Arc>, - - // the namespace of the instance itself - // TODO: set to a random uuid - pub(crate) self_namespace: Arc>, - pub(crate) op_tx: Sender, - threads: Arc>>)>>>, - next_thread_id: Arc>, - give_msg_wait: Arc>>>>, - create_msg_wait: Arc>>>, - - #[cfg(feature = "async")] - pub(crate) runtime: Arc>, -} - -// the public Mize API - -pub struct InstanceRef { - inner: Arc>, -} - -pub struct InstanceAsync { - inner: Arc>, -} - -pub struct DynMizePartGuard { - pub mize: Mize, - pub part: Option>, -} - -pub struct MizePartGuard { - pub mize: Mize, - pub part: Option, -} - -impl Deref for MizePartGuard { - type Target = T; - - fn deref(&self) -> &Self::Target { - &*self.part.as_ref().unwrap() - } -} - -impl DerefMut for MizePartGuard { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut *self.part.as_mut().unwrap() - } -} - -impl Drop for MizePartGuard { - fn drop(&mut self) { - if self.part.is_none() { - return; - } - let part = self.part.take().unwrap(); - self.mize.give_back_part(Box::new(part)); - } -} - -impl Deref for DynMizePartGuard { - type Target = dyn MizePart + Send + Sync; - - fn deref(&self) -> &Self::Target { - &*self.part.as_deref().unwrap() - } -} - -impl DerefMut for DynMizePartGuard { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut *self.part.as_deref_mut().unwrap() - } -} - -impl Drop for DynMizePartGuard { - fn drop(&mut self) { - if self.part.is_none() { - return; - } - self.mize.give_back_part(self.part.take().unwrap()); - } -} - -pub trait MizePartCreateGenerated: Sized { - fn create_generated(mize: Mize) -> Self; -} -pub trait MizePartGenerated { - fn name_generated(&self) -> &'static str; - fn get_mize_generated(&mut self) -> &mut Mize; - fn as_any_generated(&self) -> &dyn Any; - fn as_any_mut_generated(&mut self) -> &mut dyn Any; - fn into_any_generated(self: Box) -> Box; -} - -pub trait MizePartCreate: MizePartCreateGenerated + MizePart + 'static { - fn create(mize: &mut Mize) -> MizeResult> { - Ok(Box::new(Self::create_generated(mize.clone()))) - } -} - -pub trait MizePartCreateThisSucks: MizePartCreate + MizePart + 'static { - fn create_this_sucks(mize: &mut Mize) -> MizeResult> { - Self::create(mize) - } -} - -pub struct EmptyPart { - pub(crate) mize: Mize, -} -impl MizePartGenerated for EmptyPart { - fn name_generated(&self) -> &'static str { - "empty" - } - fn get_mize_generated(&mut self) -> &mut Mize { - &mut self.mize - } - fn as_any_generated(&self) -> &dyn Any { - self - } - fn as_any_mut_generated(&mut self) -> &mut dyn Any { - self - } - fn into_any_generated(self: Box) -> Box { - self - } -} - -impl MizePart for EmptyPart {} - -#[async_trait] -pub trait MizePart: MizePartGenerated { - fn name(&self) -> &'static str { - self.name_generated() - } - fn get_mize(&mut self) -> &mut Mize { - self.get_mize_generated() - } - fn as_any(&self) -> &dyn Any { - self.as_any_generated() - } - fn as_any_mut(&mut self) -> &mut dyn Any { - self.as_any_mut_generated() - } - fn into_any(self: Box) -> Box { - self.into_any_generated() - } - fn init(&mut self, mize: &mut Mize) -> MizeResult<()> { - Ok(()) - } - fn run(&mut self, mize: &mut Mize) -> MizeResult<()> { - Ok(()) - } - fn deps(&self) -> &'static [&'static str] { - &[] - } - fn opts(&self, mize: &mut Mize) { - () - } - async fn async_run(&mut self, mize: &mut Mize) -> MizeResult<()> { - Ok(()) - } - async fn async_init(&mut self, mize: &mut Mize) -> MizeResult<()> { - Ok(()) - } -} - -impl Mize { - pub fn empty() -> MizeResult { - let id_pool = Arc::new(Mutex::new(VecStringPool::default())); - let namespace_pool_raw = StringPool::default(); - let connections = Arc::new(Mutex::new(Vec::new())); - let subs = Arc::new(Mutex::new(HashMap::new())); - let (op_tx, op_rx) = unbounded(); - let give_msg_wait = Arc::new(Mutex::new(HashMap::new())); - let create_msg_wait = Arc::new(Mutex::new(None)); - let namespace = Arc::new(Mutex::new(Namespace( - namespace_pool_raw.get("mize.default.namespace"), - ))); - let self_namespace = Arc::new(Mutex::new(Namespace( - namespace_pool_raw.get("mize.default.namespace"), - ))); - - let mut instance = Mize { - store: Arc::new(Mutex::new(Box::new(MemStore::new()))), - parts: Arc::new(Mutex::new(HashMap::new())), - part_names: Arc::new(Mutex::new(Vec::new())), - config_opts: Arc::new(Mutex::new(HashMap::new())), - listeners: Arc::new(Mutex::new(HashMap::new())), - connections, - subs, - id_pool, - namespace, - self_namespace, - op_tx, - namespace_pool: Arc::new(Mutex::new(namespace_pool_raw)), - threads: Arc::new(Mutex::new(Vec::new())), - next_thread_id: Arc::new(Mutex::new(0)), - next_con_id: Arc::new(Mutex::new(1)), - give_msg_wait, - create_msg_wait, - - #[cfg(feature = "async")] - #[cfg(not(feature = "target-js"))] - runtime: Arc::new(Mutex::new( - Runtime::new().mres_msg("Could not create async runtime")?, - )), - }; - - #[cfg(feature = "target-os")] - { - let instance_clone = instance.clone(); - let op_rx_clone = op_rx.clone(); - let closure = move || updater_thread(op_rx_clone, &instance_clone); - instance.spawn_background("updater_thread", closure)?; - - let instance_clone_two = instance.clone(); - let closure_two = move || updater_thread(op_rx, &instance_clone_two); - instance.spawn_background("updater_thread", closure_two)?; - } - - // set up async update "threads" when using wasm - #[cfg(feature = "target-wasm ")] - { - let instance_clone = instance.clone(); - let op_rx_clone = op_rx.clone(); - wasm_bindgen_futures::spawn_local(updater_thread_async(op_rx_clone, instance_clone)); - - let instance_clone_two = instance.clone(); - wasm_bindgen_futures::spawn_local(updater_thread_async(op_rx, instance_clone_two)); - } - - // will move the msg stuff into it's own thread - // like this it can deadlock.... if a msg waits on an operation to complete - //let msg_instance_clone = instance.clone(); - //let msg_closure = move || msg_thread(op_rx, instance_clone); - //instance.spawn("msg_thread", closure)?; - - #[cfg(feature = "target-wasm ")] - console_log!("before loading build time config"); - - // load the config from build time - let config = ItemData::from_toml(BUILD_TIME_CONFIG)?; - instance.set_blocking("0", config); - - #[cfg(feature = "target-wasm ")] - console_log!("after loading build time config"); - - return Ok(instance); - } - - pub fn new() -> MizeResult { - trace!("[ {} ] Instance::new()", "CALL".yellow()); - - let mut instance = Mize::empty()?; - - instance.init()?; - - debug!( - "instance inited with config: {}", - instance.get("0/config")?.as_data_full()? - ); - - return Ok(instance); - } - - pub fn get_part(&mut self, name: &str) -> MizeResult { - match self.parts.lock().unwrap().get_mut(name) { - Some(part) => Ok(DynMizePartGuard { - part: Some(part.take().unwrap()), - mize: self.clone(), - }), - None => Err(mize_err!("Part '{name}' not found or currently taken")), - } - } - pub fn has_part(&mut self, name: &str) -> bool { - self.parts.lock().unwrap().contains_key(name) - } - pub fn add_part(&mut self, part: Box) -> MizeResult<()> { - self.part_names.lock().unwrap().push(part.name()); - self.parts.lock().unwrap().insert(part.name(), Some(part)); - Ok(()) - } - pub fn register_part(&mut self, part: Box) -> MizeResult<()> { - self.part_names.lock().unwrap().push(part.name()); - self.parts.lock().unwrap().insert(part.name(), Some(part)); - Ok(()) - } - pub fn add_listener( - &mut self, - name: &str, - handler: Box MizeResult<()> + Send + Sync>, - ) -> MizeResult<()> { - println!("adding listener: {}", name); - let name = name.to_owned(); - let mut listeners = self.listeners.lock().unwrap(); - listeners.insert(name, Arc::new(handler)); - - Ok(()) - } - fn part_names(&mut self) -> Vec<&'static str> { - self.part_names.lock().unwrap().clone() - } - - pub(crate) fn give_back_part(&mut self, part: Box) { - self.parts.lock().unwrap().insert(part.name(), Some(part)); - } - - pub fn init(&mut self) -> MizeResult<()> { - // gather config options from all parts - gather_config(self)?; - - // platform specific init code - crate::platform::any::instance_init(self)?; - - // end of platform specific init code - - // load the modules, as specified in the parts config - match self - .get_config("parts") - .unwrap_or(ItemData::new()) - .value_string() - { - Ok(parts_to_load) => { - for part_name in parts_to_load.split(" ") { - if part_name.trim().is_empty() { - continue; - } - self.load_part(part_name)?; - } - } - Err(err) => { - // no parts to load - } - } - - debug!("MIZE INIT DONE"); - Ok(()) - } - - pub fn with_config(config: ItemData) -> MizeResult { - trace!("[ {} ] Instance::with_config()", "CALL".yellow()); - trace!("config: {}", config); - println!("here ...."); - - let mut mize = Mize::empty()?; - - let mut opts = mize.config_opts.lock().unwrap(); - let mut config = config.clone(); - for mut path in config.get_paths_recursive()? { - if path.starts_with("/") { - path.remove(0); - } - let path_split = path - .split("/") - .map(|s| s.to_owned()) - .collect::>(); - let path_string = path_split.join("."); - if let Ok(val) = config.get_path(path_split) { - let opt = ConfigOpt { - name: path.clone(), - val: Some(val), - thunk: None, - }; - opts.insert(path_string, opt); - } - } - drop(opts); - - mize.init()?; - - Ok(mize) - } - - pub fn migrate_to_store(&self, new_store: Box) -> MizeResult<()> { - info!("MIGRATING"); - let mut old_store = self.store.lock()?; - - let id = self.id_from_string("0".to_owned())?; - let inst_data = old_store.get_value_data_full(id.clone())?; - new_store.set(id, inst_data.to_owned())?; - - for id in old_store.id_iter()? { - let data = old_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())?; - } - - *old_store = new_store; - - Ok(()) - } - - pub fn new_item(&self) -> MizeResult { - if self.get_namespace()? != self.get_self_namespace()? { - // need to send create msg and wait for it - let mut connection = self.get_connection_by_ns(self.get_namespace()?)?; - - let msg = MizeMessage::new_create(connection.id); - - connection.send(msg)?; - - let (tx, rx) = bounded::(1); - - let mut msg_wait_inner = self.create_msg_wait.lock()?; - *msg_wait_inner = Some(tx); - drop(msg_wait_inner); - - let id = rx.recv()?; - println!("new_item namespace: {:?}", id.namespace()); - - return Ok(Item::new(id, self)); - } - - let store_inner = self.store.lock()?; - let id = self.id_from_string(store_inner.new_id()?)?; - return Ok(Item::new(id, self)); - } - - pub fn get(&self, id: I) -> MizeResult { - let id = id.to_mize_id(self)?; - return Ok(Item::new(id, &self)); - } - - pub fn set>(&self, id: I, value: V) -> MizeResult<()> { - let id = id.to_mize_id(self)?; - self.op_tx.send(Operation::Set(id, value.into(), None)); - Ok(()) - } - - pub fn set_blocking>( - &self, - id: I, - value: V, - ) -> MizeResult<()> { - handle_operation( - &mut Operation::Set(id.to_mize_id(self)?, value.into(), None), - self, - )?; - Ok(()) - } - - pub fn sub(&self, id: I, sub: Subscription) -> MizeResult<()> { - let mut subs_inner = self.subs.lock()?; - let id = id.to_mize_id(self)?; - match subs_inner.get_mut(&id) { - Some(vec) => { - vec.push(sub); - } - None => { - subs_inner.insert(id.clone(), vec![sub]); - } - } - - // if we are not the owner of this item, send a sub msg to them - if !self.we_are_namespace()? { - let con = self.get_connection_by_ns(id.namespace())?; - let msg = MizeMessage::new_sub(id, con.id); - con.send(msg)?; - } - - Ok(()) - } - - pub fn new_id(&self, value: T) -> MizeResult { - value.to_mize_id(self) - } - - pub fn id_from_string(&self, string: String) -> MizeResult { - let vec_string: Vec = string - .split("/") - .map(|v| v.to_owned()) - .filter(|el| el.as_str() != "") - .collect(); - self.id_from_vec_string(vec_string) - } - - pub fn id_from_vec_string(&self, mut vec_string: Vec) -> MizeResult { - let id_pool_inner = self.id_pool.lock()?; - let namespace_inner = self.namespace.lock()?; - let first_el = vec_string - .first_mut() - .ok_or(mize_err!("MizeId was empty"))?; - - let id = if first_el.contains(":") { - // first el is a namespace + store_part - let new_first_el = first_el.clone(); - let vec: Vec<&str> = new_first_el.split(":").collect(); - let ns_part = vec - .iter() - .nth(0) - .ok_or(mize_err!("should really not happen"))?; - let store_part = vec.iter().nth(1).ok_or(mize_err!( - "mizeid was like 'namespace:/hi', why are you doing that" - ))?; - *first_el = store_part.to_owned().to_owned(); - - MizeId { - path: id_pool_inner.get(vec_string), - namespace: self.namespace_from_string(ns_part.to_owned().to_owned())?, - } - } else { - MizeId { - path: id_pool_inner.get(vec_string), - namespace: namespace_inner.clone(), - } - }; - trace!("new MizeId made: {:?}", id); - - Ok(id) - } - - pub fn load_part(&mut self, name: &str) -> MizeResult<()> { - if let Ok(path) = self - .get_config(&format!("part_dir.{}", name))? - .value_string() - { - crate::platform::any::load_part(self, name, Some(path)) - } else { - crate::platform::any::load_part(self, name, None) - } - } - - pub fn fetch_part(&mut self, name: &str) -> MizeResult { - // platform specific way to fetch a module - crate::platform::any::fetch_part(self, name) - } - - pub fn load_part_at(&mut self, name: &str, path: String) -> MizeResult<()> { - // platform specific init code - crate::platform::any::load_part(self, name, Some(path)) - } - - pub fn namespace_from_string(&self, ns_str: String) -> MizeResult { - let namespace_pool_inner = self.namespace_pool.lock()?; - let namespace = Namespace(namespace_pool_inner.get(ns_str)); - Ok(namespace) - } - - pub fn set_namespace(&self, ns: Namespace) -> MizeResult<()> { - let mut namespace_inner = self.namespace.lock()?; - *namespace_inner = ns; - - Ok(()) - } - - pub fn get_namespace(&self) -> MizeResult { - let mut namespace_inner = self.namespace.lock()?; - return Ok(namespace_inner.clone()); - } - - pub fn get_self_namespace(&self) -> MizeResult { - let mut self_namespace_inner = self.self_namespace.lock()?; - return Ok(self_namespace_inner.clone()); - } - - pub fn we_are_namespace(&self) -> MizeResult { - Ok(self.get_namespace()? == self.get_self_namespace()?) - } - - pub fn add_conn_listener(&mut self, listener: T) -> MizeResult<()> { - let mut instance_clone = self.clone(); - self.spawn_background("some_listener", move || listener.listen(instance_clone)); - Ok(()) - } - - pub fn new_connection(&self, tx: Sender) -> MizeResult { - let mut conn_inner = self.connections.lock()?; - let mut next_con_id = self.next_con_id.lock()?; - let old_next_con_id = *next_con_id; - - let connection = Connection { - id: next_con_id.to_owned(), - tx, - ns: None, - }; - conn_inner.push(connection); - *next_con_id += 1; - Ok(old_next_con_id) - } - - pub fn new_connection_join_namespace(&self, tx: Sender) -> MizeResult { - let conn_id = self.new_connection(tx)?; - - let ns_of_peer_str = self - .get(format!( - "inst/con_by_id/{}/peer/self/config/namespace", - conn_id - ))? - .value_string()?; - let ns_of_peer = self.namespace_from_string(ns_of_peer_str)?; - - self.connection_set_namespace(conn_id, ns_of_peer.clone()); - self.set_namespace(ns_of_peer); - - Ok(conn_id) - } - - pub fn connection_set_namespace(&self, conn_id: u64, namespace: Namespace) -> MizeResult<()> { - let mut connection = self.get_connection(conn_id)?; - connection.ns = Some(namespace); - self.set_connection(conn_id, connection); - Ok(()) - } - - pub fn got_msg(&self, msg: MizeMessage) -> MizeResult<()> { - Ok(self.op_tx.send(Operation::Msg(msg))?) - } - - pub fn report_err(&self, err: MizeError) { - #[cfg(feature = "target-js")] unsafe { - use wasm_bindgen::prelude::wasm_bindgen; - #[wasm_bindgen] - extern "C" { - #[wasm_bindgen(js_namespace = console)] - fn log(s: &str); - } - - macro_rules! console_log { - // Note that this is using the `log` function imported above during - // `bare_bones` - ($($t:tt)*) => ({ log(&format_args!($($t)*).to_string())}) - } - console_log!("reported_err: {:?}", err); - } - err.log(); - } - - fn set_connection(&self, conn_id: u64, new_connection: Connection) -> MizeResult<()> { - let mut conn_inner = self.connections.lock()?; - - for connection in conn_inner.iter_mut() { - if connection.id == conn_id { - *connection = new_connection; - return Ok(()); - } - } - - return Err(mize_err!( - "Connection with id {} not known to instance", - conn_id - )); - Ok(()) - } - - pub fn get_connection(&self, conn_id: u64) -> MizeResult { - let mut conn_inner = self.connections.lock()?; - - for connection in conn_inner.iter() { - if connection.id == conn_id { - return Ok(connection.clone()); - } - } - - return Err(mize_err!( - "Connection with id {} not known to instance", - conn_id - )); - } - - pub fn get_connection_by_ns(&self, ns: Namespace) -> MizeResult { - let mut conn_inner = self.connections.lock()?; - - for connection in conn_inner.iter() { - if connection.ns == Some(ns.clone()) { - return Ok(connection.clone()); - } - } - - return Err(mize_err!( - "Connection with namespace {} not known to instance", - ns.as_string() - )); - } - - pub fn spawn_and_wait( - &mut self, - name: &str, - func: impl FnOnce() -> MizeResult<()> + Send + 'static, - ) -> MizeResult<()> { - let mize_clone = self.clone(); - let mut threads_inner = self.threads.lock()?; - let mut next_thread_id = self.next_thread_id.lock()?; - - let my_thread_id_no_mutex_guard = *next_thread_id; - let thread_mutex = self.threads.clone(); - let name_to_move = name.to_owned(); - let to_spawn = move || -> MizeResult<()> { - debug!("spawning thread: {}", name_to_move); - let my_thread_id = my_thread_id_no_mutex_guard; - - if let Err(err) = func() { - mize_clone.report_err(err); - } - - //let mut threads_inner = thread_mutex.lock()?; - /* - *threads_inner = threads_inner - .clone() - .into_iter() - .filter(|el| match el { - (my_thread_id, _) => false, - (_, _) => true, - }) - .collect(); - */ - debug!("thread '{}' stopped", name_to_move); - Ok(()) - }; - - *next_thread_id += 1; - - #[cfg(feature = "target-os")] - let handle = thread::spawn(move || to_spawn()); - - #[cfg(feature = "target-os")] - threads_inner.push((*next_thread_id, name.to_owned(), Some(handle))); - - #[cfg(feature = "target-wasm ")] - { - //console_log!("in instance::spawn with wasm target") - } - //NOT WELL SUPPORTED - //crate::platform::wasm::wasm_spawn(to_spawn)?; - - Ok(()) - } - - pub fn spawn_background( - &mut self, - name: &str, - func: impl FnOnce() -> MizeResult<()> + Send + 'static, - ) -> MizeResult<()> { - let mut threads_inner = self.threads.lock()?; - let mut next_thread_id = self.next_thread_id.lock()?; - - let my_thread_id_no_mutex_guard = *next_thread_id; - let thread_mutex = self.threads.clone(); - let name_to_move = name.to_owned(); - let to_spawn = move || -> () { - debug!("spawning thread: {}", name_to_move); - let my_thread_id = my_thread_id_no_mutex_guard; - - let res = func(); - if let Err(e) = res { - e.log(); - } - - //let mut threads_inner = thread_mutex.lock()?; - /* - *threads_inner = threads_inner - .clone() - .into_iter() - .filter(|el| match el { - (my_thread_id, _) => false, - (_, _) => true, - }) - .collect(); - */ - debug!("thread '{}' stopped", name_to_move); - }; - - *next_thread_id += 1; - - #[cfg(feature = "target-os")] - thread::spawn(move || to_spawn()); - - threads_inner.push((*next_thread_id, name.to_owned(), None)); - - #[cfg(feature = "target-wasm ")] - { - //console_log!("in instance::spawn with wasm target") - } - //NOT WELL SUPPORTED - //crate::platform::wasm::wasm_spawn(to_spawn)?; - - Ok(()) - } - - pub fn give_msg_wait(&self, id: MizeId) -> MizeResult { - let mut give_msg_wait_inner = self.give_msg_wait.lock()?; - - let (tx, rx) = bounded::(1); - - let vec = match give_msg_wait_inner.get_mut(&id) { - Some(vec) => vec, - None => { - give_msg_wait_inner.insert(id.clone(), Vec::new()); - give_msg_wait_inner.get_mut(&id).unwrap() - } - }; - - vec.push(tx); - - // so that another thread can also give_msg_wait(), while we wait in the recv() of rx - drop(vec); - drop(give_msg_wait_inner); - - let data = rx.recv()?; - - return Ok(data); - } - - #[cfg(feature = "async")] - pub fn spawn_async + Send + 'static>( - &mut self, - name: &str, - func: F, - ) -> MizeResult<()> { - let mut threads_inner = self.threads.lock()?; - let mut next_thread_id = self.next_thread_id.lock()?; - - threads_inner.push((*next_thread_id, name.to_owned(), None)); - let runtime_inner = self.runtime.lock().unwrap(); - runtime_inner.spawn(func); - - *next_thread_id += 1; - - Ok(()) - } - - #[cfg(feature = "async")] - pub fn async_get_handle(&self) -> Handle { - let runtime_inner = self.runtime.lock().unwrap(); - let handle = runtime_inner.handle().to_owned(); - handle - } - - #[cfg(feature = "async")] - pub fn spawn_async_blocking< - F: Future + Send + Sync + 'static, - >( - &mut self, - name: &str, - func: F, - ) -> F::Output { - let mut threads_inner = self - .threads - .lock() - .expect("mutex lock failed in spawn_async_blocking"); - let mut next_thread_id = self - .next_thread_id - .lock() - .expect("mutex lock failed in spawn_async_blocking"); - - threads_inner.push((*next_thread_id, name.to_owned(), None)); - let runtime_inner = self.runtime.lock().unwrap(); - let handle = runtime_inner.handle().to_owned(); - *next_thread_id += 1; - - drop(runtime_inner); - drop(threads_inner); - drop(next_thread_id); - - let result = handle.block_on(func); - - return result; - } - - pub fn wait(&self) { - info!("Instance main thread waiting"); - loop { - thread::sleep_ms(10000000) - } - } - - pub fn report_error(err: MizeError) { - err.log(); - } - - pub fn get_config(&mut self, name: &str) -> MizeResult { - let mut config_opts = self.config_opts.lock().unwrap(); - - let opt = config_opts - .get_mut(name) - .ok_or_else(|| mize_err!("Config opt for {name} not in config_opts"))?; - - // get the cached value - if let Some(val) = opt.val.clone() { - //println!("get_config: {name} has cached value: {val}"); - return Ok(val); - } - - // Evaluate the thunk - let thunk = opt - .thunk - .take() - .ok_or_else(|| mize_err!("ConfigOpt {name} does not have a thunk"))?; - let result = thunk(); - - // Cache the result - opt.val = Some(result.clone()); - - return Ok(result); - } - - pub fn new_opt(&mut self, name: &str) -> ConfigOptNameAndMize { - let mut config_opts = self.config_opts.lock().unwrap(); - match config_opts.get_mut(name) { - Some(opt) => {} - None => { - let opt = ConfigOpt { - name: name.to_owned(), - val: None, - thunk: None, - }; - config_opts.insert(name.to_string(), opt); - } - } - ConfigOptNameAndMize { - name: name.to_string(), - mize: self.clone(), - } - } - - pub fn run(&mut self) -> MizeResult<()> { - let part_names = self.part_names(); - for part_name in part_names { - let mut part = self.get_part(part_name)?; - //println!("running part {part_name}"); - part.run(&mut self.clone())?; - } - let mut threads_inner = self.threads.lock().unwrap(); - for (id, name, handle) in threads_inner.drain(..) { - if let Some(handle) = handle { - handle.join().unwrap()?; - } - } - Ok(()) - } - - pub fn get_part_native( - &mut self, - name: &str, - ) -> MizeResult> { - let mut dyn_guard = self.get_part(name)?; - let part = dyn_guard.part.take().unwrap(); - drop(dyn_guard); - let concrete_part = part - .into_any() - .downcast::() - .map_err(|_| mize_err!("failed to downcast"))?; - Ok(MizePartGuard { - mize: self.clone(), - part: Some(*concrete_part), - }) - } - pub fn add_name_only_part(&mut self, name: &'static str) { - let part = NameOnlyPart { - mize: self.clone(), - name, - }; - self.add_part(Box::new(part)); - } - pub fn id_path(&self, id: &MizeId) -> MizeResult { - Ok(id.path().join("/")) - } -} - -#[derive(Default)] -struct NameOnlyPart { - mize: Mize, - name: &'static str, -} - -impl MizePart for NameOnlyPart {} -impl MizePartGenerated for NameOnlyPart { - fn as_any_generated(&self) -> &dyn Any { - self.as_any() - } - fn as_any_mut_generated(&mut self) -> &mut dyn Any { - self.as_any_mut() - } - fn get_mize_generated(&mut self) -> &mut Mize { - &mut self.mize - } - fn into_any_generated(self: Box) -> Box { - self.into_any() - } - fn name_generated(&self) -> &'static str { - self.name - } -} - -impl fmt::Debug for Mize { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Mize Instance with subs: {:?}", self.subs,) - } -} - -impl Default for Mize { - fn default() -> Self { - Self::empty().unwrap() - } -} diff --git a/src/core/instance/msg_thread.rs b/src/core/instance/msg_thread.rs deleted file mode 100644 index 139597f..0000000 --- a/src/core/instance/msg_thread.rs +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/src/core/instance/store.rs b/src/core/instance/store.rs deleted file mode 100644 index f17c837..0000000 --- a/src/core/instance/store.rs +++ /dev/null @@ -1,71 +0,0 @@ -use dyn_clone::DynClone; -use std::fmt::Debug; -use std::iter::Map; -use std::option::Iter; - -use crate::error::MizeResult; -use crate::id::MizeId; -use crate::instance::Mize; -use crate::item::get_raw_from_cbor; -use crate::item::{Item, ItemData}; -use crate::memstore::MemStore; - -dyn_clone::clone_trait_object!(Store); - -pub trait Store: DynClone + Send + Sync + Debug { - // should have the ability to be multi threaded, if the underlying implementation supports - // multithreaded IO operations - // for now all refs to a store hold a Mutex but this mutex is part of where the MizeStore trait - // is implemented, so that there can be a multithreaded implementation - //fn get(self, id: MizeId) -> MizeResult> where Self: Sized; - - fn set(&self, id: MizeId, data: ItemData) -> MizeResult<()>; - - // in the future should implement transactions, .... - - // funcs to do with links, backlinks - fn get_links(&self, item: Item) -> MizeResult>; - - fn get_backlinks(&self, item: Item) -> MizeResult>; - - fn new_id(&self) -> MizeResult; - - fn get_value_raw(&self, id: MizeId) -> MizeResult>; - - fn get_value_data_full(&self, id: MizeId) -> MizeResult; - - fn id_iter(&self) -> MizeResult; - - fn next_id(&self, prev_id: &str) -> MizeResult>; - - fn first_id(&self) -> MizeResult; -} - -pub struct IdIter { - cur_id: String, - store: Box, -} - -impl IdIter { - pub fn new(store: Box) -> MizeResult { - Ok(IdIter { - cur_id: store.first_id()?, - store, - }) - } -} - -impl Iterator for IdIter { - type Item = MizeResult; - - fn next(&mut self) -> Option { - match self.store.next_id(&self.cur_id) { - Err(err) => Some(Err(err)), - Ok(Some(new_id)) => { - self.cur_id = new_id.clone(); - Some(Ok(new_id)) - } - Ok(None) => None, - } - } -} diff --git a/src/core/instance/subscription.rs b/src/core/instance/subscription.rs deleted file mode 100644 index ddb7577..0000000 --- a/src/core/instance/subscription.rs +++ /dev/null @@ -1,68 +0,0 @@ -use core::fmt; -use flume::Sender; -use std::rc::Rc; -use std::sync::Arc; -use tracing::trace; - -use crate::error::MizeResult; -use crate::id::MizeId; -use crate::instance::connection::Connection; -use crate::item::Item; -use crate::proto::MizeMessage; - -use super::Mize; - -#[derive(Clone, Debug)] -pub struct Update { - pub instance: Arc, - pub id: MizeId, -} - -impl Update { - pub fn new_item(&self) -> MizeResult { - self.instance.get(self.id.clone()) - } -} - -pub enum Subscription { - Connection(Connection), - Closure(Box MizeResult<()> + Send>), - Channel(Sender), -} - -impl Subscription { - pub fn from_conn(conn: Connection) -> Subscription { - Subscription::Connection(conn) - } - pub fn from_closure(closure: Box MizeResult<()> + Send>) -> Subscription { - Subscription::Closure(closure) - } - pub fn from_sender(tx: Sender) -> Subscription { - Subscription::Channel(tx) - } - - pub fn handle(&mut self, update: Update) -> MizeResult<()> { - trace!("handleing update"); - match &self { - Subscription::Connection(conn) => { - let msg = MizeMessage::new_update( - update.id.clone(), - update.new_item()?.as_data_full()?, - conn.id, - ); - conn.send(msg)?; - } - Subscription::Closure(closure) => closure(update)?, - Subscription::Channel(tx) => { - tx.send(update); - } - } - Ok(()) - } -} - -impl fmt::Debug for Subscription { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "...Subscription...") - } -} diff --git a/src/core/instance/tests.rs b/src/core/instance/tests.rs deleted file mode 100644 index eb58952..0000000 --- a/src/core/instance/tests.rs +++ /dev/null @@ -1,263 +0,0 @@ -use tracing_subscriber::registry::Data; - -use crate::item::IntoItemData; - -use super::*; - -#[test] -fn test_sort_keys() -> MizeResult<()> { - let mut data = ItemData::from_toml( - r#" - [hi] - test = 4 - - [config] - zzz = "hiiii" - hi = "hello from config/hi" - - [config.test] - inner = "inner" - "#, - )?; - - let data_sorted = ItemData::from_toml( - r#" - [config] - hi = "hello from config/hi" - test = { inner = "inner" } - zzz = "hiiii" - - [hi] - test = 4 - "#, - )?; - - data.sort_keys()?; - - assert_eq!(data.to_json()?, data_sorted.to_json()?); - - Ok(()) -} - -#[test] -fn test_get_module_hash() -> MizeResult<()> { - let mut instance = Mize::empty()?; - - use crate::platform::os::get_part_hash; - let selector_toml = r#" - mize_version = "0.0.0" - system = "x86_64-unknown-linux-gnu" - toolchain_version = "rustc 1.78.0 (9b00956e5 2024-04-29)" - "#; - - instance.set_blocking("0/config/selector", ItemData::from_toml(&selector_toml)?)?; - - let (hash, selector) = get_part_hash(&mut instance, "String", ItemData::new())?; - - test_println!("hash: {}", hash); - test_println!("selector: {}", selector); - - assert_eq!(hash, "e96edf60216688314efc263c1aa8d6ce".to_owned()); - - Ok(()) -} - -#[test] -fn test_set_store_path() -> MizeResult<()> { - let instance = Mize::empty()?; - - let store_path = "/home/me/.mize".to_owned(); - - let config = instance.get("0/config")?.as_data_full()?; - - test_println!("data at 0/config: {}", config); - - instance.set_blocking("0/config/store_path", store_path.clone().into_item_data())?; - - let store_path_new = instance.get("0/config/store_path")?.value_string()?; - - assert_eq!(store_path_new, store_path); - - Ok(()) -} - -#[test] -fn test_set_sub_path() -> MizeResult<()> { - let instance = Mize::empty()?; - - let data = ItemData::from_toml( - r#" - [config] - hi = "hello from config/hi" - - [config.test] - inner = "inner" - "#, - )?; - - let data_two = ItemData::from_toml( - r#" - [config] - hi = "hello from config/hi" - - [config.test] - inner = "new inner" - "#, - )?; - - let item = instance.new_item()?; - instance.set_blocking(item.id(), data.clone())?; - - assert_eq!(item.as_data_full()?, data); - - // try to set a sub path of item - instance.set_blocking( - vec![item.id().store_part(), "config", "test", "inner"], - "new inner".into_item_data(), - )?; - - // the contents of item should then be like data_two - println!( - "item with id '{}': {}", - item.id(), - instance.get(vec![item.id().store_part()])?.as_data_full()? - ); - assert_eq!( - instance - .get(vec![item.id().store_part(), "config", "test", "inner"])? - .as_data_full()?, - ItemData::from_string("new inner") - ); - assert_eq!(item.as_data_full()?, data_two); - - Ok(()) -} - -#[test] -fn test_itemdata_set_path() -> MizeResult<()> { - let mut data = ItemData::from_toml( - r#" - [config] - hi = "hello from config/hi" - - [config.test] - inner = "inner" - "#, - )?; - - let data_two = ItemData::from_toml( - r#" - [config] - hi = "hello from config/hi" - - [config.test] - inner = "new inner" - "#, - )?; - - data.set_path( - vec!["config", "test", "inner"], - ItemData::from_string("new inner"), - )?; - - assert_eq!(data, data_two); - - Ok(()) -} - -#[test] -fn test_itemdata_merge() -> MizeResult<()> { - let mut data = ItemData::from_toml( - r#" - [config] - hi = "hello from config/hi" - - [config.test] - inner = "inner" - "#, - )?; - - let data_two = ItemData::from_toml( - r#" - [config] - hi = "hello from config/hi" - - [config.test] - inner = "new inner" - "#, - )?; - - assert_eq!( - data.get_path(vec!["config", "test", "inner"])?, - ItemData::from_string("inner") - ); - - data.merge(data_two.clone()); - - assert_eq!(data, data_two); - - assert_eq!( - data.get_path(vec!["config", "test", "inner"])?, - ItemData::from_string("new inner") - ); - - Ok(()) -} - -#[test] -fn test_item_merge() -> MizeResult<()> { - let instance = Mize::empty()?; - - let mut item = instance.new_item()?; - - // here the item should contain "empty" data - assert_eq!(item.as_data_full()?, ItemData::new()); - - let data = ItemData::from_toml( - r#" - [config] - hi = "hello from config/hi" - - [config.test] - inner = "inner" - "#, - )?; - - let data_two = ItemData::from_toml( - r#" - [config] - hi = "hello from config/hi" - - [config.test] - inner = "new inner" - "#, - )?; - - item.merge(data.clone())?; - - // now it should contain data - assert_eq!(item.as_data_full()?, data); - - let mut sub_item = instance.get(vec![item.id().store_part(), "config", "test", "inner"])?; - - // the sub item should have the string "inner" - assert_eq!(sub_item.as_data_full()?, ItemData::from_string("inner")); - - sub_item.merge(ItemData::from_string("new inner")); - - assert_eq!(sub_item.as_data_full()?, ItemData::from_string("new inner")); - - // also the item should be updated - assert_eq!(item.as_data_full()?, data_two); - - Ok(()) -} - -/* -#[test] -#[should_panic(expected = "correct panic")] -fn test_cant_set_non_existent_item() -> () { - let instance = Instance::empty().expect("wrong panic"); - instance.set_blocking("5", "hello world".into_item_data()).expect("correct panic"); -} -*/ diff --git a/src/core/instance/updater.rs b/src/core/instance/updater.rs deleted file mode 100644 index 64e08ee..0000000 --- a/src/core/instance/updater.rs +++ /dev/null @@ -1,236 +0,0 @@ -use flume::Receiver; -use std::borrow::BorrowMut; -use std::sync::Arc; -use tracing::{error, trace, warn}; - -use crate::error::{MizeError, MizeResult, MizeResultTrait}; -use crate::id::MizeId; -use crate::mize_err; -use crate::proto::{MessageCmd, MizeMessage}; -use crate::{instance::Mize, item::ItemData}; - -use super::connection::{self, Connection}; -use super::subscription::{Subscription, Update}; - -#[derive(Debug)] -pub enum Operation { - Set(MizeId, ItemData, Option), // bool: is_from_update_msg - Msg(MizeMessage), -} - -// console_log macro -// that can be copied into other files for debugging purposes -#[cfg(feature = "wasm-target")] -use wasm_bindgen::prelude::*; - -#[cfg(feature = "wasm-target")] -#[wasm_bindgen] -extern "C" { - #[wasm_bindgen(js_namespace = console)] - fn log(s: &str); -} - -#[cfg(feature = "wasm-target")] -macro_rules! console_log { - // Note that this is using the `log` function imported above during - // `bare_bones` - ($($t:tt)*) => (unsafe { log(&format_args!($($t)*).to_string())}) -} - -#[cfg(not(feature = "wasm-target"))] -macro_rules! console_log { - // Note that this is using the `log` function imported above during - // `bare_bones` - ($($t:tt)*) => {}; -} -//end of console_log macro - -pub async fn updater_thread_async(operation_rx: Receiver, instance: Mize) -> () { - let mut count = 0; - console_log!("inside an updater thread"); - - loop { - let mut operation = match operation_rx.recv_async().await { - Ok(val) => val, - Err(e) => { - instance.report_err(e.into()); - continue; - } - }; - - let op_str = match operation { - Operation::Set(_, _, _) => "SET", - Operation::Msg(_) => "MSG", - }; - - trace!("OPERATION {} - {}", count, op_str); - console_log!("OPERATION {} - {}", count, op_str); - - let result = handle_operation(&mut operation, &instance); - - trace!("OPERATION {} DONE", count); - count += 1; - - if let Err(err) = result { - error!("OPERATION {} FAILED: {:?}", count, operation); - err.log(); - } - } -} - -pub fn updater_thread(operation_rx: Receiver, instance: &Mize) -> MizeResult<()> { - let mut count = 0; - - loop { - let mut operation = operation_rx.recv()?; - let op_str = match operation { - Operation::Set(_, _, _) => "SET", - Operation::Msg(_) => "MSG", - }; - - trace!("OPERATION {} - {}", count, op_str); - - let result = handle_operation(&mut operation, instance); - - trace!("OPERATION {} DONE", count); - count += 1; - - if let Err(err) = result { - error!("OPERATION FAILED: {:?}", operation); - err.log(); - } - } - Ok(()) -} - -pub fn handle_operation(operation: &mut Operation, instance: &Mize) -> MizeResult<()> { - match operation { - Operation::Set(id, value, maybe_conn) => { - let item_data: ItemData = value.to_owned(); - let mut item = instance.get(id.clone())?; - item.merge(item_data)?; - - //check subs and handle them - let mut subs_inner = instance.subs.lock()?; - if let Some(vec) = subs_inner.get_mut(&id) { - let update = Update { - instance: Arc::new(instance.to_owned()), - id: id.clone(), - }; - for sub in vec.iter_mut() { - // don't handle sub of type connection, in case the update comes from this - // connection - if let Some(conn) = maybe_conn { - if let Subscription::Connection(conn2) = sub { - if conn.id == conn2.id { - continue; - } - } - } - - sub.handle(update.clone()); - } - } - } - Operation::Msg(msg) => handle_msg(msg, instance)?, - } - Ok(()) -} - -fn handle_msg(msg: &mut MizeMessage, instance: &Mize) -> MizeResult<()> { - match msg.cmd()? { - MessageCmd::Get => { - let id = msg.id(instance)?; - let mut connection = instance.get_connection(msg.conn_id)?.clone(); - let item = instance.get(id.clone())?; - let msg = MizeMessage::new_give(id, item.as_data_full()?, msg.conn_id); - connection.send(msg)?; - } - - MessageCmd::GetSub => { - let id = msg.id(instance)?; - let mut connection = instance.get_connection(msg.conn_id)?.clone(); - let item = instance.get(id.clone())?; - let msg = MizeMessage::new_give(id.clone(), item.as_data_full()?, msg.conn_id); - connection.send(msg)?; - let sub = Subscription::from_conn(connection.clone()); - instance.sub(id, sub)?; - } - - MessageCmd::Sub => { - let id = msg.id(instance)?; - let mut connection = instance.get_connection(msg.conn_id)?.clone(); - let sub = Subscription::from_conn(connection.clone()); - instance.sub(id, sub)?; - } - - MessageCmd::Update => { - let data = msg.data()?; - let id = msg.id(instance)?; - let connection = instance.get_connection(msg.conn_id)?; - instance - .op_tx - .send(Operation::Set(id.clone(), data, Some(connection))); - } - - // this should check, if the update is valid - // but for now, we do just always accept it - MessageCmd::UpdateRequest => { - let data = msg.data()?; - let id = msg.id(instance)?; - let connection = instance.get_connection(msg.conn_id)?; - instance - .op_tx - .send(Operation::Set(id.clone(), data, Some(connection))); - } - - MessageCmd::Give => { - let id = msg.id(instance)?; - let data = msg.data()?; - let give_msg_wait_inner = instance.give_msg_wait.lock()?; - if let Some(vec) = give_msg_wait_inner.get(&id) { - for tx in vec { - tx.send(data.clone()); - } - } else { - warn!( - "got give msg for id '{}', that has no one waiting for it", - id - ); - } - } - - MessageCmd::Create => { - println!("instance.store: {:?}", instance.clone().store); - let item = instance.new_item()?; - let reply_msg = MizeMessage::new_create_reply(item.id(), msg.conn_id); - let mut connection = instance.get_connection(msg.conn_id)?; - connection.send(reply_msg)?; - } - - MessageCmd::CreateReply => { - let create_msg_wait_inner = instance.create_msg_wait.lock()?; - if let Some(sender) = create_msg_wait_inner.as_ref() { - sender.send(msg.id(&mut instance.clone())?)?; - } - return Ok(()); - } - MessageCmd::Custom(type_val) => { - let listeners = instance.listeners.lock()?; - let type_str = type_val.value_string()?; - let msg = msg.clone(); - let mut mize = instance.clone(); - println!("type_str: {}", type_str); - println!("listeners: {:?}", listeners.keys()); - if let Some(listener) = listeners.get(&type_str) { - let listener = listener.clone(); - drop(listeners); - listener(msg, &mut mize)?; - } - } - _ => { - return Err(mize_err!("got a message, that is not handeled")); - } - } - Ok(()) -} diff --git a/src/core/item.rs b/src/core/item.rs deleted file mode 100644 index 346e605..0000000 --- a/src/core/item.rs +++ /dev/null @@ -1,818 +0,0 @@ -use crate::config::ConfigOpt; -use colored::Colorize; -use core::fmt; -use serde::Deserialize; -use serde::Serialize; -use std::fmt::Debug; -use std::fs::File; -use std::io; -use std::rc::Rc; -use std::{collections::HashMap, fmt::Display, io::Cursor, path::PathBuf}; -use std::{i128, string}; -use tracing::{debug, error, info, instrument, trace, warn, Instrument}; -use tracing::{span, Level}; - -use crate::error::{IntoMizeResult, MizeError, MizeResult}; -use crate::id::MizeId; -use crate::instance::connection::value_raw_con_by_id; -use crate::instance::store::Store; -use crate::instance::{connection, Mize}; -use crate::mize_err; -use crate::proto::MizeMessage; -use ciborium::Value as CborValue; - -// a item always has to do with a Instance, which takes care of how it is updated -#[derive(Debug, Clone)] -pub struct Item<'a> { - id: MizeId, - pub instance: &'a Mize, -} - -// without an Instance it is not an item, but only the "data of an item" -// and this type for now is just an alias to CborValue -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ItemData(pub CborValue); - -impl Item<'_> { - pub fn id(&self) -> MizeId { - self.id.clone() - } - - pub fn new(id: MizeId, instance: &Mize) -> Item { - Item { id, instance } - } - - pub fn value_raw(&self) -> MizeResult> { - let data = self.as_data_full()?; - let raw = get_raw_from_cbor(data.cbor(), vec![])?; - return Ok(raw.to_owned()); - } - - pub fn value_string(&self) -> MizeResult { - let raw = self.value_raw()?; - String::from_utf8(raw.clone()) - .mres_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 { - let id = self.id(); - - // the instance we are - if id.store_part() == "self" { - debug!("getting item '{}' from self", self.id()); - - match id.nth_part(1)? { - "con_by_id" => { - return value_raw_con_by_id(&mut self.clone()); - } - "namespace" => { - let namespace_inner = self.instance.namespace.lock()?; - return Ok(ItemData::from_string(namespace_inner.as_real_string())); - } - "self_namespace" => { - let namespace_inner = self.instance.self_namespace.lock()?; - return Ok(ItemData::from_string(namespace_inner.as_real_string())); - } - "config" => { - let rest_path = id - .path - .into_iter() - .skip(2) - .map(|v| v.to_owned()) - .collect::>() - .join("."); - let mut mize = self.instance.to_owned(); - return Ok(mize.get_config(rest_path.as_str())?); - } - _ => {} - } - return Err(mize_err!( - "a /self path, but the next element in the path '{:?}' is not valid", - id.nth_part(1) - )); - } - - let self_namespace_inner = self.instance.self_namespace.lock()?; - - if self.id().namespace() == self_namespace_inner.to_owned() { - debug!("getting item '{}' from store", self.id()); - - if id.store_part() == "inst" { - match id.nth_part(1)? { - "con_by_id" => { - return value_raw_con_by_id(&mut self.clone()); - } - "namespace" => { - let namespace_inner = self.instance.namespace.lock()?; - return Ok(ItemData::from_string(namespace_inner.as_real_string())); - } - "self_namespace" => { - let namespace_inner = self.instance.self_namespace.lock()?; - return Ok(ItemData::from_string(namespace_inner.as_real_string())); - } - _ => {} - } - } - - let store_inner = self.instance.store.lock()?; - return store_inner.get_value_data_full(self.id()); - } else { - let mut connection = self.instance.get_connection_by_ns(self.id().namespace())?; - - debug!( - "getting item '{}' from connection '{}' from store", - self.id(), - connection.id - ); - - let msg = MizeMessage::new_get(self.id(), connection.id); - connection.send(msg); - let data = self.instance.give_msg_wait(self.id())?; - return Ok(data); - } - } - - #[instrument(name = "fn.ItemData::merge")] - pub fn merge + Debug>(&mut self, mut value: V) -> MizeResult<()> { - let mut data = self.as_data_full()?; - //let mut data = data_full.get_path(id_path_without_store_part)?; - trace!("item::merge data: {:?}", data); - trace!("item::merge id: {:?}", self.id()); - - let new_data = value.into(); - - data.merge(new_data); - trace!("item::merge new_data: {:?}", data); - - // handle the case of /self/* - if self.id().store_part() == "self" { - let rest_path = self - .id() - .path - .into_iter() - .skip(1) - .map(|v| v.to_owned()) - .collect::>() - .join("/"); - let id_for_store = self - .instance - .new_id("0".to_owned() + "/" + rest_path.as_str())?; - - let store_inner = self.instance.store.lock()?; - store_inner.set(id_for_store, data)?; - } else if self.instance.we_are_namespace()? { - let store_inner = self.instance.store.lock()?; - store_inner.set(self.id(), data)?; - } else { - let namespace = self.id().namespace(); - let mut connection = self.instance.get_connection_by_ns(namespace)?; - let msg = MizeMessage::new_update_request(self.id(), data, connection.id); - connection.send(msg)?; - } - - Ok(()) - } -} - -impl<'a> Display for Item<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - //let item_data = self.as_data_full().map_err(|_| std::fmt::Error)?; - write!(f, "Item with id: {}", self.id()); - return Ok(()); - } -} - -impl ItemData { - pub fn new() -> ItemData { - ItemData(CborValue::Null) - } - - pub fn empty() -> ItemData { - ItemData(CborValue::Null) - } - - pub fn from_toml(toml_string: &str) -> MizeResult { - let toml_deserializer = toml::Deserializer::new(&toml_string); - - let value = CborValue::deserialize(toml_deserializer).mres_msg(format!( - "Could not deserialize the toml string: {}", - &toml_string - ))?; - - return Ok(value.into_item_data()); - } - - pub fn to_toml(&self) -> MizeResult { - let mut out_string = String::new(); - let toml_serializer = toml::Serializer::new(&mut out_string); - CborValue::serialize(&self.cbor(), toml_serializer)?; - Ok(out_string) - } - - pub fn value_string(self) -> MizeResult { - match self.cbor() { - CborValue::Text(string) => Ok(string.to_owned()), - _ => Err(mize_err!("this ItemData has no string value")), - } - } - - pub fn value_bool(self) -> MizeResult { - match self.cbor() { - CborValue::Bool(val) => Ok(*val), - _ => Err(mize_err!("this ItemData has no string value")), - } - } - pub fn as_bool(self) -> Option { - match self.cbor() { - CborValue::Bool(val) => Some(*val), - _ => None, - } - } - - pub fn from_string>(into_string: S) -> ItemData { - let string = into_string.into(); - let data = CborValue::Text(string); - return ItemData(data); - } - - pub fn to_json(self) -> MizeResult { - let mut result: Vec = Vec::new(); - - self.0 - .serialize(&mut serde_json::Serializer::new(&mut result))?; - - Ok(String::from_utf8(result)?) - } - - pub fn from_json(json_str: String) -> MizeResult { - let mut json_deserializer = serde_json::Deserializer::from_str(json_str.as_str()); - - let value = CborValue::deserialize(&mut json_deserializer).mres_msg(format!( - "could not deserialize the json string: {}", - json_str - ))?; - - return Ok(value.into_item_data()); - } - - pub fn merge(&mut self, other: ItemData) { - item_data_merge(&mut self.0, &other.0); - } - - pub fn cbor(&self) -> &CborValue { - &self.0 - } - - pub fn from_cbor(cbor: CborValue) -> ItemData { - ItemData(cbor) - } - - pub fn sort_keys(&mut self) -> MizeResult<()> { - item_data_sort_keys(&mut self.0) - } - - pub fn null() -> CborValue { - CborValue::Null - } - - pub fn parse>(value: T) -> ItemData { - let value_str = value.into(); - if value_str == "false" { - return CborValue::Bool(false).into_item_data(); - } - if value_str == "false" { - return CborValue::Bool(true).into_item_data(); - } - if let Ok(int) = value_str.parse::() { - return int.into_item_data(); - } - return CborValue::Text(value_str).into_item_data(); - } - - pub fn set_path(&mut self, path: P, value: D) -> MizeResult<()> { - //trace!("[ {} ] ItemData::set_path()", "CALL".yellow()); - let path = path.into_path(); - let value = value.into_item_data(); - - item_data_set_path(&mut self.0, path, &value.0) - } - - pub fn get_path(&self, path: P) -> MizeResult { - let path = path.into_path(); - Ok(item_data_get_path(&self.0, path)? - .to_owned() - .into_item_data()) - } - - pub fn get_paths_recursive(&mut self) -> MizeResult> { - let mut paths = Vec::new(); - let mut path_accu = Vec::new(); - get_paths(&mut self.0, &mut paths, &mut path_accu, true)?; - Ok(paths) - } - - pub fn get_paths(&mut self) -> MizeResult> { - let mut paths = Vec::new(); - let mut path_accu = Vec::new(); - get_paths(&mut self.0, &mut paths, &mut path_accu, false)?; - Ok(paths) - } -} - -fn get_paths( - val: &mut CborValue, - paths: &mut Vec, - path_accu: &mut Vec, - recurse: bool, -) -> MizeResult<()> { - let map = val - .as_map_mut() - .ok_or(mize_err!("ItemData is not map... when calling get_paths"))?; - for (key, val) in map { - let text = key - .as_text() - .ok_or(mize_err!("ItemData::get_paths but key is not of type text"))? - .to_owned(); - if recurse && val.is_map() { - let mut path_accu = path_accu.clone(); - path_accu.push(text); - get_paths(val, paths, &mut path_accu, recurse)?; - } else { - let path = path_accu.join("/") + "/" + text.as_str(); - paths.push(path); - } - } - Ok(()) -} - -impl Default for ItemData { - fn default() -> Self { - ItemData::new() - } -} - -pub fn data_from_string(data_string: String) -> MizeResult { - let mut data = ItemData::new(); - - // in case it's just a string - if !data_string.contains("=") { - let cbor = CborValue::Text(data_string); - return Ok(ItemData::from_cbor(cbor)); - } - - for option in data_string.split(":") { - //trace!("data_from_string: option: {}", option); - if option == "".to_owned() { - continue; - } - - let path = option - .split("=") - .nth(0) - .ok_or(MizeError::new().msg(format!( - "Failed to parse Option: option '{}' has an empty path (thing before =)", - option - )))?; - - //trace!("data_from_string: path: {}", path); - - let value = option - .split("=") - .nth(1) - .ok_or(MizeError::new().msg(format!( - "Failed to parse Option: option '{}' has an empty value (thing after =)", - option - )))?; - //trace!("data_from_string: value: {}", value); - - let mut path_vec = Vec::new(); - path_vec.extend(path.split(".")); - - //trace!("data_from_string: path_vec: {:?}", path_vec); - - data.set_path(path_vec, ItemData::parse(value))?; - } - - trace!("data_from_string: data: {}", data); - return Ok(data); -} - -pub fn item_data_get_path(data: &CborValue, path: Vec) -> MizeResult<&CborValue> { - let mut path_iter = path.clone().into_iter(); - //println!("data: {:?}", data); - //println!("path: {:?}", path); - - let path_el = match path_iter.nth(0) { - Some(val) => val, - None => return Ok(data), // our base case - }; - - let mut sub_data = &CborValue::Null; - match data { - CborValue::Map(ref map) => { - for (key, val) in map { - //println!("key: {:?}", key); - //println!("path_el: {}", path_el); - if let CborValue::Text(key_str) = key { - if key_str == &path_el { - sub_data = val; - } - } - } - } - val => { - return Err(MizeError::new() - .msg(format!( - "Failed to get path '{:?}' from ItemData, the data at '{}' is not a map", - path, path_el - )) - .msg(format!("{:?} is: {:?}", path_el, val))); - } - }; - item_data_get_path(sub_data, path_iter.collect()) -} - -pub fn item_data_sort_keys(data: &mut CborValue) -> MizeResult<()> { - // for a list, sort each item of the list - if data.is_array() { - for el in data.as_array_mut().unwrap().iter_mut() { - item_data_sort_keys(el)? - } - } - - // sort the keys of a map - if data.is_map() { - let map: &mut Vec<(CborValue, CborValue)> = data.as_map_mut().unwrap(); - //map.sort_by_key(|el| el.0); - map.sort_by(|a, b| { - match a.0.partial_cmp(&b.0) { - Some(val) => val, - None => { - // just say the two values are equal, if they can't be ordered - std::cmp::Ordering::Equal - } - } - }); - - // also sort every sub value - for (key, val) in map { - item_data_sort_keys(val)? - } - } - - Ok(()) -} - -pub fn item_data_set_path( - data: &mut CborValue, - path: Vec, - data_to_set: &CborValue, -) -> MizeResult<()> { - //trace!("[ {} ] item_data_set_path()", "CALL".yellow()); - //trace!("[ {} ] data: {}", "ARG".yellow(), data.clone().into_item_data()); - //trace!("[ {} ] path: {:?}", "ARG".yellow(), path); - //trace!("[ {} ] data_to_set: {}", "ARG".yellow(), data_to_set.clone().into_item_data()); - - test_println!("item_data_set_path ###########################"); - test_println!("data: {}", ItemData::from_cbor(data.clone())); - test_println!("path: {:?}", path); - test_println!("data_to_set: {}", ItemData::from_cbor(data_to_set.clone())); - test_println!("###########################"); - - let mut path_iter = path.clone().into_iter(); - let path_el = match path_iter.nth(0) { - Some(val) => val, - None => { - //trace!("item_data_set_path: base_case"); - // our base case - *data = data_to_set.to_owned(); - return Ok(()); - } - }; - match data { - CborValue::Map(ref mut map) => { - for (key, val) in &mut *map { - if let CborValue::Text(key_str) = key { - if key_str == &path_el { - //trace!("item_data_set_path: setting key {key_str} in map with recursive call"); - return item_data_set_path(val, path_iter.collect(), data_to_set); - } - } - } - - // if we get here, that means, the key (which is the variable path_el) does not exist - // in the map - // so add it... but also with a recursive call which is needed, in case path_iter - // longer than 1 - //trace!("item_data_set_path: adding key {path_el} to map"); - let mut inner_value = CborValue::Null; - item_data_set_path(&mut inner_value, path_iter.collect(), data_to_set); - map.push((CborValue::Text(path_el.clone()), inner_value)); - return Ok(()); - } - CborValue::Null => { - //trace!("item_data_set_path: CborValue::Null case"); - let mut inner_value = CborValue::Null; - item_data_set_path(&mut inner_value, path_iter.collect(), data_to_set); - - let map_vec = vec![(CborValue::Text(path_el), inner_value)]; - *data = CborValue::Map(map_vec); - - return Ok(()); - } - val => { - return Err(MizeError::new() - .msg(format!( - "Failed to get path '{:?}' from ItemData, the data at '{}' is not a map", - path, path_el - )) - .msg(format!("{:?} is: {:?}", path_el, val))); - } - }; - - return Err(MizeError::new().msg("unreachable")); -} - -pub fn item_data_merge(merge_into: &mut CborValue, other: &CborValue) { - // needs to be recursive - - match (merge_into, other) { - // if both are maps - // merge the keys/vals in the maps and call recursively on them - (CborValue::Map(ref mut merge_into_map), CborValue::Map(ref other_map)) => { - // go through other_map and merge those keys/values to merge_into - for (other_key, other_val) in other_map { - // so find that same vale in merge_into, if exists recursively merge, else just add to - // vec - let mut found_value = CborValue::Null; - let mut value_found = false; - let mut new_value_for_merge_into: Vec<(CborValue, CborValue)> = Vec::new(); // here we collect the - // new contents of the - // map, to assign later - // to merge_into_map - - for (merge_into_key, merge_into_val) in merge_into_map.clone() { - if merge_into_key == *other_key { - value_found = true; - found_value = merge_into_val.to_owned(); - // if we found it, also don't add it to new_value_for_merge_into - } else { - //if not found push to new_value_for_merge_into - new_value_for_merge_into - .push((merge_into_key.to_owned(), merge_into_val.to_owned())); - } - } - - if value_found { - // we found it so merge and asign - item_data_merge(&mut found_value, other_val); - - // to asign push to new_value_for_merge_into, because the old was removed already - new_value_for_merge_into.push((other_key.to_owned(), found_value)); - } else { - // if not found, just add the other_key/val to new_value_for_merge_into - new_value_for_merge_into.push((other_key.to_owned(), other_val.to_owned())); - } - - // finally, we need to asign the new_value_for_merge_into into merge_into - *merge_into_map = new_value_for_merge_into; - } - } - - // if other is Null, don't asign - // this is gonna have repercussions.... because it's not clean behaviour - (merge_into, CborValue::Null) => {} - - // in any other case we just want to set merge_into to other - // also this is the base case - (merge_into, other) => { - *merge_into = other.to_owned(); - } - } -} - -#[instrument(name = "fn.get_raw_from_cbor")] -pub fn get_raw_from_cbor<'a>(value: &'a CborValue, path: Vec<&String>) -> MizeResult<&'a [u8]> { - trace!("[ {} ] value: {:?}", "ARG".yellow(), value); - trace!("[ {} ] path: {:?}", "ARG".yellow(), path); - - let mut path_iter = path.clone().into_iter(); - let path_el = - match path_iter.nth(0) { - Some(val) => val, - None => { - // our base case - let ret_val = - match value { - CborValue::Bytes(vec) => { - trace!("[ {} ] ret value: {:?}", "RET".yellow(), &vec[..]); - return Ok(&vec[..]); - } - CborValue::Text(string) => { - trace!("[ {} ] ret value: {:?}", "RET".yellow(), string.as_bytes()); - return Ok(string.as_bytes()); - } - other => { - return Err(mize_err!( - "path '{}' is empty and the value: '{:?}' is neither Bytes nor Text", - path.iter().map(|p| p.as_str()).collect::>().join("."), - other - )); - } - }; - } - }; - - match value { - CborValue::Bytes(vec) => { - trace!("[ {} ] ret value: {:?}", "RET".yellow(), &vec[..]); - return Ok(&vec[..]); - } - CborValue::Text(string) => { - trace!("[ {} ] ret value: {:?}", "RET".yellow(), string.as_bytes()); - return Ok(string.as_bytes()); - } - CborValue::Map(map) => { - let mut inner_val: &CborValue = &CborValue::Null; - let mut inner_val_found = false; - - // find the inner_val at path - for (key, val) in map.into_iter() { - if let CborValue::Text(key_text) = key { - if key_text == path_el { - inner_val = val; - inner_val_found = true; - } - } - } - - // if there is no value at that path - if inner_val_found == false { - return Err(MizeError::new() - // jesus christ, this is a pfusch... - .msg(format!( - "get_raw_from_cbor: Path '{}' not Found", - path.clone() - .into_iter() - .map(|v| v.to_owned()) - .collect::>() - .join("/") - ))); - } - - //path_iter.next(); - let inner_path = path_iter.collect(); - let ret_value = get_raw_from_cbor(inner_val, inner_path); - trace!("[ {} ] ret value: {:?}", "RET".yellow(), ret_value); - return ret_value; - } - _ => Err(MizeError::new().msg(format!( - "get_raw_from_cbor: value is not a map, text or bytes ... value: {:?}", - value - ))), - } -} - -trait IntoPath { - fn into_path(self) -> Vec; -} - -pub trait IntoItemData { - fn into_item_data(self) -> ItemData; -} - -impl IntoPath for &str { - fn into_path(self) -> Vec { - if !self.contains('/') { - return self.split(".").map(|v| v.to_owned()).collect(); - } - self.to_owned().split("/").map(|v| v.to_owned()).collect() - } -} - -impl IntoPath for &[&str] { - fn into_path(self) -> Vec { - self.into_iter().map(|v| (*v).to_owned()).collect() - } -} -impl IntoPath for Vec { - fn into_path(self) -> Vec { - self - } -} -impl IntoPath for Vec<&str> { - fn into_path(self) -> Vec { - self.into_iter().map(|v| v.to_owned()).collect() - } -} - -impl IntoItemData for &str { - fn into_item_data(self) -> ItemData { - ItemData(self.into()) - } -} -impl IntoItemData for String { - fn into_item_data(self) -> ItemData { - ItemData(self.into()) - } -} -impl IntoItemData for &String { - fn into_item_data(self) -> ItemData { - ItemData(self.to_owned().into()) - } -} -impl IntoItemData for Vec { - fn into_item_data(self) -> ItemData { - let array = self - .into_iter() - .map(|v| v.into_item_data().cbor().to_owned()) - .collect::>(); - ItemData(CborValue::Array(array)) - } -} -impl IntoItemData for CborValue { - fn into_item_data(self) -> ItemData { - ItemData(self) - } -} -impl IntoItemData for ItemData { - fn into_item_data(self) -> ItemData { - self - } -} -impl IntoItemData for i128 { - fn into_item_data(self) -> ItemData { - ItemData(self.into()) - } -} -impl IntoItemData for bool { - fn into_item_data(self) -> ItemData { - ItemData(self.into()) - } -} - -impl fmt::Display for ItemData { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ItemData: "); - let display_writer = DisplayWriter(f); - self.0 - .serialize(&mut serde_json::Serializer::pretty(display_writer)) - .map_err(|serde_err| std::fmt::Error) - } -} - -// thanks to: https://stackoverflow.com/a/61768916 -struct DisplayWriter<'a, 'b>(&'a mut fmt::Formatter<'b>); - -impl<'a, 'b> io::Write for DisplayWriter<'a, 'b> { - fn write(&mut self, bytes: &[u8]) -> std::result::Result { - self.0 - .write_str(&String::from_utf8_lossy(bytes)) - .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?; - - Ok(bytes.len()) - } - fn flush(&mut self) -> std::result::Result<(), std::io::Error> { - todo!() - } -} - -impl PartialEq for ItemData { - fn eq(&self, other: &Self) -> bool { - let mut buf: Vec = Vec::new(); - let mut buf_other: Vec = Vec::new(); - - ciborium::into_writer(&self.0, &mut buf); - ciborium::into_writer(&other.0, &mut buf_other); - - buf == buf_other - } -} -impl Eq for ItemData {} - -pub fn set_config_from_data(mize: &mut Mize, mut data: ItemData) -> MizeResult<()> { - let mut config_opts = mize.config_opts.lock().unwrap(); - for path in data.get_paths_recursive()? { - let mut conf_name = path.replace("/", "."); - if conf_name.starts_with(".") { - conf_name.remove(0); - } - let val = data.get_path(path.split("/").filter(|s| s != &"").collect::>())?; - match config_opts.get_mut(&conf_name) { - Some(opt) => { - opt.val = Some(val); - } - None => { - config_opts.insert( - conf_name.clone(), - ConfigOpt { - name: conf_name, - val: Some(val), - thunk: None, - }, - ); - } - }; - } - Ok(()) -} diff --git a/src/core/lib.rs b/src/core/lib.rs deleted file mode 100644 index 9b77184..0000000 --- a/src/core/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ - -#![ allow( warnings ) ] - diff --git a/src/core/macros.rs b/src/core/macros.rs deleted file mode 100644 index f578409..0000000 --- a/src/core/macros.rs +++ /dev/null @@ -1,31 +0,0 @@ -// console_log macro -// that can be copied into other files for debugging purposes -#[cfg(feature = "wasm-target")] -use wasm_bindgen::prelude::*; - -#[cfg(feature = "wasm-target")] -#[wasm_bindgen] -extern "C" { - #[wasm_bindgen(js_namespace = console)] - fn log(s: &str); -} - -#[cfg(feature = "wasm-target")] -macro_rules! console_log { - // Note that this is using the `log` function imported above during - // `bare_bones` - ($($t:tt)*) => (unsafe { log(&format_args!($($t)*).to_string())}) -} - -#[macro_export] -macro_rules! add_parts { - ($mize:expr, $($part:expr),+) => { - $( - let part = $part.create($mize.clone()); - $mize.add_part( - part - ); - )+ - mize.init_parts(); - }; -} diff --git a/src/core/memstore.rs b/src/core/memstore.rs deleted file mode 100644 index 9cdc7e7..0000000 --- a/src/core/memstore.rs +++ /dev/null @@ -1,152 +0,0 @@ -use ciborium::Value as CborValue; -use colored::Colorize; -use std::collections::binary_heap::Iter; -use std::collections::HashMap; -use std::iter::Map; -use std::sync::{Arc, Mutex}; -use tracing::{instrument, trace}; - -use crate::error::{IntoMizeResult, MizeError, MizeResult}; -use crate::id::MizeId; -use crate::instance::store::{IdIter, Store}; -use crate::instance::Mize; -use crate::item::get_raw_from_cbor; -use crate::item::{Item, ItemData}; -use crate::mize_err; - -#[derive(Clone, Debug)] -pub struct MemStore { - inner: Arc>, -} - -pub type MemStoreId = u64; - -#[derive(Debug)] -struct MemStoreInner { - map: HashMap, - next_id: u64, -} - -impl Store for MemStore { - fn set(&self, id: MizeId, data: ItemData) -> MizeResult<()> { - let mut inner = self.inner.lock()?; - - if let Some(old_data) = inner.map.get(&id_to_u64(id.clone())?) { - //if there is already data there, set at the correct path - let mut old_data = old_data.to_owned(); - let path = id.after_store_part(); - old_data.set_path(path, data)?; - inner.map.insert(id_to_u64(id)?, old_data); - } else { - // if no data exists for that store_part, just insert - inner.map.insert(id_to_u64(id)?, data); - } - - return Ok(()); - } - fn get_links(&self, item: Item) -> MizeResult> { - let inner = self.inner.lock()?; - - Ok(Vec::new()) - } - fn get_backlinks(&self, item: Item) -> MizeResult> { - let inner = self.inner.lock()?; - - Ok(Vec::new()) - } - fn new_id(&self) -> MizeResult { - let mut inner = self.inner.lock()?; - - let id_string = format!("{}", inner.next_id); - inner.next_id += 1; - return Ok(id_string); - } - - #[instrument(name="fn.MemStore::get_value_raw" skip(self))] - fn get_value_raw(&self, id: MizeId) -> MizeResult> { - trace!("[ {} ] id: {:?}", "ARG".yellow(), id); - let inner = self.inner.lock()?; - - let cbor_val = inner - .map - .get(&id_to_u64(id.clone())?) - .ok_or(MizeError::new().msg(format!( - "Item with store_part: {}, id: {} does not exist in MemStore", - id_to_u64(id.clone())?, - id - )))?; - - 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.0, id_without_first)?.to_owned()) - } - - fn get_value_data_full(&self, id: MizeId) -> MizeResult { - let inner = self.inner.lock()?; - - let data = match inner.map.get(&id_to_u64(id.clone())?) { - Some(val) => val.to_owned(), - None => ItemData::new(), - }; - - let new_path = id.after_store_part(); - let ret_data = data.get_path(new_path)?; - - return Ok(ret_data); - } - fn id_iter(&self) -> MizeResult { - IdIter::new(Box::new(self.to_owned())) - } - - fn next_id(&self, prev_id_str: &str) -> MizeResult> { - let inner = self.inner.lock()?; - - let mut id = str_to_u64(prev_id_str)?; - - loop { - id += 1; - - if id > inner.next_id { - return Ok(None); - } - - if inner.map.contains_key(&id) { - println!("returning: {}", id); - return Ok(Some(format!("{}", id))); - } else { - // try id +1 - continue; - } - } - } - - fn first_id(&self) -> MizeResult { - Ok("0".to_owned()) - } -} - -impl MemStore { - pub fn new() -> MemStore { - let inner = MemStoreInner { - map: HashMap::new(), - next_id: 0, - }; - return MemStore { - inner: Arc::new(Mutex::new(inner)), - }; - } -} - -fn id_to_u64(id: MizeId) -> MizeResult { - str_to_u64(id.store_part()) -} - -fn str_to_u64(id_str: &str) -> MizeResult { - id_str.parse().mres_msg(format!( - "Could not parse the store_part of mizeid {} into a u64 for the MemStore", - id_str - )) -} diff --git a/src/core/proto/mod.rs b/src/core/proto/mod.rs deleted file mode 100644 index 35d8204..0000000 --- a/src/core/proto/mod.rs +++ /dev/null @@ -1,434 +0,0 @@ -use core::fmt; -use serde::Serialize; -use std::io; - -use ciborium::{value::Integer, Value as CborValue}; - -use crate::{ - error::{IntoMizeResult, MizeError, MizeResult}, - id::MizeId, - instance::{self, connection::Connection, Mize}, - item::{IntoItemData, ItemData}, -}; - -#[derive(Clone)] -pub struct MizeMessage { - value: CborValue, - pub conn_id: u64, -} - -impl MizeMessage { - pub fn bytes(&self) -> Vec { - let mut writer = Vec::new(); - ciborium::into_writer(&self.value, &mut writer).unwrap(); - writer - } - pub fn into_writer(&self, writer: &mut impl io::Write) -> MizeResult<()> { - Ok(ciborium::into_writer(&self.value, writer)?) - } -} - -// msg items -static MSG_CMD: u16 = 1; -static MSG_ID: u16 = 2; -static MSG_DATA: u16 = 3; - -// cmds -static CMD_GET: u16 = 1; -static CMD_UPDATE: u16 = 2; -static CMD_GIVE: u16 = 3; -static CMD_CREATE: u16 = 4; -static CMD_CREATE_REPLY: u16 = 5; -static CMD_UPDATE_REQUEST: u16 = 6; -static CMD_GET_SUB: u16 = 7; -static CMD_SUB: u16 = 8; - -#[derive(Debug)] -pub enum MessageCmd { - Get, - Update, - Give, - Create, - CreateReply, - UpdateRequest, - GetSub, - Sub, - Custom(ItemData), -} - -impl MizeMessage { - pub fn new(value: CborValue, conn_id: u64) -> MizeMessage { - MizeMessage { value, conn_id } - } - - pub fn new_custom( - custom_cmd: T, - value: U, - conn_id: u64, - ) -> MizeMessage { - let value = value.into_item_data(); - let custom_cmd = custom_cmd.into_item_data(); - - let cmd = (CborValue::Integer(MSG_CMD.into()), custom_cmd.0); - let data = (CborValue::Integer(MSG_DATA.into()), value.cbor().to_owned()); - let msg_value = CborValue::Map(vec![cmd, data]); - - MizeMessage { - value: msg_value, - conn_id, - } - } - - pub fn new_get(id: MizeId, conn_id: u64) -> MizeMessage { - let id_path = id - .path() - .into_iter() - .map(|string| CborValue::Text(string.to_owned())) - .collect(); - - let cmd = ( - CborValue::Integer(MSG_CMD.into()), - CborValue::Integer(CMD_GET.into()), - ); - let id = (CborValue::Integer(MSG_ID.into()), CborValue::Array(id_path)); - let value = CborValue::Map(vec![cmd, id]); - - MizeMessage::new(value, conn_id) - } - - pub fn new_get_sub(id: MizeId, conn_id: u64) -> MizeMessage { - let id_path = id - .path() - .into_iter() - .map(|string| CborValue::Text(string.to_owned())) - .collect(); - - let cmd = ( - CborValue::Integer(MSG_CMD.into()), - CborValue::Integer(CMD_GET_SUB.into()), - ); - let id = (CborValue::Integer(MSG_ID.into()), CborValue::Array(id_path)); - let value = CborValue::Map(vec![cmd, id]); - - MizeMessage::new(value, conn_id) - } - - pub fn new_sub(id: MizeId, conn_id: u64) -> MizeMessage { - let id_path = id - .path() - .into_iter() - .map(|string| CborValue::Text(string.to_owned())) - .collect(); - - let cmd = ( - CborValue::Integer(MSG_CMD.into()), - CborValue::Integer(CMD_SUB.into()), - ); - let id = (CborValue::Integer(MSG_ID.into()), CborValue::Array(id_path)); - let value = CborValue::Map(vec![cmd, id]); - - MizeMessage::new(value, conn_id) - } - - pub fn new_create(conn_id: u64) -> MizeMessage { - let cmd = ( - CborValue::Integer(MSG_CMD.into()), - CborValue::Integer(CMD_CREATE.into()), - ); - let value = CborValue::Map(vec![cmd]); - - MizeMessage::new(value, conn_id) - } - - pub fn new_create_reply(id: MizeId, conn_id: u64) -> MizeMessage { - let id_path = id - .path() - .into_iter() - .map(|string| CborValue::Text(string.to_owned())) - .collect(); - - let cmd = ( - CborValue::Integer(MSG_CMD.into()), - CborValue::Integer(CMD_CREATE_REPLY.into()), - ); - let id = (CborValue::Integer(MSG_ID.into()), CborValue::Array(id_path)); - let value = CborValue::Map(vec![cmd, id]); - - MizeMessage::new(value, conn_id) - } - - pub fn new_give(id: MizeId, data: ItemData, conn_id: u64) -> MizeMessage { - let id_path = id - .path() - .into_iter() - .map(|string| CborValue::Text(string.to_owned())) - .collect(); - - let cmd = ( - CborValue::Integer(MSG_CMD.into()), - CborValue::Integer(CMD_GIVE.into()), - ); - let id = (CborValue::Integer(MSG_ID.into()), CborValue::Array(id_path)); - let data = (CborValue::Integer(MSG_DATA.into()), data.cbor().to_owned()); - let value = CborValue::Map(vec![cmd, id, data]); - - MizeMessage::new(value, conn_id) - } - - pub fn new_update_request(id: MizeId, data: ItemData, conn_id: u64) -> MizeMessage { - let id_path = id - .path() - .into_iter() - .map(|string| CborValue::Text(string.to_owned())) - .collect(); - - let cmd = ( - CborValue::Integer(MSG_CMD.into()), - CborValue::Integer(CMD_UPDATE_REQUEST.into()), - ); - let id = (CborValue::Integer(MSG_ID.into()), CborValue::Array(id_path)); - let data = (CborValue::Integer(MSG_DATA.into()), data.cbor().to_owned()); - let value = CborValue::Map(vec![cmd, id, data]); - - MizeMessage::new(value, conn_id) - } - - pub fn new_update(id: MizeId, data: ItemData, conn_id: u64) -> MizeMessage { - let id_path = id - .path() - .into_iter() - .map(|string| CborValue::Text(string.to_owned())) - .collect(); - - let cmd = ( - CborValue::Integer(MSG_CMD.into()), - CborValue::Integer(CMD_UPDATE.into()), - ); - let id = (CborValue::Integer(MSG_ID.into()), CborValue::Array(id_path)); - let data = (CborValue::Integer(MSG_DATA.into()), data.cbor().to_owned()); - let value = CborValue::Map(vec![cmd, id, data]); - - MizeMessage::new(value, conn_id) - } - - pub fn value(self) -> CborValue { - self.value - } - - pub fn cmd(&self) -> MizeResult { - // return err, if msg is not a map - let msg_as_map = match &self.value { - CborValue::Map(val) => val, - _ => { - return Err(MizeError::new().msg("Message was not a map")); - } - }; - - //check if in this map there is a cmd, otherwise return err - let val_of_c = { - let mut tmp_val = 0; - for (key, val) in msg_as_map { - if let CborValue::Integer(key_int) = key { - // number one indicates the cmd field - let one: Integer = 1.into(); - if key_int == &one { - if let CborValue::Integer(val_int) = val { - tmp_val = val_int.to_owned().into(); - } else { - return Ok(MessageCmd::Custom(ItemData(val.to_owned()))); - } - } - } - } - if tmp_val == 0 { - return Err(MizeError::new().msg("error getting the cmd value form a msg")); - } - tmp_val - }; - - // match on value of cmd - let cmd = match val_of_c { - 1 => MessageCmd::Get, - 2 => MessageCmd::Update, - 3 => MessageCmd::Give, - 4 => MessageCmd::Create, - 5 => MessageCmd::CreateReply, - 6 => MessageCmd::UpdateRequest, - 7 => MessageCmd::GetSub, - 8 => MessageCmd::Sub, - _ => { - return Err(MizeError::new().msg("error cmd of msg was not a valid command")); - } - }; - - return Ok(cmd); - } - - pub fn id_str(&mut self) -> MizeResult> { - // return err, if msg is not a map - let msg_as_map = match &self.value { - CborValue::Map(val) => val, - _ => { - return Err(MizeError::new().msg("Message was not a map")); - } - }; - - let vec_value = { - let mut data = &CborValue::Null; - for (key, val) in msg_as_map { - if let CborValue::Integer(key_int) = key { - // number 2 indicates the id field - let two: Integer = 2.into(); - if key_int == &two { - data = val; - } - } - } - if data == &CborValue::Null { - return Err(MizeError::new().msg("error getting the data value form a msg")); - } - match data { - CborValue::Array(inner) => inner, - _ => { - return Err(MizeError::new().msg("Id is not a vector")); - } - } - }; - - let mut vec_string: Vec = Vec::new(); - for val in vec_value { - match val { - CborValue::Text(text) => vec_string.push(text.to_owned()), - _ => { - return Err(MizeError::new() - .msg("one in the vec of the id in a msg is not of type Text")); - } - } - } - - Ok(vec_string) - } - - pub fn id(&mut self, instance: &Mize) -> MizeResult { - let id_str = self.id_str()?; - return instance.new_id(id_str); - } - - pub fn data(&mut self) -> MizeResult { - // return err, if msg is not a map - let msg_as_map = match &self.value { - CborValue::Map(val) => val, - _ => { - return Err(MizeError::new().msg("Message was not a map")); - } - }; - - let data = { - let mut tmp_val = &CborValue::Null; - let mut found = false; - for (key, val) in msg_as_map { - if let CborValue::Integer(key_int) = key { - // number three indicates the data field - let three: Integer = 3.into(); - if key_int == &three { - tmp_val = val; - found = true; - } - } - } - if !found { - return Err(MizeError::new().msg("error getting the data value form a msg")); - } - tmp_val - }; - - return Ok(data.to_owned().into_item_data()); - } -} - -// thanks to: https://stackoverflow.com/a/61768916 -struct DisplayWriter<'a, 'b>(&'a mut fmt::Formatter<'b>); - -impl<'a, 'b> io::Write for DisplayWriter<'a, 'b> { - fn write(&mut self, bytes: &[u8]) -> std::result::Result { - self.0 - .write_str(&String::from_utf8_lossy(bytes)) - .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?; - - Ok(bytes.len()) - } - fn flush(&mut self) -> std::result::Result<(), std::io::Error> { - todo!() - } -} - -impl fmt::Display for MizeMessage { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut err = false; - - match self.to_owned().cmd() { - Ok(cmd) => { - writeln!(f, "MizeMessage with cmd: {:?}", cmd); - } - Err(e) => { - writeln!(f, "MizeMessage with unparsable cmd"); - err = true; - } - } - - match self.to_owned().id_str() { - Ok(id) => { - let id_str = id.join("/"); - writeln!(f, "\tid: {:?}", id_str); - } - Err(e) => { - writeln!(f, "\t msg has no id"); - //err = true; - } - } - - match self.to_owned().data() { - Ok(data) => { - let value = data.cbor(); - write!(f, "\tdata: "); - let display_writer = DisplayWriter(f); - if let Err(e) = value - .serialize(&mut serde_json::Serializer::pretty(display_writer)) - .map_err(|serde_err| std::fmt::Error) - { - writeln!(f, "serialize err: {:?}", e); - err = true; - } - } - Err(e) => { - writeln!(f, "\t msg has no data"); - //err = true; - } - } - - if err { - write!(f, "Full msg: "); - let display_writer = DisplayWriter(f); - self.value - .serialize(&mut serde_json::Serializer::pretty(display_writer)) - .map_err(|serde_err| std::fmt::Error) - .mres_msg("serialize error") - .inspect_err(|e| { - e.clone().log(); - }); - } - - Ok(()) - } -} - -impl fmt::Debug for MizeMessage { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "\nMizeMessage: "); - let display_writer = DisplayWriter(f); - let value = self.to_owned().value(); - value - .serialize(&mut serde_json::Serializer::pretty(display_writer)) - .map_err(|serde_err| std::fmt::Error) - } -} diff --git a/src/core/types/mod.rs b/src/core/types/mod.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 32dde86..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,164 +0,0 @@ -#![allow(warnings)] - -static PROTO_VERSION: u8 = 1; - - -use std::cell::RefCell; -use std::fmt::format; - -thread_local! { - pub static MIZE_STDOUT: RefCell MizeResult<()>>>> = const { RefCell::new(None) }; -} - -#[macro_export] -macro_rules! out { - ($($arg:tt)*) => { - // format_args! handles string interpolation safely at compile time - if let Err(e) = $crate::write_to_mize_stdout(format_args!($($arg)*)) { - // Choose your error handling behavior here (panic, print to stderr, or ignore) - eprintln!("out! macro failed to write!!"); - } - }; -} - -pub fn out_macro_stdout() -> MizeResult<()> { - MIZE_STDOUT.with(|cell| { - *cell.borrow_mut() = Some(Box::new(|s| { - println!("{}", s); - Ok(()) - })); - }); - Ok(()) -} - -pub fn write_to_mize_stdout(args: std::fmt::Arguments) -> MizeResult<()> { - MIZE_STDOUT.with(|stdout| { - if let Some(fun) = stdout.borrow().as_ref() { - fun(format!("{}", args)); - Ok(()) - } else { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - "stdout not initialized", - )) - } - })?; - Ok(()) -} - -pub mod prelude { - pub use super::*; -} -pub use flume; - -#[macro_export] -macro_rules! test_println { - ($($arg:tt)*) => { - - #[cfg(test)] - print!("[[ {} ]] ", <&str as colored::Colorize>::blue("TEST")); - - #[cfg(test)] - print!($($arg)*); - - #[cfg(test)] - print!("\n"); - }; -} - -#[macro_export] -macro_rules! test_print { - ($($arg:tt)*) => { - - #[cfg(test)] - print!("[[ {} ]] ", <&str as colored::Colorize>::blue("TEST")); - - #[cfg(test)] - print!($($arg)*); - }; -} - -// the core part has the code that can run on any platform -mod core { - pub mod config; - pub mod error; - pub mod id; - pub mod instance; - pub mod item; - pub mod macros; - pub mod memstore; - pub mod proto; - pub mod types; -} - -pub use async_trait::async_trait; -pub use ciborium; -pub use core::error::MizeError; -pub use core::error::MizeResult; -pub use core::instance::Mize; -pub use core::instance::{ - DynMizePartGuard, MizePart, MizePartCreate, MizePartCreateGenerated, MizePartGenerated, - MizePartGuard, -}; -pub use core::*; -pub use mize_macros::*; -use std::path::PathBuf; - -// platform specific stuff -pub mod platform { - #[cfg(feature = "target-js")] - pub mod js; - - #[cfg(feature = "target-os")] - pub mod os; - - pub mod any { - //////////// instance_init - #[cfg(feature = "target-js")] - pub use super::js::wasm_instance_init as instance_init; - - #[cfg(feature = "target-os")] - pub use super::os::os_instance_init as instance_init; - - #[cfg(not(any(feature = "target-os", feature = "target-js")))] - pub use super::super::instance_init; - - //////////// load_part - #[cfg(feature = "target-os")] - pub use super::os::load_part; - - #[cfg(feature = "target-js")] - //pub use super::js::load_part; - pub use super::super::load_part; - - #[cfg(not(any(feature = "target-os", feature = "target-js")))] - pub use super::super::load_part; - - //////////// fetch_part - #[cfg(feature = "target-os")] - pub use super::os::fetch_part; - - #[cfg(feature = "target-js")] - pub use super::super::fetch_part; - - #[cfg(not(any(feature = "target-os", feature = "target-js")))] - pub use super::super::fetch_part; - } -} - -// platform specific functions -pub fn instance_init(instance: &mut core::instance::Mize) -> MizeResult<()> { - Ok(()) -} - -pub fn load_part( - instance: &mut core::instance::Mize, - name: &str, - path: Option, -) -> MizeResult<()> { - Ok(()) -} - -pub fn fetch_part(instance: &mut core::instance::Mize, name: &str) -> MizeResult { - Ok("oh noooooooooooooo, something went really really wrong, if this ends up in the executable....".to_owned()) -} diff --git a/src/platform/js/deno.json b/src/platform/js/deno.json deleted file mode 100644 index 5b320c2..0000000 --- a/src/platform/js/deno.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "tasks": { - "dev": "deno run --watch main.ts" - }, - "imports": { - "@std/assert": "jsr:@std/assert@1" - } -} diff --git a/src/platform/js/init.js b/src/platform/js/init.js deleted file mode 100644 index 1726094..0000000 --- a/src/platform/js/init.js +++ /dev/null @@ -1,30 +0,0 @@ - - -export async function init_mize(config) { - - if ("mize" in window) { - window.mize.set("self/config", config) - return window.mize - } - - let config_str = ""; - if (typeof config == "string") { - config_str = config - - } else if (typeof config == "object") { - config_str = JSON.stringify(config) - - } else { - throw "Error: config passed to init_mize() is not of type 'object' or 'string'" - } - - const { new_js_instance } = wasm_bindgen; - - await wasm_bindgen(config.module_dir.mize + "/mize_bg.wasm") - - window.mize = await new_js_instance(config_str) - window.mize.mod = {} - window.mize.init() - - return window.mize -} diff --git a/src/platform/js/mod.rs b/src/platform/js/mod.rs deleted file mode 100644 index 5bcddd6..0000000 --- a/src/platform/js/mod.rs +++ /dev/null @@ -1,328 +0,0 @@ -use crate::id::MizeId; -use crate::item::{Item, ItemData}; -use crate::platform::js::js_sys::Function; -use core::convert::From; -use core::option::Option; -use std::panic; -use std::ptr::NonNull; -use web_sys::js_sys::{self, eval, Promise}; -use web_sys::Worker; -use web_sys::{WorkerOptions, WorkerType}; - -use crate::core::item::IntoItemData; -use crate::error::MizeResult; -use crate::Mize; -use crate::MizeError; -use crate::mize_err; - -// console_log macro -// that can be copied into other files for debugging purposes -#[cfg(feature = "target-js")] -use wasm_bindgen::prelude::*; - -#[cfg(feature = "target-js")] -#[wasm_bindgen] -extern "C" { - #[wasm_bindgen(js_namespace = console)] - fn log(s: &str); -} - -#[cfg(feature = "target-js")] -macro_rules! console_log { - // Note that this is using the `log` function imported above during - // `bare_bones` - ($($t:tt)*) => (unsafe { log(&format_args!($($t)*).to_string())}) -} - -#[cfg(not(feature = "target-js"))] -macro_rules! console_log { - // Note that this is using the `log` function imported above during - // `bare_bones` - ($($t:tt)*) => {}; -} -//end of console_log macro - -#[global_allocator] -static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; - -pub fn wasm_instance_init(mize: &mut Mize) -> MizeResult<()> { - console_log!("Hello world from wasm_instance_init!!!!!!!!!!"); - - #[cfg(feature = "target-obsidian")] { - ////// populate values from $MIZE_CONFIG_FILES - if let Ok(config_file_paths) = obsidian_get_env_var("MIZE_CONFIG_FILES") { - for config_file_path in config_file_paths.split(":") { - println!("reading config file: {config_file_path}"); - let content = std::fs::read_to_string(config_file_path)?; - let mut data = ItemData::from_toml(content.as_str())?; - crate::core::item::set_config_from_data(mize, data)?; - } - } - - ////// load config from MIZE_CONFIG env var - match std::env::var("MIZE_CONFIG") { - Ok(config_string) => { - let data = data_from_string(config_string)?; - crate::core::item::set_config_from_data(mize, data)?; - } - Err(var_err) => match var_err { - VarError::NotPresent => { - debug!("env var MIZE_CONFIG NOT present") - } - VarError::NotUnicode(_) => { - warn!("env var MIZE_CONFIG is not Unicode, so not reading it") - } - }, - }; - - } - - Ok(()) -} - -#[cfg(feature = "target-obsidian")] -pub fn obsidian_get_env_var(name: &str) -> Option { - use js_sys::{Reflect, Object}; - // 1. Get the global `process` object - let global = js_sys::global(); - let process = Reflect::get(&global, &JsValue::from_str("process")).ok()?; - - if process.is_undefined() { - return None; - } - - // 2. Get the `env` object from `process` - let env = Reflect::get(&process, &JsValue::from_str("env")).ok()?; - if env.is_undefined() { - return None; - } - - // 3. Get the `MIZE_STORE` value from `env` - let mize_store = Reflect::get(&env, &JsValue::from_str("MIZE_STORE")).ok()?; - - // 4. Convert the JsValue to a Rust String if it exists - mize_store.as_string() -} - - -pub fn load_module(mize: &mut Mize, name: &str, path: Option) -> MizeResult<()> { - console_log!("loading module NOT IMPLEMENTED: {}", name); - - //wasm_bindgen_futures::spawn_local(load_module_async(mize.clone(), name.to_owned(), path)); - - Ok(()) -} - -/* -async fn load_module_async(mut mize: Mize, name: String, path: Option) -> () { - let name = name.as_str(); - let module_url = fetch_module(&mut mize, name).unwrap(); - let memory = wasm_bindgen::memory(); - - let mut empty_module: Box = Box::new(EmptyModule {}); - let mut mize = mize.clone(); - - let empty_module_ptr = Box::into_raw(Box::new(empty_module)); - let empty_module_usize = empty_module_ptr as usize; - let mize_usize = Box::into_raw(Box::new(mize)) as usize; - - console_log!("testttttttttttttt in load_module_async..."); - - let function_str = format!( - r#" - const promise = new Promise((resolve, reject) => {{ - import("{module_url}/mize_module_{name}.js").then( module => {{ - const wasm_bindgen = module.get_wasm_bindgen(); - - const {{ wasm_get_mize_module_mme }} = wasm_bindgen; - - wasm_bindgen("{module_url}/mize_module_{name}_bg.wasm", memory).then( () => {{ - console.log("empty_module_usize:", empty_module_usize) - console.log("mize_usize:", mize_usize) - //resolve() - resolve(wasm_get_mize_module_mme(empty_module_usize, mize_usize)) - }}) - }}) - }}) - return promise; - "# - ); - - let function = Function::new_with_args("memory, empty_module_usize, mize_usize", &function_str); - - let ret_value: JsValue = match function.call3( - &JsValue::null(), - &memory, - &empty_module_usize.into(), - &mize_usize.into(), - ) { - Ok(val) => val, - Err(err) => { - console_log!("failed to load the wasm mize module...."); - console_log!("{:?}", err); - return; - } - }; - - console_log!("got ret_value: {:?}", ret_value); - let ret_promise = Promise::from(ret_value); - let ret_result = match wasm_bindgen_futures::JsFuture::from(ret_promise).await { - Ok(val) => val, - Err(err) => { - console_log!("err awaiting ret_promise"); - console_log!("{:?}", err); - return; - } - }; - - let mut filled_module = unsafe { Box::from_raw(empty_module_ptr) }; - - console_log!("before...."); - //let a = mize.get("0/config"); - console_log!("after...."); - - //filled_module.init(&instance); - - /* - console_log!("got ret_result: {:?}", ret_result); - let ret_f64 = ret_result.as_f64().unwrap(); - console_log!("got ret_f64: {:?}", ret_f64); - - let ret_usize = ret_f64.floor() as usize; - - let mut module: Box = Box::new(EmptyModule {}); - - unsafe { - let get_mize_module_fn_ptr = ret_usize as *const fn(&mut Box, Instance) -> (); - let get_mize_module_fn: fn(&mut Box, Instance) -> () = unsafe { std::mem::transmute(get_mize_module_fn_ptr) }; - get_mize_module_fn(&mut module, instance.clone()); - } - */ -} - */ - - pub fn fetch_module(mize: &mut Mize, name: &str) -> MizeResult { - let module_name_with_slashes = name.replace(".", "/"); - if let Ok(module_path) = mize - .get(format!( - "self/config/module_dir/{}", - module_name_with_slashes - ))? - .value_string() - { - return Ok(module_path); - } else { - let module_url = mize.get("self/config/module_url")?.value_string()?; - return Ok(format!("{}/{}", module_url, module_name_with_slashes)); - } -} - -async fn download_module(mize: &mut Mize, name: &str) -> MizeResult { - use wasm_bindgen_futures::JsFuture; - use web_sys::{Request, RequestInit, RequestMode, Response}; - - let opts = RequestInit::new(); - opts.set_method("GET"); - opts.set_mode(RequestMode::Cors); - - let url = format!("{}/mize_module_{}_bg.wasm", fetch_module(mize, name)?, name); - - let request = Request::new_with_str_and_init(&url, &opts).unwrap(); - - let window = web_sys::window().unwrap(); - let resp_value = JsFuture::from(window.fetch_with_request(&request)) - .await - .unwrap(); - - let resp: Response = resp_value.dyn_into().unwrap(); - - let wasm_bytes: js_sys::ArrayBuffer = JsFuture::from(resp.array_buffer().unwrap()) - .await - .unwrap() - .dyn_into() - .unwrap(); - - Ok(wasm_bytes) -} - -#[wasm_bindgen] -#[derive(Clone)] -pub struct JsMize { - inner: NonNull, -} - -#[wasm_bindgen] -pub struct JsItem { - mize: NonNull, - id: MizeId, -} - -#[wasm_bindgen] -pub async fn new_js_instance(config_json_str: String) -> JsMize { - panic::set_hook(Box::new(console_error_panic_hook::hook)); - - let config = ItemData::from_json(config_json_str).expect("parsing of json config failed"); - - let mut mize = Mize::with_config(config).expect("Mize::new() failed"); - - let mut js_instance = JsMize { - inner: NonNull::from(Box::leak(Box::new(mize))), - }; - - return js_instance; -} - -#[wasm_bindgen] -impl JsMize { - #[wasm_bindgen] - pub unsafe fn init(&mut self) -> MizeResult<()> { - self.inner.as_mut().init() - } - - #[wasm_bindgen] - pub unsafe fn set(&mut self, id: String, value: String) -> () { - let data = value.into_item_data(); - console_log!("data in set: {}", data); - self.inner.as_mut().set(id, data); - } - - #[wasm_bindgen] - pub unsafe fn get_handle(&mut self, id: String) -> MizeResult { - let item = self.inner.as_mut().get(id)?; - Ok(JsItem { - mize: self.inner, - id: item.id(), - }) - } -} - -impl JsMize { - pub fn inner(&mut self) -> &mut Mize { - unsafe { self.inner.as_mut() } - } -} - -#[wasm_bindgen] -impl JsItem { - #[wasm_bindgen] - pub unsafe fn value_string(&mut self) -> MizeResult { - let item = self.mize.as_mut().get(self.id.clone())?; - let string = item.value_string()?; - Ok(string) - } - - #[wasm_bindgen] - pub unsafe fn as_data_full(&mut self) -> MizeResult { - let item = self.mize.as_mut().get(self.id.clone())?; - let data_raw = item.as_data_full()?; - let jsvalue = serde_wasm_bindgen::to_value(data_raw.cbor())?; - Ok(jsvalue) - } -} - -impl From for JsValue { - fn from(value: MizeError) -> Self { - let string = format!("{:?}", value); - string.into() - } -} diff --git a/src/platform/js/utils.rs b/src/platform/js/utils.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/platform/os/fsstore.rs b/src/platform/os/fsstore.rs deleted file mode 100644 index 0e7f653..0000000 --- a/src/platform/os/fsstore.rs +++ /dev/null @@ -1,218 +0,0 @@ -use ciborium::Value as CborValue; -use std::fs; -use std::fs::OpenOptions; -use std::io::Write; -use std::path::{Path, PathBuf}; -use sysinfo::{Pid, ProcessRefreshKind, RefreshKind, System}; -use tracing::debug; - -use crate::core::id::MizeId; -use crate::core::item::{Item, ItemData}; -use crate::error::{IntoMizeResult, MizeError, MizeResult}; -use crate::instance::store::IdIter; -use crate::instance::{self, Mize}; -use crate::item::get_raw_from_cbor; -use crate::item::IntoItemData; -use crate::memstore::MemStore; -use crate::{core::instance::store::Store, mize_err}; -use tokio::net::UnixStream; - -#[derive(Clone, Debug)] -pub struct FileStore { - path: PathBuf, -} - -impl FileStore { - pub fn new(path_str: &str) -> MizeResult { - let path = Path::new(path_str); - - // 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.display(), pid)); - - } else { - // write our own pid file - fs::remove_file(path.join("pid")); - let pid = std::process::id(); - let mut file = OpenOptions::new().write(true).create(true).open(path.join("pid"))?; - write!(file, "{}", pid)?; - } - */ - - // init the store - if !path.join("next_id").exists() { - fs::write(path.join("next_id"), "1"); - } - - Ok(FileStore { - path: Path::new(&path).to_owned(), - }) - } - - pub fn store_is_opened(store_path: String, instance: &mut Mize) -> MizeResult { - // this was the old method.... - //let valid_pid_file = valid_pid_file(Path::new(&store_path))?.is_some(); - - let can_connect_to_sock = match instance - .spawn_async_blocking("con_test_thread", try_connect_to_sock(store_path.clone())) - { - Ok(_) => true, - Err(_) => false, - }; - debug!( - "MiZe Store at {} opened: {}", - store_path, can_connect_to_sock - ); - Ok(can_connect_to_sock) - } -} - -async fn try_connect_to_sock(store_path: String) -> MizeResult<()> { - match UnixStream::connect(PathBuf::from(store_path).join("sock")).await { - Err(_) => Err(mize_err!("")), - Ok(_) => Ok(()), - } -} - -impl Store for FileStore { - fn new_id(&self) -> MizeResult { - let mut next_id: u64 = - String::from_utf8(fs::read(self.path.join("next_id")).mres_msg(format!( - "could not read next_id at '{}'", - self.path.display() - ))?)? - .parse() - .mres_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(&self, id: MizeId, data: ItemData) -> MizeResult<()> { - let path = self - .path - .join("store") - .join(id.namespace_str()) - .join(id.store_part()); - fs::create_dir_all(self.path.join("store").join(id.namespace_str()))?; - - let file = OpenOptions::new().write(true).create(true).open(path)?; - - ciborium::into_writer(data.cbor(), file)?; - Ok(()) - } - - fn get_links(&self, item: Item) -> MizeResult> { - Ok(Vec::new()) - } - - fn get_backlinks(&self, item: Item) -> MizeResult> { - Ok(Vec::new()) - } - - fn get_value_raw(&self, id: MizeId) -> MizeResult> { - let path = self - .path - .join("store") - .join(id.namespace_str()) - .join(id.store_part()); - - let file = OpenOptions::new().read(true).create(true).open(path)?; - - let cbor_val: CborValue = ciborium::from_reader(file).mres_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 { - let file_path = self - .path - .join("store") - .join(id.namespace_str()) - .join(id.store_part()); - if !file_path.exists() {} - let file = OpenOptions::new() - .read(true) - .open(file_path.clone()) - .map_err(|e| { - mize_err!( - "fsstoree: Unable to open '{}', err: {}", - file_path.display(), - e - ) - })?; - - let cbor_value: CborValue = ciborium::from_reader(file).mres_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 = path_iter.map(|v| v.to_owned()).collect(); - //println!("data: {}", data); - //println!("new_path: {:?}", new_path); - let ret_data = data.get_path(new_path)?; - //println!("ret_data: {}", ret_data); - - return Ok(ret_data); - } - fn id_iter(&self) -> MizeResult { - todo!() - } - fn next_id(&self, prev_id: &str) -> MizeResult> { - todo!() - } - fn first_id(&self) -> MizeResult { - Ok("0".to_owned()) - } -} - -fn valid_pid_file(path: &Path) -> MizeResult> { - let pid_file_path = 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).mres_msg(format!( - "Could not read contents of pid file at '{}'", - pid_file_path.display() - ))?)? - .parse() - .mres_msg(format!( - "Could not parse contents of pid file at '{}' to u32", - pid_file_path.display() - ))?; - - if Path::new("/proc").join(format!("{}", pid)).exists() { - return Ok(Some(pid)); - } else { - return Ok(None); - } -} diff --git a/src/platform/os/logging.rs b/src/platform/os/logging.rs deleted file mode 100644 index a862318..0000000 --- a/src/platform/os/logging.rs +++ /dev/null @@ -1,353 +0,0 @@ -use clap::{crate_version, Arg, Command}; -use clap::{ArgAction, ArgMatches}; -use std::collections::HashMap; -use std::path::PathBuf; - -use colored::Colorize; -use core::fmt; -use std::env; -use std::fmt::Write; -use std::sync::atomic::AtomicUsize; -use std::sync::Arc; -use std::sync::Mutex; -use tokio::sync::mpsc; -use tracing::level_filters::LevelFilter; -use tracing::Event; -use tracing::{debug, error, info, trace, warn}; -use tracing::{field::Visit, Id, Subscriber}; -use tracing::{span_enabled, Instrument, Level}; -use tracing_core::Field; -use tracing_subscriber::filter::EnvFilter; -use tracing_subscriber::fmt::format; -use tracing_subscriber::fmt::FmtContext; -use tracing_subscriber::fmt::FormatEvent; -use tracing_subscriber::fmt::FormatFields; -use tracing_subscriber::fmt::FormattedFields; -use tracing_subscriber::registry::LookupSpan; - -use crate::id::MizeId; -use crate::item::ItemData; -use crate::MizeError; -use crate::MizeResult; - -static DEFAULT_LOG_LEVEL: LevelFilter = LevelFilter::WARN; - -pub fn init_logger(cli_matches: &ArgMatches) { - println!("init_logger called"); - // to save log messages, before the logger is setup - let mut log_messages: Vec<(Level, String)> = Vec::new(); - - log_messages.push((Level::INFO, "Starting Mize".to_owned())); - - // builder with DEFAULT_LOG_LEVEL - let mut builder = tracing_subscriber::fmt::Subscriber::builder(); - - // set loglevel - let mut log_level = DEFAULT_LOG_LEVEL; - log_messages.push(( - Level::TRACE, - format!( - "set log level from DEFAULT_LOG_LEVEL to {}", - DEFAULT_LOG_LEVEL - ), - )); - - // check env RUST_LOG - let mut val_rust_log = level_from_env("RUST_LOG", log_level); - if let Some(level_rust_log) = val_rust_log.0 { - log_level = level_rust_log; - log_messages.push(( - Level::TRACE, - format!( - "set log level from the Variable RUST_LOG to {}", - level_rust_log - ), - )); - } - log_messages.append(&mut val_rust_log.1); - - // check env LOG - let mut val_mize_log = level_from_env("LOG", log_level); - if let Some(level_mize_log) = val_mize_log.0 { - println!("set log level from the Variable LOG to {}", level_mize_log); - log_level = level_mize_log; - log_messages.push(( - Level::TRACE, - format!( - "set log level from the Variable MIZE_LOG to {}", - level_mize_log - ), - )); - } - log_messages.append(&mut val_mize_log.1); - - // check env MIZE_LOG - let mut val_mize_log = level_from_env("MIZE_LOG", log_level); - if let Some(level_mize_log) = val_mize_log.0 { - log_level = level_mize_log; - log_messages.push(( - Level::TRACE, - format!( - "set log level from the Variable MIZE_LOG to {}", - level_mize_log - ), - )); - } - log_messages.append(&mut val_mize_log.1); - - // check -vvvvv flags - let v_flag_count = cli_matches.get_count("verbose"); - if v_flag_count > 0 { - let default_log_level_as_num = match DEFAULT_LOG_LEVEL { - LevelFilter::OFF => 0, - LevelFilter::ERROR => 1, - LevelFilter::WARN => 2, - LevelFilter::INFO => 3, - LevelFilter::DEBUG => 4, - LevelFilter::TRACE => 5, - }; - let new_log_level_num = default_log_level_as_num + v_flag_count; - log_level = match new_log_level_num { - 0 => LevelFilter::OFF, - 1 => LevelFilter::ERROR, - 2 => LevelFilter::WARN, - 3 => LevelFilter::INFO, - 4 => LevelFilter::DEBUG, - 5 => LevelFilter::TRACE, - _ => { - log_messages.push(( - Level::TRACE, - format!( - "the number of verbose (-v) flags passed ({}) exeeds the maximumg log_level", - v_flag_count - ), - )); - LevelFilter::TRACE - } - }; - log_messages.push(( - Level::TRACE, - format!("set log level from the verbose flags to {}", log_level), - )); - } - - // check --log-level arg - if let Some(log_level_arg_string) = cli_matches.get_one::("log-level") { - let log_level_from_arg = match log_level_arg_string.to_owned().to_lowercase().as_str() { - "none" => LevelFilter::OFF, - "trace" => LevelFilter::TRACE, - "debug" => LevelFilter::DEBUG, - "info" => LevelFilter::INFO, - "warn" => LevelFilter::WARN, - "error" => LevelFilter::ERROR, - _ => { - log_messages.push((Level::WARN, format!( - "The argument to --log-level \"{}\" is not a valid log-level. loglevel stays at: {}" - , log_level_arg_string - , log_level - ))); - log_level - } - }; - log_level = log_level_from_arg; - log_messages.push(( - Level::TRACE, - format!( - "set log level from the --log-level arg to {}", - log_level_from_arg - ), - )); - } - - // actually set the log_level on the builder - log_messages.push((Level::INFO, format!("loglevel is now {}", log_level))); - - // filter loging - //let mut my_env_filter = tracing_subscriber::filter::EnvFilter::new("") - //.add_directive("[get_raw_from_cbor]=debug".parse().expect("error parsing log directive")) - //.add_directive("[MemStore::get_value_raw]=trace".parse().expect("error parsing log directive")) - //.add_directive("trace".parse().unwrap()) - //.add_directive("[get_raw_from_cbor]=debug".parse().expect("error parsing log directive")) - //; - - //MinimalTracer::register(); - - println!("log_level: {}", log_level); - let field_formatter = tracing_subscriber::fmt::format::debug_fn(|writer, field, value| { - if field.name() == "message" { - write!(writer, "{:?}", value)?; - } else { - write!(writer, "{}={:?}", field, value)?; - } - Ok(()) - }); - builder - //.with_env_filter(my_env_filter) - .without_time() - .event_format(MyFormatter) - .fmt_fields(field_formatter) - .with_max_level(log_level) - .init(); - - // write out all log messages from log_messages - for (level, msg) in log_messages { - match level { - Level::ERROR => error!("{}", msg), - Level::WARN => warn!("{}", msg), - Level::INFO => info!("{}", msg), - Level::DEBUG => debug!("{}", msg), - Level::TRACE => trace!("{}", msg), - } - } -} - -fn level_from_env( - var_name: &str, - log_level: LevelFilter, -) -> (Option, Vec<(Level, String)>) { - let mut log_messages: Vec<(Level, String)> = Vec::new(); - let var_value = env::var(var_name); - println!("checking env var: {}={:?}", var_name, var_value); - - match var_value { - Ok(val) => { - // set loglevel acording to RUST_LOG - let level = match val.to_lowercase().as_str() { - "none" => LevelFilter::OFF, - "trace" => LevelFilter::TRACE, - "debug" => LevelFilter::DEBUG, - "info" => LevelFilter::INFO, - "warn" => LevelFilter::WARN, - "error" => LevelFilter::ERROR, - _ => { - log_messages.push((Level::WARN, format!( - "The value of Environment Variable {}: \"{}\" is not a valid log-level. loglevel stays at: {}" - , var_name - , val - , log_level - ))); - log_level - } - }; - return (Some(level), log_messages); - } - Err(env::VarError::NotPresent) => {} - Err(env::VarError::NotUnicode(os_string)) => { - let os_string_as_hex: String = os_string - .clone() - .into_encoded_bytes() - .iter() - .map(|b| format!("{:02x}", b).to_string()) - .collect::>() - .join(""); - log_messages.push((Level::DEBUG, format!( - "value of Environment Variable {} was not a unicode valid string. Therefore ignoring it. - \n value with replacement char U+FFFD: {} - \n the WTF-8 raw bytes as hex: {}" - , var_name - , os_string.to_string_lossy(), os_string_as_hex - ))); - } - }; - return (None, log_messages); -} - -struct MyFormatter; - -impl FormatEvent for MyFormatter -where - S: tracing::Subscriber + for<'a> LookupSpan<'a>, - N: for<'a> FormatFields<'a> + 'static, -{ - fn format_event( - &self, - ctx: &FmtContext<'_, S, N>, - mut writer: format::Writer<'_>, - event: &Event<'_>, - ) -> fmt::Result { - // Format values from the event's's metadata: - - let metadata = event.metadata(); - - // set format - //builder.format(|buf, record| match record.level() {}); - - let level_str = match metadata.level() { - &Level::TRACE => format!("[ {} ]", "TRACE".yellow()), - &Level::DEBUG => format!("[ {} ]", "DEBUG".green()), - &Level::INFO => format!("[ {} ]", "INFO".blue()), - &Level::WARN => format!("[ {} ]", "WARN".truecolor(245, 164, 66)), - &Level::ERROR => format!("[ {} ]", "ERROR".red()), - }; - - // with target - // write!(&mut writer, "{} {}: ", level_str, metadata.target())?; - - write!(&mut writer, "{} ", level_str)?; - - // Format all the spans in the event's span context. - if let Some(scope) = ctx.event_scope() { - for span in scope.from_root() { - write!(writer, "{}", span.name())?; - - // `FormattedFields` is a formatted representation of the span's - // fields, which is stored in its extensions by the `fmt` layer's - // `new_span` method. The fields will have been formatted - // by the same field formatter that's provided to the event - // formatter in the `FmtContext`. - let ext = span.extensions(); - let fields = &ext - .get::>() - .expect("will never be `None`"); - - // Skip formatting the fields if the span had no fields. - if !fields.is_empty() { - //write!(writer, "{{{}}}", fields)?; - } - write!(writer, ": ")?; - } - } - - // Write fields on the event - ctx.field_format().format_fields(writer.by_ref(), event)?; - - writeln!(writer); - Ok(()) - } -} - -// thanks: https://stackoverflow.com/a/75546824 -pub struct StringVisitor<'a> { - string: &'a mut String, -} -impl<'a> StringVisitor<'a> { - pub(crate) fn new(string: &'a mut String) -> Self { - StringVisitor { string } - } -} - -impl<'a> Visit for StringVisitor<'a> { - fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { - if field.name() == "message" { - write!(self.string, "{value:?} ").unwrap(); - } else { - write!(self.string, "{} = {:?}; ", field.name(), value).unwrap(); - } - } -} - -struct LogFilter { - target: Option, - level: Option, -} - -fn string_to_level(string: &str) -> Option { - match string.to_lowercase().as_str() { - "info" => Some(Level::INFO), - "debug" => Some(Level::DEBUG), - "warn" | "warning" => Some(Level::WARN), - "trace" => Some(Level::TRACE), - "error" => Some(Level::ERROR), - _ => None, - } -} diff --git a/src/platform/os/mod.rs b/src/platform/os/mod.rs deleted file mode 100644 index bf401d2..0000000 --- a/src/platform/os/mod.rs +++ /dev/null @@ -1,494 +0,0 @@ -use ciborium::Value as CborValue; -use clap::ArgAction; -use clap::ArgMatches; -use clap::{crate_version, Arg, Command}; -use colored::Colorize; -use core::fmt; -use flate2::bufread::GzDecoder; -use serde::Deserialize; -use sha2::{Digest, Sha256, Sha512}; -use std::collections::HashMap; -use std::env; -use std::env::VarError; -use std::fmt::Write; -use std::fs; -use std::fs::File; -use std::io::copy; -use std::path::Path; -use std::path::PathBuf; -use std::sync::atomic::AtomicUsize; -use std::sync::Arc; -use std::sync::Mutex; -use std::time::UNIX_EPOCH; -use tar::Archive; -use tokio::sync::mpsc; -use tracing::level_filters::LevelFilter; -use tracing::Event; -use tracing::{debug, error, info, trace, warn}; -use tracing::{field::Visit, Id, Subscriber}; -use tracing::{span_enabled, Instrument, Level}; -use tracing_core::Field; -use tracing_subscriber::filter::EnvFilter; -use tracing_subscriber::fmt::format; -use tracing_subscriber::fmt::FmtContext; -use tracing_subscriber::fmt::FormatEvent; -use tracing_subscriber::fmt::FormatFields; -use tracing_subscriber::fmt::FormattedFields; -use tracing_subscriber::registry::LookupSpan; - -use crate::config::ConfigOpt; -use crate::error::{IntoMizeResult, MizeError, MizeResult}; -use crate::id::MizeId; -use crate::instance::store::Store; -use crate::instance::EmptyPart; -use crate::instance::Mize; -use crate::item::{data_from_string, IntoItemData, ItemData}; -use crate::memstore::MemStore; -use crate::{mize_err, MizePart}; - -use self::fsstore::FileStore; - -pub mod fsstore; -pub mod logging; - -#[cfg(target_family = "unix")] -mod unix_socket; - -#[cfg(target_family = "unix")] -use crate::platform::os::unix_socket::UnixListener; -//mod web; - -pub fn os_instance_init(mize: &mut Mize) -> MizeResult<()> { - crate::out_macro_stdout()?; - // this is the code, that runs to initialize an Instance on a system with an os present. - - ////// populate values from $MIZE_CONFIG_FILES - if let Ok(config_file_paths) = std::env::var("MIZE_CONFIG_FILES") { - for config_file_path in config_file_paths.split(":") { - println!("reading config file: {config_file_path}"); - let content = std::fs::read_to_string(config_file_path)?; - let mut data = ItemData::from_toml(content.as_str())?; - crate::core::item::set_config_from_data(mize, data)?; - } - } - - ////// load config from MIZE_CONFIG env var - match std::env::var("MIZE_CONFIG") { - Ok(config_string) => { - let data = data_from_string(config_string)?; - crate::core::item::set_config_from_data(mize, data)?; - } - Err(var_err) => match var_err { - VarError::NotPresent => { - debug!("env var MIZE_CONFIG NOT present") - } - VarError::NotUnicode(_) => { - warn!("env var MIZE_CONFIG is not Unicode, so not reading it") - } - }, - }; - - // setup loging to stderr if enabled - if mize - .get_config("log.stderr.enable") - .unwrap_or(ItemData::new()) - .value_bool() - .unwrap_or(false) - { - use tracing::{span_enabled, Instrument, Level}; - let level_string = mize - .get_config("log.level")? - .value_string() - .unwrap_or("info".to_string()); - let log_level = match level_string.to_lowercase().as_str() { - "info" => Level::INFO, - "debug" => Level::DEBUG, - "warn" | "warning" => Level::WARN, - "trace" => Level::TRACE, - "error" => Level::ERROR, - _ => Level::INFO, // the default log level - }; - println!("enabling loggging to stderr with log_level: {}", log_level); - - // builder - let mut builder = tracing_subscriber::fmt::Subscriber::builder(); - - let field_formatter = tracing_subscriber::fmt::format::debug_fn(|writer, field, value| { - if field.name() == "message" { - write!(writer, "{:?}", value)?; - } else { - //write!(writer, "{}={:?}", field, value)?; - } - Ok(()) - }); - builder - //.with_env_filter(my_env_filter) - .without_time() - .event_format(MyFormatter) - .fmt_fields(field_formatter) - .with_max_level(log_level) - .init(); - } - - ////// if a config.store_path is set, upgrade to the filestore there - let mut store_path = match mize.get_config("store")?.value_string() { - Ok(path) => path, - Err(e) => { - // the default store_path: $HOME/.mize - let home_dir = if let Some(dir) = std::env::home_dir() { - dir - } else { - return Err(mize_err!( - "could not get home_dir and store_path is not set in the config" - )); - }; - - let store_path_buff = home_dir.join(".mize"); - let store_path = store_path_buff.display().to_string(); - - mize.set_blocking( - "self/config/store_path", - store_path.clone().into_item_data(), - )?; - - let store_path = mize.get("self/config/store_path")?.value_string()?; - - println!("store_path: {}", store_path); - - store_path - } - }; - - if FileStore::store_is_opened(store_path.to_owned(), mize)? { - // if the store is already opened, connect to the instance, that opened it and join - // it's namespace - - #[cfg(target_family = "unix")] - { - info!("CONNECTING"); - use crate::platform::os::unix_socket; - unix_socket::connect(mize, store_path.into())?; - return Ok(()); - } - - #[cfg(target_family = "windows")] - { - error!("CONNECTING... would connect, but that is not implemented on windows yet"); - } - } else { - // else open it ourselves - let file_store = FileStore::new(store_path.as_str())?; - mize.migrate_to_store(Box::new(file_store))?; - - let path = Path::new(&store_path).to_owned(); - - #[cfg(target_family = "unix")] - { - mize.add_conn_listener(UnixListener::new(path)?)?; - } - - #[cfg(target_family = "windows")] - { - warn!("would add a Listener on a local socket, but that is not yet implemented for windows"); - } - } - - Ok(()) -} - -pub fn seconds_since_modification(path: &Path) -> MizeResult { - let metadata = fs::metadata(path)?; - - let modified = metadata.modified()?; - - let duration = modified.duration_since(UNIX_EPOCH)?; - - Ok(duration.as_secs()) -} - -pub fn get_part_hash( - mize: &mut Mize, - name: &str, - mut options: ItemData, -) -> MizeResult<(String, String)> { - let mut selector_data = mize.get("self/config/selector")?.as_data_full()?; - - // handle the case, when we want a module for not the system we are running on... - println!("get_module_hash: name: {}", name); - let mut name_parts = name.split("."); - if name_parts - .next() - .ok_or(mize_err!("no 0th element in the modName"))? - == "cross" - { - let system = name_parts - .next() - .ok_or(mize_err!("no 1th element in the modName"))?; - let mod_name: String = name_parts.collect(); - println!("get_module_hash: mod_name: {}", mod_name); - if mod_name == "" { - return Err(mize_err!("no 2nd element in the modName")); - } - - selector_data.set_path("system", system)?; - selector_data.set_path("modName", mod_name)?; - } else { - selector_data.set_path("modName", name)?; - } - - selector_data.merge(options); - - // important to produce the same hash for the sama selector data - selector_data.sort_keys(); - - let selector_str = selector_data.to_json()?; - - let mut hasher = Sha256::new(); - - hasher.update(selector_str.clone().as_bytes()); - - let result = hasher.finalize(); - - let mut hex: String = result - .iter() - .map(|b| format!("{:02x}", b).to_string()) - .collect::>() - .join(""); - - hex.truncate(32); - - return Ok((hex, selector_str)); -} - -fn download_part( - mize: &mut Mize, - store_path: &str, - part_url: &str, - part_hash: &str, - part_name: &str, - part_selector: &str, -) -> MizeResult<()> { - let tmp_file_path_gz = format!("{}/{}.tar.gz", store_path, part_hash); - - let tmp_gz_file = if !PathBuf::from(tmp_file_path_gz.clone()).exists() { - let mut tmp_gz_file = File::create(&tmp_file_path_gz)?; - - debug!("downloading part '{}' with hash: {}", part_name, part_hash); - - let response = http_req::request::get( - format!( - "http://{}/mize/dist/{}-{}.tar.gz", - part_url, part_hash, part_name - ), - &mut tmp_gz_file, - )?; - - let code = response.status_code(); - if code != 200.into() { - return Err(mize_err!( - "failed to get part '{}' with hash '{}' and selector: {}", - part_name, - part_hash, - part_selector - ) - .msg(format!( - "the http request to fetch the part returned a status code of: {}", - code - ))); - } - - tmp_gz_file - } else { - std::fs::File::open(tmp_file_path_gz.clone())? - }; - - let tar = GzDecoder::new(std::io::BufReader::new(tmp_gz_file)); - let mut archive = Archive::new(tar); - - //archive.set_mask(umask::Mode::parse("rwxrwxrwx")?.into()); - - let target_dir = format!("{}/parts/{}", store_path, part_hash); - - std::fs::create_dir_all(target_dir.as_str())?; - - archive.unpack(target_dir.as_str())?; - - fs::remove_file(&tmp_file_path_gz)?; - - Ok(()) -} - -pub fn fetch_part(mize: &mut Mize, part_name: &str) -> MizeResult { - let part_name_with_slashes = part_name.replace(".", "/"); - if let Ok(part_path) = mize - .get(format!("self/config/part_dir/{}", part_name_with_slashes))? - .value_string() - { - // in case a dir is configured, which holds the parts output - return Ok(part_path); - } else { - // if null, load it from the url - let part_url = mize.get("self/config/part_url")?.value_string()?; - - let store_path = mize.get("self/config/store_path")?.value_string()?; - - let (part_hash, part_selector) = get_part_hash(mize, part_name, ItemData::new())?; - - if !PathBuf::from(format!("{}/parts/{}", store_path, part_hash.as_str())).exists() { - // download part if it does not exist - download_part( - mize, - store_path.as_str(), - part_url.as_str(), - part_hash.as_str(), - part_name, - part_selector.as_str(), - )?; - } - - return Ok(format!("{}/parts/{}", store_path, part_hash.as_str())); - } -} - -pub fn load_part(mize: &mut Mize, part_name: &str, path: Option) -> MizeResult<()> { - let part_path = if path.is_some() { - format!("{}/lib/lib{}_part.so", path.unwrap(), part_name) - } else { - format!( - "{}/lib/lib{}_part.so", - fetch_part(mize, part_name)?, - part_name - ) - }; - - let lib = unsafe { libloading::Library::new(part_path)? }; - - let func: libloading::Symbol< - unsafe extern "C" fn(&mut Box, Mize) -> (), - > = unsafe { lib.get(format!("make_mize_part_{}", part_name).as_bytes())? }; - - let mut part: Box = Box::new(EmptyPart { mize: mize.clone() }); - - unsafe { func(&mut part, mize.clone()) }; - - part.init(mize)?; - - mize.add_part(part)?; - - unsafe { - // dropping the lib, would (i suspect) free all memory, of the library's code, which would - // make the part's vtable point into empty memory - std::mem::forget(lib); - } - - Ok(()) -} - -pub fn config_from_cli_args(matches: &ArgMatches) -> MizeResult { - let mut config = ItemData::new(); - - if let Some(config_file_path) = matches.get_one::("config") { - config.merge(config_from_file(config_file_path.to_string())?); - trace!("config after --config arg: {}", config); - } - - if let Some(config_string) = matches.get_one::("opt") { - config.merge(data_from_string(config_string.to_string())?); - trace!("config after --opt arg: {}", config); - } - - return Ok(config); -} - -pub fn config_from_file(file_path: String) -> MizeResult { - let toml_string = fs::read_to_string(&file_path) - .mres_msg(format!("Could not read file {} as mize config", &file_path))?; - - let item_data = ItemData::from_toml(toml_string.as_str())?; - - return Ok(item_data); -} - -struct MyFormatter; - -impl FormatEvent for MyFormatter -where - S: tracing::Subscriber + for<'a> LookupSpan<'a>, - N: for<'a> FormatFields<'a> + 'static, -{ - fn format_event( - &self, - ctx: &FmtContext<'_, S, N>, - mut writer: format::Writer<'_>, - event: &Event<'_>, - ) -> fmt::Result { - // Format values from the event's's metadata: - - let metadata = event.metadata(); - - // set format - //builder.format(|buf, record| match record.level() {}); - - let level_str = match metadata.level() { - &Level::TRACE => format!("[ {} ]", "TRACE".yellow()), - &Level::DEBUG => format!("[ {} ]", "DEBUG".green()), - &Level::INFO => format!("[ {} ]", "INFO".blue()), - &Level::WARN => format!("[ {} ]", "WARN".truecolor(245, 164, 66)), - &Level::ERROR => format!("[ {} ]", "ERROR".red()), - }; - - // with target - // write!(&mut writer, "{} {}: ", level_str, metadata.target())?; - - write!(&mut writer, "{} ", level_str)?; - - // Format all the spans in the event's span context. - if let Some(scope) = ctx.event_scope() { - for span in scope.from_root() { - write!(writer, "{}", span.name())?; - - // `FormattedFields` is a formatted representation of the span's - // fields, which is stored in its extensions by the `fmt` layer's - // `new_span` method. The fields will have been formatted - // by the same field formatter that's provided to the event - // formatter in the `FmtContext`. - let ext = span.extensions(); - let fields = &ext - .get::>() - .expect("will never be `None`"); - - // Skip formatting the fields if the span had no fields. - if !fields.is_empty() { - //write!(writer, "{{{}}}", fields)?; - } - write!(writer, ": ")?; - } - } - - // Write fields on the event - ctx.field_format().format_fields(writer.by_ref(), event)?; - - writeln!(writer); - Ok(()) - } -} - -// thanks: https://stackoverflow.com/a/75546824 -pub struct StringVisitor<'a> { - string: &'a mut String, -} -impl<'a> StringVisitor<'a> { - pub(crate) fn new(string: &'a mut String) -> Self { - StringVisitor { string } - } -} - -impl<'a> Visit for StringVisitor<'a> { - fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { - if field.name() == "message" { - write!(self.string, "{value:?} ").unwrap(); - } else { - write!(self.string, "{} = {:?}; ", field.name(), value).unwrap(); - } - } -} diff --git a/src/platform/os/unix_socket.rs b/src/platform/os/unix_socket.rs deleted file mode 100644 index 03d264a..0000000 --- a/src/platform/os/unix_socket.rs +++ /dev/null @@ -1,233 +0,0 @@ -use ciborium::Value as CborValue; -use flume::{unbounded, Receiver, Sender}; -use std::fs; -use std::path::{Path, PathBuf}; -use tokio::io::{AsyncReadExt, AsyncWriteExt, Interest}; -use tokio::net::unix::{OwnedReadHalf, OwnedWriteHalf}; -use tokio::net::{UnixListener as TokioUnixListener, UnixStream}; -use tracing::{debug, info, warn}; - -use crate::error::{IntoMizeResult, MizeError, MizeResult}; -use crate::instance::connection::{ConnListener, Connection}; -use crate::instance::{self, Mize}; -use crate::proto::{self, MizeMessage}; - -pub struct UnixListener { - sock_path: PathBuf, -} - -impl UnixListener { - pub fn new(store_path: PathBuf) -> MizeResult { - Ok(UnixListener { - sock_path: store_path.join("sock").to_owned(), - }) - } -} - -pub fn connect(instance: &mut Mize, store_path: PathBuf) -> MizeResult<()> { - let conn_id = instance.spawn_async_blocking( - "unix_connection", - connect_async(instance.clone(), store_path), - )?; - - let ns_of_peer_str = instance - .get(format!( - "inst/con_by_id/{}/peer/self/config/namespace", - conn_id - ))? - .value_string()?; - let ns_of_peer = instance.namespace_from_string(ns_of_peer_str)?; - - info!( - "connect_async ... ns_of_peer: {}", - ns_of_peer.clone().as_string() - ); - - instance.connection_set_namespace(conn_id, ns_of_peer.clone()); - instance.set_namespace(ns_of_peer); - - Ok(()) -} - -async fn connect_async(mut instance: Mize, store_path: PathBuf) -> MizeResult { - let mut stream = UnixStream::connect(store_path.join("sock")).await?; - let (unix_read, unix_write) = stream.into_split(); - - let (send_tx, send_rx) = unbounded::(); - - let conn_id = instance.new_connection(send_tx)?; - - let cloned_instance = instance.clone(); - instance.spawn_background("incomming", move || { - let result = unix_incomming(unix_read, cloned_instance, conn_id); - // if unix incomming fails, close the connection - if let Err(err) = result { - warn!("Connection closing because of EOF"); - } - Ok(()) - }); - - let outgoing_cloned_instance = instance.clone(); - instance.spawn_background("outgoing", move || { - let result = unix_outgoing(unix_write, send_rx, outgoing_cloned_instance, conn_id); - // if writing fails, close this connection - if let Err(err) = result { - warn!("Connection closing because of EOF"); - } - Ok(()) - }); - - return Ok(conn_id); -} - -impl ConnListener for UnixListener { - fn listen(self, mut instance: Mize) -> MizeResult<()> { - instance.spawn_async("unix listen async", unix_listen(self, instance.clone())); - Ok(()) - } -} - -async fn unix_listen(listener: UnixListener, mut instance: Mize) -> MizeResult<()> { - // remove the file at sock_path if it already exists - fs::remove_file(&listener.sock_path); - - let listener = TokioUnixListener::bind(&listener.sock_path).mres_msg(format!( - "Could not bind to unix socket at '{}'", - listener.sock_path.display() - ))?; - - loop { - let (mut unix_sock, addr) = listener - .accept() - .await - .mres_msg("Error while accepting Unix sock connection")?; - info!("new connection"); - - let (send_tx, send_rx) = unbounded::(); - let (unix_read, unix_write) = unix_sock.into_split(); - - let conn_id = instance.new_connection(send_tx)?; - let cloned_instance = instance.clone(); - instance.spawn_background("incomming", move || { - let result = unix_incomming(unix_read, cloned_instance, conn_id); - // if unix incomming fails, close the connection - if let Err(err) = result { - warn!("Connection closing because of EOF"); - } - Ok(()) - }); - - let outgoing_cloned_instance = instance.clone(); - instance.spawn_background("outgoing", move || { - let result = unix_outgoing(unix_write, send_rx, outgoing_cloned_instance, conn_id); - // if writing fails, close this connection - if let Err(err) = result { - warn!("Connection closing because of EOF"); - } - Ok(()) - }); - } -} - -fn unix_outgoing( - mut unix_write: OwnedWriteHalf, - send_rx: Receiver, - mut instance: Mize, - conn_id: u64, -) -> MizeResult<()> { - for msg in send_rx { - debug!("unix outgoing got msg: {}", msg); - let adapter = MyCiboriumWriter { - inner: &mut unix_write, - instance: &mut instance, - }; - let value = msg.value(); - ciborium::into_writer(&value, adapter)? - } - Ok(()) -} - -pub fn unix_incomming( - mut unix_read: OwnedReadHalf, - mut instance: Mize, - conn_id: u64, -) -> MizeResult<()> { - loop { - //println!("unix incoming loop..."); - let adapter = MyCiboriumReader { - inner: &mut unix_read, - instance: &mut instance, - }; - let value: CborValue = ciborium::from_reader(adapter)?; - if let CborValue::Integer(_) = value { - break; - } - let msg = MizeMessage::new(value, conn_id); - debug!("unix incoming got msg: {}", msg); - instance.got_msg(msg); - } - Ok(()) -} - -struct MyCiboriumWriter<'a> { - inner: &'a mut OwnedWriteHalf, - instance: &'a mut Mize, -} - -impl<'a> ciborium_io::Write for MyCiboriumWriter<'a> { - type Error = MizeError; - fn write_all(&mut self, data: &[u8]) -> Result<(), Self::Error> { - //println!("CALL: write_all"); - let runtime = self.instance.runtime.lock()?; - //println!("after runtime"); - let num_read = runtime.block_on(self.inner.write_all(data))?; - Ok(()) - } - fn flush(&mut self) -> Result<(), Self::Error> { - //println!("CALL flush"); - let handle = self.instance.async_get_handle(); - let result = handle.block_on(self.inner.flush()); - //println!("flush result: {:?}", result); - Ok(()) - } -} - -struct MyCiboriumReader<'a> { - inner: &'a mut OwnedReadHalf, - instance: &'a mut Mize, -} - -async fn test(test: &mut OwnedReadHalf, buf: &mut [u8]) { - //println!("hello from async..."); - //println!("len: {}", buf.len()); - let num_read = test.read_u8().await; - //println!("num_read: {:?}", num_read); - //test.read_exact(buf).await; - //println!("hello from async... twoooooooooooooo"); -} - -impl<'a> ciborium_io::Read for MyCiboriumReader<'a> { - type Error = MizeError; - fn read_exact(&mut self, data: &mut [u8]) -> Result<(), Self::Error> { - //println!("data before: {:?}", data); - //let runtime = self.instance.runtime.lock()?; - //println!("are we here after runtime lock()"); - //runtime.block_on(test(self.inner, data)); - //println!("are we hereeeeeeeeeeeeeeeeeeee"); - - //return Ok(()); - - //println!("incoming before block_on"); - let handle = self.instance.async_get_handle(); - let num_read = handle.block_on(self.inner.read_exact(data))?; - //println!("incoming num_read: {:?}", num_read); - //println!("data after: {:?}", data); - - // if we read 0 bytes, that means the reader stream closed and we should terminate the - // connection - //if num_read == 0 { - //return Err(MizeError::new().msg("ReceiverStream closed")); - //} - Ok(()) - } -} diff --git a/src/platform/os/web.rs b/src/platform/os/web.rs deleted file mode 100644 index 8587e0a..0000000 --- a/src/platform/os/web.rs +++ /dev/null @@ -1,239 +0,0 @@ - -static SERVER_PORT: u16 = 3000; -static API_ENDPOINT: &str = "@mize"; - - -pub fn run() -> Result { - /* - * - Run a Webserver - * - * - * - */ - - - // I will deal with renders later. cli only for now - // let renders = - -// for render in &*renders { -// match render.render_type { -// RenderType::JsonUi => {}, -// RenderType::WebComponent => { -// let url_path = String::from("/api/render/") + &render.name + "/webroot"; -// let file_path = mutexes.mize_folder.clone() + "/mr/" + &render.folder[..] + "/" + &render.webroot.clone()[..]; -// let serve_dir = get_service(ServeDir::new(&file_path)).handle_error(handle_error); - -// app = app.nest_service(&url_path, serve_dir); -// }, -// } -// } - - - // let serve_client = get_service(ServeDir::new("js-client/src")).handle_error(handle_error); - - let mut app = Router::new() - .route(format!("/{}/socket", API_ENDPOINT), get(websocket_handler)) -// .route(format!("/{}/render/:id", API_ENDPOINT), get(get_render_main)) -// .route(format!("/{}/file", API_ENDPOINT), get(get_file_handler)) -// .merge(SpaRouter::new(format!("/{}/client", API_ENDPOINT), "js-client/src").index_file("main.html")) -// .nest_service(format!("/{}/client", API_ENDPOINT), serve_client) - .with_state(main) - .fallback(render_item); - - let addr = SocketAddr::from(([0, 0, 0, 0], SERVER_PORT)); - // tracing::debug!("listening on {}", addr); - - axum::Server::bind(&addr) - .serve(app.into_make_service()) - .await - .expect(format!("Unable to bind axum::Server to {}", addr)); -} - -pub struct Web { -} - -impl Web { - -} - - -async fn handle_error(_err: std::io::Error) -> impl IntoResponse { - MizeError::new(0).msg("internal server error").handle() - (StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong...") -} - -async fn render_item(uri: Uri) -> impl IntoResponse { - Html(fs::read_to_string("js-client/src/main.html").unwrap()) -} - -//#[axum_macros::debug_handler] -//async fn get_render_main(extract::Path(id): extract::Path, State(mutexes): State) -> http::Response { -// let renders = &*mutexes.renders.lock().await; - -// let render = renders.iter().filter(|&render| render.name == id).nth(0) -// .unwrap_or(renders.iter().filter(|&render| render.name == "mize-mmejs").nth(0).expect("mize-mmejs")); - -// let file_path = mutexes.mize_folder.clone() + "/mr/" + &render.folder + "/" + &render.main; - -// match render.render_type { -// RenderType::JsonUi => { -// return Response::builder() -// .header("content-type", "application/json") -// .status(StatusCode::OK) -// .body(fs::read_to_string(file_path).unwrap()).unwrap(); -// }, -// RenderType::WebComponent => { -// return Response::builder() -// .header("content-type", "application/javascript") -// .status(StatusCode::OK) -// .body(fs::read_to_string(file_path).unwrap()).unwrap(); -// }, -// } -//} - -async fn websocket_handler( - ws: WebSocketUpgrade, - State(main): State<&Main>, - headers: HeaderMap, -) -> impl IntoResponse { - ws.on_upgrade(|socket| handle_websocket_connection(socket, main, headers)) -} - -async fn handle_websocket_connection( - socket: WebSocket, - main: &Main, - headers: HeaderMap, -){ - //TODO: auth - - //socket_tx.send() ... send out the socket - //socket_rx.read() ... read a message from the socket - let (mut socket_tx, mut socket_rx) = socket.split(); - - // msg_tx.send() ... send a MizeMessage to a Peer. should be in a Peer struct - // msg_rx.read() ... read MizeMessages that should be sent to the Peer that this ws connection is to - let (msg_tx, msg_rx): (Sender, Receiver) = mpsc::channel(SOCKET_CHANNEL_SIZE); - - // why is this actually - let mut msg_rx = ReceiverStream::new(msg_rx); - - // check if mize-module header exists -// let origin = if let Some(mod_header_val) = headers.get("mize-module"){ - -// let mut mods = mutexes.modules.lock().await; -// let mut client_id = mutexes.next_free_client_id.lock().await; -// let mut module = Module{ -// tx: msg_tx.clone(), -// client_id: *client_id, -// name: String::from("tmp"), -// kind: ModuleKind::Extern(), -// registered_types: Vec::new(), -// }; - -// *client_id += 1; - -// if let Ok(name) = mod_header_val.to_str() { -// module.name = name.to_string(); -// } else { -// let err = MizeError::new(113) -// .extra_msg("The mize-module Header could not be decoded into a String."); - -// msg_tx.send(proto::MizeMessage::Json(err.to_json_message())).await; -// return; -// }; -// println!("module {} connected", module.name); -// mods.push(module.clone()); -// drop(mods); -// Peer::Module(module) - -// } else { -// }; - - // Forwarding messages - tokio::spawn(async move { - while let Some(msg) = msg_rx.next().await { - match msg { - proto::MizeMessage::Json(json_msg) => { - if let Ok(msg) = serde_json::to_string(&json_msg) { - let result = socket_tx.send(Message::Text(msg.clone())).await; - if let Err(e) = result { - println!("Client no longer Connected: {:?}", e); - remove_peer(myorigin.clone(), mymutexes.clone()).await; - } else { - println!("SENDING: {}", msg); - } - } else { - let err: MizeError = MizeError::new(11).extra_msg("error while serializing a json message").handle(); - if let Ok(text) = serde_json::to_string(&err.to_json()){ - socket_tx.send(Message::Text(text)); - } else { - MizeError::new(11).extra_msg("not even being able to serialize an error, while failing to serializing a message").handle(); - } - } - } - proto::MizeMessage::Bin(bin_msg) => { - socket_tx.send(Message::Binary(bin_msg.raw)).await; - } - proto::MizeMessage::Pong() => { - socket_tx.send(Message::Pong(Vec::new())).await; - } - proto::MizeMessage::Close((num, reason)) => { - println!("SENDING Close message"); - socket_tx.send(Message::Close(Some(CloseFrame{code: num, reason: Cow::Owned(reason)}))).await; - } - } - } - }); - - // Reading messages - while let Some(result) = socket_rx.next().await { - let msg = if let Ok(msg) = result {msg} else { - let err = MizeError::new(115).extra_msg("TCP Connection Closed"); - remove_peer(origin.clone(), mutexes.clone()); - return; - }; - match msg { - Message::Binary(b) => { - println!("Recieved a Binary Message. Those are not implemented yet.") - }, - - - Message::Text(text) => { - println!("GOT: {}", text); - let json_msg: proto::JsonMessage = serde_json::from_str(&text).expect("error parsing json"); - if let Err(err) = proto::handle_json_msg(json_msg, origin.clone(), mutexes.clone()).await { - let err_msg: MizeMessage = err.handle().into(); - origin.send(err_msg).await; - }; - }, - - Message::Close(inner) => { - match inner { - Some(CloseFrame{code, reason}) => { - origin.send(MizeMessage::Close((code, reason.into_owned()))).await; - }, - None => { - origin.send(MizeMessage::Close((1000, "You didn't send a Close Reason".to_owned()))).await; - } - }; - - println!("Close from Client"); - remove_peer(origin.clone(), mutexes.clone()).await; - } - - - Message::Ping(_) => { - msg_tx.send(MizeMessage::Pong()); - }, - - - Message::Pong(_) => { - let err = MizeError::new(11) - .extra_msg("unhandeld WebSocket-Message type: Pong") - .handle(); - msg_tx.send(proto::MizeMessage::Json(err.to_json_message())).await; - }, - - }; - }; -} diff --git a/src/test/mod.rs b/src/test/mod.rs deleted file mode 100644 index 52f58df..0000000 --- a/src/test/mod.rs +++ /dev/null @@ -1,31 +0,0 @@ - -use crate::instance::MizeInstance; - -#[test] -fn most_minimal_instance_usage() { - // so I'm actually starting the effort for a better code base here in the tests - // i want to write down how you would use the very important instance type - // and then implement it to make it usable in this way - - // how every mize based program to run on an os should create a mize instance - // opens the instance the way the user has configured (with env vars, build args, or config - // files) - // and we just call it "new()" and not "default_system()" so that it is clear that this is the - // method that should be used - let mize = MizeInstance::new(); - - // then the most important things you do with your mize instance is to get/set stuff - let name: MizeItem = mize.get("1/namespace"); - let id = mize.new_item(); - mize.set(id.join("name"), "test-item"); - - // or register update callbacks and update - //mize.on_update("5/name", |delta| println!(delta.new_value())); - //mize.update("5/name", "other-item") - - // the goal is that also most things about the MizeInstance itself is controlled by - // get/set/update -ing values at the 0/ paths -} - - -