removed the old src

This commit is contained in:
Sebastian Moser
2026-10-22 22:13:47 +02:00
parent 7f86f3dc5e
commit 387c31259d
27 changed files with 0 additions and 5919 deletions

View File

@@ -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<dyn Fn() -> ItemData + Send + Sync>;
pub struct ConfigOpt {
pub name: String,
pub val: Option<ItemData>,
pub thunk: Option<ConfigThunk>,
}
#[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(())
}

View File

@@ -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<T> = Result<T, MizeError>;
pub trait MizeResultTrait<T> {
fn critical(self) -> T;
fn as_std(self) -> Result<T, MizeErrorWhichImplementsError>;
}
pub trait IntoMizeResult<T, S> {
fn mres(self) -> MizeResult<T>;
fn mres_msg(self, msg: S) -> MizeResult<T>
where
S: std::fmt::Display;
}
#[derive(Debug, Clone)]
pub struct MizeError {
pub category: Vec<String>,
pub code: u32,
pub messages: Vec<String>,
//pub caused_by_msg: Option<CausedByMessage>,
pub code_location: Option<MizeCodeLocation>,
pub backtrace: String,
}
/*
#[derive(Debug, Clone)]
pub struct CausedByMessage {
// peer: &Connection, // TODO: add later
msg: Box<MizeMessage>,
}
*/
#[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<E>(mut self, msg: E) -> MizeError
where
E: std::fmt::Display,
{
self.messages.push(format!("{}", msg));
return self;
}
pub fn category<T>(mut self, category: T) -> MizeError
where
T: Into<String>,
{
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<T> {
fn extra_msg<E>(self, msg: E) -> Result<T, MizeError>
where E: std::fmt::Display
;
fn handle(self) -> Result<T, MizeError>;
fn is_critical(self) -> T;
}
impl<T> MizeResultExtension<T> for Result<T, MizeError> {
fn msg<E>(mut self, msg: E) -> Result<T, MizeError>
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<T, MizeError> {
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<FromUtf8Error> 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<T: Display> From<T> 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<T> MizeResultTrait<T> for MizeResult<T> {
fn critical(self) -> T {
match self {
Ok(val) => val,
Err(err) => {
err.critical();
unreachable!()
}
}
}
fn as_std(self) -> Result<T, MizeErrorWhichImplementsError> {
match self {
Ok(val) => Ok(val),
Err(err) => Err(MizeErrorWhichImplementsError { inner: err }),
}
}
}
impl<T, E, S> IntoMizeResult<T, S> for Result<T, E>
where
E: std::fmt::Display,
{
#[track_caller]
fn mres(self) -> MizeResult<T> {
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<T>
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<MizeError> 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<T> {
fn mres(self) -> MizeResult<T>;
}
#[cfg(feature = "target-js")]
impl<T> IntoMizeResultJsValue<T> for Result<T, JsValue> {
fn mres(self) -> MizeResult<T> {
match self {
Ok(value) => Ok(value),
Err(err) => Err(mize_err!("From JsValue: {:?}", err)),
}
}
}

View File

@@ -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<MizeId>;
}
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<String> {
let tmp = self.path();
let mut path_iter = tmp.into_iter();
path_iter.next();
let new_path: Vec<String> = 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<MizeId> {
instance.id_from_string(self.to_owned())
}
}
impl IntoMizeId for String {
fn to_mize_id(self, instance: &Mize) -> MizeResult<MizeId> {
instance.id_from_string(self)
}
}
impl IntoMizeId for &String {
fn to_mize_id(self, instance: &Mize) -> MizeResult<MizeId> {
instance.id_from_string(self.to_owned())
}
}
impl IntoMizeId for Vec<String> {
fn to_mize_id(self, instance: &Mize) -> MizeResult<MizeId> {
instance.id_from_vec_string(self)
}
}
impl IntoMizeId for Vec<&String> {
fn to_mize_id(self, instance: &Mize) -> MizeResult<MizeId> {
let owned = self
.into_iter()
.map(|s| s.to_owned())
.collect::<Vec<String>>();
instance.id_from_vec_string(owned)
}
}
impl IntoMizeId for &[&str] {
fn to_mize_id(self, instance: &Mize) -> MizeResult<MizeId> {
let mut vec: Vec<String> = 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<MizeId> {
let mut vec: Vec<String> = 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<MizeId> {
Ok(self)
}
}
// would only work with a global id_pool
// for now use Instance::new_id()
//impl<T: Into<String>> From<T> for MizeId {
//fn from(value: T) -> Self {
//let string = value.into();
//let path: Vec<String> = 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::<String>::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::<String>::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::<String>::new(), id_fife.after_store_part());
//TODO: add the parsing form mize:// urls....
Ok(())
}
}

View File

@@ -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<MizeMessage>,
pub id: u64,
pub ns: Option<Namespace>,
}
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<ItemData> {
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<ItemData> {
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::<Vec<&String>>())?;
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);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +0,0 @@

View File

@@ -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<Item<Self>> 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<Vec<MizeId>>;
fn get_backlinks(&self, item: Item) -> MizeResult<Vec<MizeId>>;
fn new_id(&self) -> MizeResult<String>;
fn get_value_raw(&self, id: MizeId) -> MizeResult<Vec<u8>>;
fn get_value_data_full(&self, id: MizeId) -> MizeResult<ItemData>;
fn id_iter(&self) -> MizeResult<IdIter>;
fn next_id(&self, prev_id: &str) -> MizeResult<Option<String>>;
fn first_id(&self) -> MizeResult<String>;
}
pub struct IdIter {
cur_id: String,
store: Box<dyn Store>,
}
impl IdIter {
pub fn new(store: Box<dyn Store>) -> MizeResult<IdIter> {
Ok(IdIter {
cur_id: store.first_id()?,
store,
})
}
}
impl Iterator for IdIter {
type Item = MizeResult<String>;
fn next(&mut self) -> Option<Self::Item> {
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,
}
}
}

View File

@@ -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<Mize>,
pub id: MizeId,
}
impl Update {
pub fn new_item(&self) -> MizeResult<Item> {
self.instance.get(self.id.clone())
}
}
pub enum Subscription {
Connection(Connection),
Closure(Box<dyn Fn(Update) -> MizeResult<()> + Send>),
Channel(Sender<Update>),
}
impl Subscription {
pub fn from_conn(conn: Connection) -> Subscription {
Subscription::Connection(conn)
}
pub fn from_closure(closure: Box<dyn Fn(Update) -> MizeResult<()> + Send>) -> Subscription {
Subscription::Closure(closure)
}
pub fn from_sender(tx: Sender<Update>) -> 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...")
}
}

View File

@@ -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");
}
*/

View File

@@ -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<Connection>), // 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<Operation>, 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<Operation>, 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(())
}

View File

@@ -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<Vec<u8>> {
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<String> {
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<ItemData> {
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::<Vec<String>>()
.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<V: Into<ItemData> + 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::<Vec<String>>()
.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<ItemData> {
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<String> {
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<String> {
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<bool> {
match self.cbor() {
CborValue::Bool(val) => Ok(*val),
_ => Err(mize_err!("this ItemData has no string value")),
}
}
pub fn as_bool(self) -> Option<bool> {
match self.cbor() {
CborValue::Bool(val) => Some(*val),
_ => None,
}
}
pub fn from_string<S: Into<String>>(into_string: S) -> ItemData {
let string = into_string.into();
let data = CborValue::Text(string);
return ItemData(data);
}
pub fn to_json(self) -> MizeResult<String> {
let mut result: Vec<u8> = 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<ItemData> {
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<T: Into<String>>(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::<i128>() {
return int.into_item_data();
}
return CborValue::Text(value_str).into_item_data();
}
pub fn set_path<P: IntoPath, D: IntoItemData>(&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<P: IntoPath>(&self, path: P) -> MizeResult<ItemData> {
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<Vec<String>> {
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<Vec<String>> {
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<String>,
path_accu: &mut Vec<String>,
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<ItemData> {
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<String>) -> 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<String>,
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::<Vec<_>>().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::<Vec<String>>()
.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<String>;
}
pub trait IntoItemData {
fn into_item_data(self) -> ItemData;
}
impl IntoPath for &str {
fn into_path(self) -> Vec<String> {
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<String> {
self.into_iter().map(|v| (*v).to_owned()).collect()
}
}
impl IntoPath for Vec<String> {
fn into_path(self) -> Vec<String> {
self
}
}
impl IntoPath for Vec<&str> {
fn into_path(self) -> Vec<String> {
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<String> {
fn into_item_data(self) -> ItemData {
let array = self
.into_iter()
.map(|v| v.into_item_data().cbor().to_owned())
.collect::<Vec<_>>();
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<usize, std::io::Error> {
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<u8> = Vec::new();
let mut buf_other: Vec<u8> = 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::<Vec<&str>>())?;
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(())
}

View File

@@ -1,3 +0,0 @@
#![ allow( warnings ) ]

View File

@@ -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();
};
}

View File

@@ -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<Mutex<MemStoreInner>>,
}
pub type MemStoreId = u64;
#[derive(Debug)]
struct MemStoreInner {
map: HashMap<u64, ItemData>,
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<Vec<MizeId>> {
let inner = self.inner.lock()?;
Ok(Vec::new())
}
fn get_backlinks(&self, item: Item) -> MizeResult<Vec<MizeId>> {
let inner = self.inner.lock()?;
Ok(Vec::new())
}
fn new_id(&self) -> MizeResult<String> {
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<Vec<u8>> {
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<ItemData> {
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> {
IdIter::new(Box::new(self.to_owned()))
}
fn next_id(&self, prev_id_str: &str) -> MizeResult<Option<String>> {
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<String> {
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<u64> {
str_to_u64(id.store_part())
}
fn str_to_u64(id_str: &str) -> MizeResult<u64> {
id_str.parse().mres_msg(format!(
"Could not parse the store_part of mizeid {} into a u64 for the MemStore",
id_str
))
}

View File

@@ -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<u8> {
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<T: IntoItemData, U: IntoItemData>(
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<MessageCmd> {
// 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<Vec<String>> {
// 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<String> = 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<MizeId> {
let id_str = self.id_str()?;
return instance.new_id(id_str);
}
pub fn data(&mut self) -> MizeResult<ItemData> {
// 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<usize, std::io::Error> {
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)
}
}

View File

View File

@@ -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<Option<Box<dyn Fn(String) -> 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<String>,
) -> MizeResult<()> {
Ok(())
}
pub fn fetch_part(instance: &mut core::instance::Mize, name: &str) -> MizeResult<String> {
Ok("oh noooooooooooooo, something went really really wrong, if this ends up in the executable....".to_owned())
}

View File

@@ -1,8 +0,0 @@
{
"tasks": {
"dev": "deno run --watch main.ts"
},
"imports": {
"@std/assert": "jsr:@std/assert@1"
}
}

View File

@@ -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
}

View File

@@ -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<String> {
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<String>) -> 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<String>) -> () {
let name = name.as_str();
let module_url = fetch_module(&mut mize, name).unwrap();
let memory = wasm_bindgen::memory();
let mut empty_module: Box<dyn Module + Send + Sync> = 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<dyn Module + Send + Sync> = Box::new(EmptyModule {});
unsafe {
let get_mize_module_fn_ptr = ret_usize as *const fn(&mut Box<dyn Module + Send + Sync>, Instance) -> ();
let get_mize_module_fn: fn(&mut Box<dyn Module + Send + Sync>, 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<String> {
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<js_sys::ArrayBuffer> {
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<Mize>,
}
#[wasm_bindgen]
pub struct JsItem {
mize: NonNull<Mize>,
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<JsItem> {
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<String> {
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<JsValue> {
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<MizeError> for JsValue {
fn from(value: MizeError) -> Self {
let string = format!("{:?}", value);
string.into()
}
}

View File

@@ -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<FileStore> {
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<bool> {
// 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<String> {
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<Vec<MizeId>> {
Ok(Vec::new())
}
fn get_backlinks(&self, item: Item) -> MizeResult<Vec<MizeId>> {
Ok(Vec::new())
}
fn get_value_raw(&self, id: MizeId) -> MizeResult<Vec<u8>> {
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<ItemData> {
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<String> = 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<IdIter> {
todo!()
}
fn next_id(&self, prev_id: &str) -> MizeResult<Option<String>> {
todo!()
}
fn first_id(&self) -> MizeResult<String> {
Ok("0".to_owned())
}
}
fn valid_pid_file(path: &Path) -> MizeResult<Option<u32>> {
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);
}
}

View File

@@ -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::<String>("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<LevelFilter>, 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::<Vec<String>>()
.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<S, N> FormatEvent<S, N> 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::<FormattedFields<N>>()
.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<String>,
level: Option<Level>,
}
fn string_to_level(string: &str) -> Option<Level> {
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,
}
}

View File

@@ -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<u64> {
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::<Vec<String>>()
.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<String> {
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<String>) -> 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<dyn MizePart + Send + Sync>, Mize) -> (),
> = unsafe { lib.get(format!("make_mize_part_{}", part_name).as_bytes())? };
let mut part: Box<dyn MizePart + Send + Sync> = 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<ItemData> {
let mut config = ItemData::new();
if let Some(config_file_path) = matches.get_one::<String>("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::<String>("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<ItemData> {
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<S, N> FormatEvent<S, N> 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::<FormattedFields<N>>()
.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();
}
}
}

View File

@@ -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<UnixListener> {
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<u64> {
let mut stream = UnixStream::connect(store_path.join("sock")).await?;
let (unix_read, unix_write) = stream.into_split();
let (send_tx, send_rx) = unbounded::<MizeMessage>();
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::<MizeMessage>();
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<MizeMessage>,
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(())
}
}

View File

@@ -1,239 +0,0 @@
static SERVER_PORT: u16 = 3000;
static API_ENDPOINT: &str = "@mize";
pub fn run() -> Result<Web, MizeError> {
/*
* - 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<String>, State(mutexes): State<Mutexes>) -> http::Response<String> {
// 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<proto::MizeMessage>, Receiver<proto::MizeMessage>) = 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;
},
};
};
}

View File

@@ -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
}