many changes

This commit is contained in:
Sebastian Moser
2025-01-16 18:43:44 +01:00
parent f985b18875
commit 99d270a26e
14 changed files with 355 additions and 183 deletions

View File

@@ -14,7 +14,7 @@ use interner::shared::{VecStringPool, StringPool};
use crate::error::{MizeError, MizeResult, IntoMizeResult, MizeResultTrait};
use crate::instance::store::Store;
use crate::instance::updater::updater_thread;
use crate::instance::updater::{ updater_thread, updater_thread_async };
use crate::id::{IntoMizeId, MizeId, Namespace};
use crate::instance::subscription::Subscription;
use crate::item::{Item, ItemData};
@@ -59,7 +59,7 @@ pub struct Instance {
connections: Arc<Mutex<Vec<Connection>>>,
next_con_id: Arc<Mutex<u64>>,
subs: Arc<Mutex<HashMap<MizeId, Vec<Subscription>>>>,
pub modules: Arc<Mutex<HashMap<String, Box<dyn Module + Sync + Send>>>>,
pub modules: Arc<Mutex<HashMap<String, Box<dyn Module + Sync + Send >>>>,
pub id_pool: Arc<Mutex<VecStringPool>>,
pub namespace_pool: Arc<Mutex<StringPool>>,
@@ -74,7 +74,7 @@ pub struct Instance {
next_thread_id: Arc<Mutex<u32>>,
give_msg_wait: Arc<Mutex<HashMap<MizeId, Vec<Sender<ItemData>>>>>,
create_msg_wait: Arc<Mutex<Option<Sender<MizeId>>>>,
update_thread_busy: Arc<Mutex<bool>>,
#[cfg(feature = "async")]
pub runtime: Arc<Mutex<Runtime>>,
}
@@ -113,7 +113,6 @@ impl Instance {
next_thread_id: Arc::new(Mutex::new(0)),
next_con_id: Arc::new(Mutex::new(1)),
give_msg_wait, create_msg_wait,
update_thread_busy: Arc::new(Mutex::new(false)),
#[cfg(feature = "async")]
runtime: Arc::new(Mutex::new(Runtime::new().mize_result_msg("Could not create async runtime")?)),
@@ -121,14 +120,29 @@ impl Instance {
let instance_clone = instance.clone();
let op_rx_clone = op_rx.clone();
let closure = move || updater_thread(op_rx_clone, &instance_clone);
instance.spawn("updater_thread", closure)?;
#[cfg(feature = "os-target")]
{
let instance_clone = instance.clone();
let op_rx_clone = op_rx.clone();
let closure = move || updater_thread(op_rx_clone, &instance_clone);
instance.spawn("updater_thread", closure)?;
let instance_clone_two = instance.clone();
let closure_two = move || updater_thread(op_rx, &instance_clone_two);
instance.spawn("updater_thread", closure_two)?;
let instance_clone_two = instance.clone();
let closure_two = move || updater_thread(op_rx, &instance_clone_two);
instance.spawn("updater_thread", closure_two)?;
}
// set up async update "threads" when using wasm
#[cfg(feature = "wasm-target")]
{
let instance_clone = instance.clone();
let op_rx_clone = op_rx.clone();
wasm_bindgen_futures::spawn_local(updater_thread_async(op_rx_clone, instance_clone));
let instance_clone_two = instance.clone();
wasm_bindgen_futures::spawn_local(updater_thread_async(op_rx, instance_clone_two));
}
// will move the msg stuff into it's own thread
// like this it can deadlock.... if a msg waits on an operation to complete
@@ -161,7 +175,7 @@ impl Instance {
return Ok(instance);
}
fn init(&mut self) -> MizeResult<()> {
pub fn init(&mut self) -> MizeResult<()> {
// platform specific init code
crate::platform::any::instance_init(self)?;
@@ -169,7 +183,18 @@ impl Instance {
// end of platform specific init code
self.load_module("String")?;
// load the modules, ad specified in the load_modules config
match self.get("0/config/load_modules")?.value_string() {
Ok(modules_to_load) => {
for module in modules_to_load.split(" ") {
self.load_module(module)?;
}
},
Err(err) => {
// no load_modules option is set
}
}
debug!("INSTANCE INIT DONE");
@@ -318,6 +343,14 @@ impl Instance {
crate::platform::any::load_module(self, name, Some(path))
}
pub fn get_module(&mut self, name: &str) -> MizeResult<Box<dyn Module + Send + Sync>> {
let inner = self.modules.lock()?;
let module = inner.get(name).ok_or(mize_err!("Couldn't get_module('{name}')"))?.clone_module();
Ok(module)
}
pub fn namespace_from_string(&self, ns_str: String) -> MizeResult<Namespace> {
let namespace_pool_inner = self.namespace_pool.lock()?;
let namespace = Namespace ( namespace_pool_inner.get(ns_str) );
@@ -539,16 +572,6 @@ impl Instance {
}
}
pub fn wait_for_updaater_thread(&self) -> MizeResult<()> {
thread::sleep_ms(10000000);
return Ok(());
while !self.op_tx.is_empty() {
thread::sleep_ms(50);
}
self.update_thread_busy.lock()?;
trace!("wait_for_updaater_thread Thread Idle");
Ok(())
}
pub fn report_error(err: MizeError) {
err.log();

View File

@@ -2,19 +2,32 @@
// https://users.rust-lang.org/t/casting-between-trait-object-types/97220/2
use std::ffi::OsString;
use crate::instance::Instance;
use crate::error::MizeResult;
pub trait Module {
pub trait Module: {
fn init(&mut self, instance: &Instance) -> MizeResult<()>;
fn exit(&mut self, instance: &Instance) -> MizeResult<()>;
fn clone_module(&self) -> Box<dyn Module + Send + Sync>;
// extra traits, that can be implemented
// return None if not implemented
fn run_cli(&mut self, instance: &Instance, cmd_line: Vec<OsString>) -> Option<MizeResult<()>> {
None
}
}
pub struct EmptyModule {
}
impl Module for EmptyModule {
fn init(&mut self, instance: &Instance) -> MizeResult<()> {
println!("empty module fn init");
@@ -25,5 +38,9 @@ impl Module for EmptyModule {
Ok(())
}
fn clone_module(&self) -> Box<dyn Module + Send + Sync> {
Box::new(EmptyModule { })
}
}

View File

@@ -19,6 +19,75 @@ pub enum Operation {
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: Instance) -> () {
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: &Instance) -> MizeResult<()> {
let mut count = 0;
@@ -31,8 +100,6 @@ pub fn updater_thread(operation_rx : Receiver<Operation>, instance: &Instance) -
trace!("OPERATION {} - {}", count, op_str);
//let mut busy = instance.update_thread_busy.lock()?;
let result = handle_operation(&mut operation, instance);
trace!("OPERATION {} DONE", count);
@@ -43,7 +110,6 @@ pub fn updater_thread(operation_rx : Receiver<Operation>, instance: &Instance) -
err.log();
}
//drop(busy);
}
Ok(())
}

View File

@@ -30,7 +30,7 @@ pub struct Item<'a> {
// 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)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ItemData ( pub CborValue );
impl Item<'_> {
@@ -162,6 +162,13 @@ impl ItemData {
return Ok(value.into_item_data());
}
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 from_string<S: Into<String>>(into_string: S) -> ItemData {
let string = into_string.into();
let data = CborValue::Text(string);
@@ -177,6 +184,15 @@ impl ItemData {
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)
.mize_result_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);
}
@@ -226,6 +242,41 @@ impl ItemData {
}
impl Default for ItemData {
fn default() -> Self {
ItemData::new()
}
}
pub fn data_from_string(data_string: String) -> MizeResult<ItemData> {
let mut config = 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(":") {
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 beforee =)", option)))?;
let value = option.split("=").nth(1)
.ok_or(MizeError::new().msg(format!("Failed to parse Option: option '{}' has an empty value (thing after =)", option)))?;
let mut path_vec = vec!["config"];
path_vec.extend(path.split("."));
config.set_path(path_vec, ItemData::parse(value))?;
}
return Ok(config);
}
pub fn item_data_get_path(data: &CborValue, path: Vec<String>) -> MizeResult<&CborValue> {
let mut path_iter = path.clone().into_iter();
//println!("data: {:?}", data);