recent mize changes
This commit is contained in:
49
src/core/config.rs
Normal file
49
src/core/config.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
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(())
|
||||
}
|
||||
367
src/core/error.rs
Normal file
367
src/core/error.rs
Normal file
@@ -0,0 +1,367 @@
|
||||
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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
199
src/core/id.rs
Normal file
199
src/core/id.rs
Normal file
@@ -0,0 +1,199 @@
|
||||
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(())
|
||||
}
|
||||
}
|
||||
57
src/core/instance/connection.rs
Normal file
57
src/core/instance/connection.rs
Normal file
@@ -0,0 +1,57 @@
|
||||
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);
|
||||
}
|
||||
1068
src/core/instance/mod.rs
Normal file
1068
src/core/instance/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
2
src/core/instance/msg_thread.rs
Normal file
2
src/core/instance/msg_thread.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
|
||||
71
src/core/instance/store.rs
Normal file
71
src/core/instance/store.rs
Normal file
@@ -0,0 +1,71 @@
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
68
src/core/instance/subscription.rs
Normal file
68
src/core/instance/subscription.rs
Normal file
@@ -0,0 +1,68 @@
|
||||
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...")
|
||||
}
|
||||
}
|
||||
263
src/core/instance/tests.rs
Normal file
263
src/core/instance/tests.rs
Normal file
@@ -0,0 +1,263 @@
|
||||
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");
|
||||
}
|
||||
*/
|
||||
236
src/core/instance/updater.rs
Normal file
236
src/core/instance/updater.rs
Normal file
@@ -0,0 +1,236 @@
|
||||
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(())
|
||||
}
|
||||
818
src/core/item.rs
Normal file
818
src/core/item.rs
Normal file
@@ -0,0 +1,818 @@
|
||||
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(())
|
||||
}
|
||||
3
src/core/lib.rs
Normal file
3
src/core/lib.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
#![ allow( warnings ) ]
|
||||
|
||||
31
src/core/macros.rs
Normal file
31
src/core/macros.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
// 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();
|
||||
};
|
||||
}
|
||||
152
src/core/memstore.rs
Normal file
152
src/core/memstore.rs
Normal file
@@ -0,0 +1,152 @@
|
||||
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
|
||||
))
|
||||
}
|
||||
434
src/core/proto/mod.rs
Normal file
434
src/core/proto/mod.rs
Normal file
@@ -0,0 +1,434 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
0
src/core/types/mod.rs
Normal file
0
src/core/types/mod.rs
Normal file
Reference in New Issue
Block a user