From 5cfc9cfe7ccbb3ac6589477bf0f86ad38e596f04 Mon Sep 17 00:00:00 2001 From: Sebastian Moser Date: Thu, 29 Aug 2024 08:40:38 +0200 Subject: [PATCH] module loading works --- Cargo.lock | 11 +++++ Cargo.toml | 6 ++- build.rs | 26 +++++++++++ modules | 2 +- src/core/instance/mod.rs | 22 +++++++++- src/core/instance/module.rs | 23 ++++++++++ src/lib.rs | 21 ++++++++- src/platform/os/mod.rs | 82 ++++++++++++++++++++++++++++++----- test-config.toml | 2 +- types/mize/instance/item.json | 7 --- 10 files changed, 177 insertions(+), 25 deletions(-) create mode 100644 build.rs delete mode 100644 types/mize/instance/item.json diff --git a/Cargo.lock b/Cargo.lock index 8de0a3d..e458215 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1116,6 +1116,16 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if 1.0.0", + "windows-targets 0.52.5", +] + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -1268,6 +1278,7 @@ dependencies = [ "dyn-clone", "home", "interner", + "libloading", "nix", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 56ac8cc..00c1935 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ path = "src/platform/os/main.rs" required-features = [ "os-target" ] [features] -os-target = [ "clap", "home", "daemonize", "nix", "toml", "sysinfo", "ciborium/default", "tracing-subscriber", "async", "tracing-subscriber/env-filter"] +os-target = [ "clap", "home", "daemonize", "nix", "toml", "sysinfo", "ciborium/default", "tracing-subscriber", "async", "tracing-subscriber/env-filter", "libloading" ] wasm-target = [ "wasm-bindgen", "console_error_panic_hook", "wasm-bindgen-cli" ] async = ["tokio/net", "tokio", "tokio/rt-multi-thread", "tokio/io-util"] @@ -33,6 +33,9 @@ tracing = "0.1.40" serde_json = { version = "1.0.117", optional = false } crossbeam = "0.8.4" +# buildin modules +#mize_module_blob = { path = "./modules/modules/Blob" } + # wasm dependencies wasm-bindgen = { version = "0.2.84", optional = true } console_error_panic_hook = { version = "0.1.7", optional = true } @@ -47,6 +50,7 @@ toml = { version = "0.8.13", features = ["parse"], optional = true } sysinfo = { version = "0.30.12", optional = true } tracing-subscriber = { version = "0.3.18", optional = true } tokio = { version = "1.21.0", features = ["sync"], optional = true } +libloading = { version = "0.8.5", optional = true } # bare dependencies diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..624b0b2 --- /dev/null +++ b/build.rs @@ -0,0 +1,26 @@ +use std::process::Command; +use std::env; + +fn main() { + + // compile the string plugin + //let _out_dir = env::var_os("OUT_DIR").unwrap(); + //let mut string_module = Command::new("bash"); + //string_module.arg("-c"); + //string_module.arg("echo hiiiiiiiiiiiiiiiii"); + //string_module.arg("--help"); + //string_module.arg("--out-dir"); + //string_module.arg(out_dir); + //string_module.env("PWD", "/hoem/me/work/mize/module/modules/Blob"); + + //let _res = string_module.spawn(); + //let _child = Command::new("cargo") + //.arg("build") + //.arg("--lib") + //.arg("--manifest-path") + //.arg("/home/me/work/mize/modules/modules/Blob/Cargo.toml") + //.spawn() + //.expect("failed to start wasm build"); + + //to outdir (), using the nightly feature --out-dir to have the result there. By default I get a libhearts.rlib +} diff --git a/modules b/modules index b670350..a605c0e 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit b670350309b5bfedb6850916117215e6cbe4c40d +Subproject commit a605c0efb12529c7aa46a098b95138c924731128 diff --git a/src/core/instance/mod.rs b/src/core/instance/mod.rs index f294b89..3eb51e8 100644 --- a/src/core/instance/mod.rs +++ b/src/core/instance/mod.rs @@ -20,7 +20,7 @@ use crate::instance::subscription::Subscription; use crate::item::{Item, ItemData}; use crate::memstore::MemStore; use crate::instance::updater::Operation; -use crate::mize_err; +use crate::{mize_err, Module}; use crate::proto::MizeMessage; use self::connection::{ConnListener, Connection}; @@ -51,6 +51,7 @@ pub struct Instance { connections: Arc>>, next_con_id: Arc>, subs: Arc>>>, + pub modules: Arc>>>, pub id_pool: Arc>, pub namespace_pool: Arc>, @@ -96,6 +97,7 @@ impl Instance { connections, subs, id_pool, namespace, self_namespace, op_tx, namespace_pool: Arc::new(Mutex::new(namespace_pool_raw)), + modules: Arc::new(Mutex::new(HashMap::new())), context: vec![], threads: vec![], next_con_id: Arc::new(Mutex::new(1)), @@ -115,7 +117,8 @@ impl Instance { let closure_two = move || updater_thread(op_rx, &instance_clone_two); instance.spawn("updater_thread", closure_two)?; - // will probably move the msg stuff into it's own thread + // will move the msg stuff into it's own thread + // like this it can deadlock.... if a msg waits on an operation to complete //let msg_instance_clone = instance.clone(); //let msg_closure = move || msg_thread(op_rx, instance_clone); //instance.spawn("msg_thread", closure)?; @@ -142,6 +145,16 @@ impl Instance { crate::platform::any::instance_init(self); // end of platform specific init code + self.load_module("Blob")?; + + let mut modules_inner = self.modules.lock()?; + + let module = modules_inner.get_mut("Blob").unwrap(); + + println!("right before segfault"); + module.init(&self); + + //self.load_module("String")?; debug!("INSTANCE INIT DONE"); Ok(()) @@ -275,6 +288,11 @@ impl Instance { Ok(id) } + pub fn load_module(&mut self, name: &str) -> MizeResult<()> { + // platform specific init code + crate::platform::any::load_module(self, name) + } + pub fn namespace_from_string(&self, ns_str: String) -> MizeResult { let namespace_pool_inner = self.namespace_pool.lock()?; let namespace = Namespace ( namespace_pool_inner.get(ns_str) ); diff --git a/src/core/instance/module.rs b/src/core/instance/module.rs index 6830ff0..e96e86a 100644 --- a/src/core/instance/module.rs +++ b/src/core/instance/module.rs @@ -2,5 +2,28 @@ // https://users.rust-lang.org/t/casting-between-trait-object-types/97220/2 +use crate::instance::Instance; +use crate::error::MizeResult; + pub trait Module { + fn init(&mut self, instance: &Instance) -> MizeResult<()>; + + fn exit(&mut self, instance: &Instance) -> MizeResult<()>; } + + +pub struct EmptyModule { +} + +impl Module for EmptyModule { + fn init(&mut self, instance: &Instance) -> MizeResult<()> { + println!("empty module fn init"); + Ok(()) + } + fn exit(&mut self, instance: &Instance) -> MizeResult<()> { + println!("empty module fn exit"); + Ok(()) + + } +} + diff --git a/src/lib.rs b/src/lib.rs index 73ae77d..915d7dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,10 @@ mod core { } pub use core::*; - +pub use core::instance::module::Module; +pub use core::instance::Instance; +pub use core::error::MizeError; +pub use core::error::MizeResult; // platform specific stuff pub mod platform { @@ -31,8 +34,24 @@ pub mod platform { #[cfg(feature = "os-target")] pub use super::os::os_instance_init as instance_init; + + #[cfg(not(any(feature = "os-target", feature = "wasm-target")))] + pub use super::super::instance_init; + + + #[cfg(feature = "os-target")] + pub use super::os::load_module; + + #[cfg(not(any(feature = "os-target", feature = "wasm-target")))] + pub use super::super::load_module; + } } +pub fn instance_init(instance: &mut core::instance::Instance) {} + + +pub fn load_module(instance: &mut core::instance::Instance, name: &str) -> MizeResult<()> { Ok(()) } + diff --git a/src/platform/os/mod.rs b/src/platform/os/mod.rs index 309a8f9..e95828a 100644 --- a/src/platform/os/mod.rs +++ b/src/platform/os/mod.rs @@ -5,6 +5,7 @@ use std::fs; use tracing::{debug, error, info, trace, warn}; use clap::ArgMatches; use std::path::Path; +use std::time::UNIX_EPOCH; use crate::id::MizeId; use crate::instance::store::Store; @@ -12,8 +13,9 @@ use crate::instance::Instance; use crate::error::{IntoMizeResult, MizeError, MizeResult}; use crate::item::{ItemData, IntoItemData}; use crate::memstore::MemStore; -use crate::mize_err; +use crate::{mize_err, Module}; use crate::platform::os::unix_socket::UnixListener; +use crate::instance::module::EmptyModule; use self::fsstore::FileStore; @@ -63,17 +65,17 @@ pub fn os_instance_init(instance: &mut Instance) -> MizeResult<()> { ////// if a config.store_path is set, upgrade to the filestore there let mut test = instance.get("0")?.as_data_full()?; - let mut store_path = instance.get("0/config/store_path")?.value_string()?; - - if store_path == "" { - let home_dir = env!("HOME"); - if home_dir == "" { - return Err(mize_err!("env var $HOME empty")); - } - - // the default store_path: $HOME/.mize - store_path = home_dir.to_owned() + "/.mize"; - } + let mut store_path = match instance.get("0/config/store_path")?.value_string() { + Ok(path) => path, + Err(e) => { + // the default store_path: $HOME/.mize + let home_dir = env!("HOME"); + if home_dir == "" { + return Err(mize_err!("env var $HOME empty")); + } + home_dir.to_owned() + "/.mize" + }, + }; if FileStore::store_is_opened(store_path.to_owned())? { // if the store is already opened, connect to the instance, that opened it and join @@ -94,6 +96,62 @@ pub fn os_instance_init(instance: &mut Instance) -> MizeResult<()> { Ok(()) } +pub fn seconds_since_modification(path: &Path) -> u64 { + let metadata = match fs::metadata(path) { + Err(_) => { return u64::MAX; }, // we are the older file, if it fails + Ok(data) => data, + }; + + let modified = match metadata.modified() { + Err(_) => { return u64::MAX; }, // we are the older file, if it fails + Ok(data) => data, + }; + + let duration = match modified.duration_since(UNIX_EPOCH) { + Err(_) => { return u64::MAX; }, // we are the older file, if it fails + Ok(data) => data, + }; + + duration.as_secs() +} + +pub fn load_module(instance: &mut Instance, name: &str) -> MizeResult<()> { + + let module_dir_str = instance.get("0/config/module_dir")?.value_string()?; + let module_dir = Path::new(&module_dir_str); + + let release_path = module_dir.join("modules").join(name).join("target").join("release").join(format!("libmize_module_{}.so", name)); + let debug_path = module_dir.join("modules").join(name).join("target").join("debug").join(format!("libmize_module_{}.so", name)); + + let module_path = match seconds_since_modification(&release_path) > seconds_since_modification(&debug_path) { + true => debug_path, + false => release_path, + }; + + let lib = unsafe { libloading::Library::new(module_path)? }; + + let func: libloading::Symbol) -> ()> = unsafe { lib.get(format!("get_mize_module_{}", name).as_bytes())? }; + + let mut module: Box = Box::new(EmptyModule {}); + + unsafe { func(&mut module) }; + + + let mut modules_inner = instance.modules.lock()?; + + module.init(&instance); + + modules_inner.insert(name.to_owned(), module); + + unsafe { + // dropping the lib, would (i suspect) free all memory, of the library's code, which would + // make the module's vtable point into empty memory + std::mem::forget(lib); + } + + Ok(()) +} + pub fn config_from_cli_args(matches: &ArgMatches) -> MizeResult { let mut config = ItemData::new(); diff --git a/test-config.toml b/test-config.toml index ce842ab..f1f4918 100644 --- a/test-config.toml +++ b/test-config.toml @@ -1,5 +1,5 @@ [config] namespace = "test.c2vi.dev" +module_dir = "/home/me/work/mize/modules" test = "hello from test item" -store_path = "/home/me/.mize" diff --git a/types/mize/instance/item.json b/types/mize/instance/item.json deleted file mode 100644 index 9ebb0f1..0000000 --- a/types/mize/instance/item.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "instance", - "paths": [ - [["daemon", "pid"], "int"], - [["daemon", "log", "blob"]] - ] -}