module loading in wasm

This commit is contained in:
Sebastian Moser
2025-07-01 15:21:39 +02:00
parent f87b2270a5
commit 1ca2dcaf73
10 changed files with 253 additions and 67 deletions

View File

@@ -42,6 +42,26 @@ pub mod msg_thread;
pub mod module;
// 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(test)]
@@ -150,11 +170,16 @@ impl Instance {
//let msg_closure = move || msg_thread(op_rx, instance_clone);
//instance.spawn("msg_thread", closure)?;
#[cfg(feature = "wasm-target")]
console_log!("before loading build time config");
// load the config from build time
let config = ItemData::from_toml(BUILD_TIME_CONFIG)?;
instance.set_blocking("0", config);
#[cfg(feature = "wasm-target")]
console_log!("after loading build time config");
return Ok(instance);
}
@@ -187,6 +212,8 @@ impl Instance {
match self.get("0/config/load_modules")?.value_string() {
Ok(modules_to_load) => {
for module in modules_to_load.split(" ") {
#[cfg(feature = "wasm-target")]
console_log!("loading module in Instance::init() ... {}", module);
self.load_module(module)?;
}
},

View File

@@ -24,6 +24,26 @@ pub trait Module: {
}
// 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())})
}
pub struct EmptyModule {
}
@@ -31,6 +51,9 @@ pub struct EmptyModule {
impl Module for EmptyModule {
fn init(&mut self, instance: &Instance) -> MizeResult<()> {
println!("empty module fn init");
#[cfg(feature = "wasm-target")]
console_log!("empty module fn init");
Ok(())
}
fn exit(&mut self, instance: &Instance) -> MizeResult<()> {

View File

@@ -81,12 +81,14 @@ pub fn os_instance_init(instance: &mut Instance) -> MizeResult<()> {
},
Err(e) => {
// the default store_path: $HOME/.mize
let home_dir = env!("HOME");
if home_dir == "" {
return Err(mize_err!("env var $HOME empty"));
}
let home_dir = if let Some(dir) = std::env::home_dir() {
dir
} else {
return Err(mize_err!("could not get home_dir and store_path is not set in the config"));
};
let store_path = home_dir.to_owned() + "/.mize";
let store_path_buff = home_dir.join(".mize");
let store_path = store_path_buff.display().to_string();
instance.set_blocking("self/config/store_path", store_path.clone().into_item_data())?;

View File

@@ -1,6 +1,8 @@
use core::convert::From;
use core::option::Option;
use std::ptr::NonNull;
use std::panic;
use web_sys::js_sys::{self, eval};
use web_sys::js_sys::{self, eval, Promise};
use crate::id::MizeId;
use crate::item::{Item, ItemData};
use crate::platform::wasm::js_sys::Function;
@@ -12,6 +14,7 @@ use crate::error::MizeResult;
use crate::{mize_err, Module};
use crate::MizeError;
use crate::core::item::IntoItemData;
use crate::instance::module::EmptyModule;
@@ -45,9 +48,6 @@ macro_rules! console_log {
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
@@ -61,13 +61,132 @@ pub fn wasm_instance_init(instance: &mut Instance) -> MizeResult<()> {
pub fn load_module(instance: &mut Instance, name: &str, path: Option<String>) -> MizeResult<()> {
console_log!("loading module: {}", name);
let hi = 1;
let hi = 1;
let hi = 1;
wasm_bindgen_futures::spawn_local(load_module_async(instance.clone(), name.to_owned(), path));
Ok(())
}
async fn load_module_async(mut instance: Instance, name: String, path: Option<String>) -> () {
let name = name.as_str();
let module_url = fetch_module(&mut instance, name).unwrap();
let memory = wasm_bindgen::memory();
let mut empty_module: Box<dyn Module + Send + Sync> = Box::new(EmptyModule {});
let mut mize = instance.clone();
let empty_module_ptr = Box::into_raw(Box::new(empty_module));
let empty_module_usize = empty_module_ptr as usize;
let mize_usize = Box::into_raw(Box::new(mize)) as usize;
console_log!("testttttttttttttt in load_module_async...");
let function_str = format!(r#"
const promise = new Promise((resolve, reject) => {{
import("{module_url}/mize_module_{name}.js").then( module => {{
const wasm_bindgen = module.get_wasm_bindgen();
const {{ wasm_get_mize_module_mme }} = wasm_bindgen;
wasm_bindgen("{module_url}/mize_module_{name}_bg.wasm", memory).then( () => {{
console.log("empty_module_usize:", empty_module_usize)
console.log("mize_usize:", mize_usize)
//resolve()
resolve(wasm_get_mize_module_mme(empty_module_usize, mize_usize))
}})
}})
}})
return promise;
"#);
let function = Function::new_with_args("memory, empty_module_usize, mize_usize", &function_str);
let ret_value: JsValue = match function.call3(&JsValue::null(), &memory, &empty_module_usize.into(), &mize_usize.into()) {
Ok(val) => val,
Err(err) => {
console_log!("failed to load the wasm mize module....");
console_log!("{:?}", err);
return;
},
};
console_log!("got ret_value: {:?}", ret_value);
let ret_promise = Promise::from(ret_value);
let ret_result = match wasm_bindgen_futures::JsFuture::from(ret_promise).await {
Ok(val) => val,
Err(err) => {
console_log!("err awaiting ret_promise");
console_log!("{:?}", err);
return;
},
};
let mut filled_module = unsafe {
Box::from_raw(empty_module_ptr)
};
console_log!("before....");
let a = instance.get("0/config");
console_log!("after....");
//filled_module.init(&instance);
/*
console_log!("got ret_result: {:?}", ret_result);
let ret_f64 = ret_result.as_f64().unwrap();
console_log!("got ret_f64: {:?}", ret_f64);
let ret_usize = ret_f64.floor() as usize;
let mut module: Box<dyn Module + Send + Sync> = Box::new(EmptyModule {});
unsafe {
let get_mize_module_fn_ptr = ret_usize as *const fn(&mut Box<dyn Module + Send + Sync>, Instance) -> ();
let get_mize_module_fn: fn(&mut Box<dyn Module + Send + Sync>, Instance) -> () = unsafe { std::mem::transmute(get_mize_module_fn_ptr) };
get_mize_module_fn(&mut module, instance.clone());
}
*/
}
pub fn fetch_module(instance: &mut Instance, name: &str) -> MizeResult<String> {
let module_name_with_slashes = name.replace(".", "/");
if let Ok(module_path) = instance.get(format!("self/config/module_dir/{}", module_name_with_slashes))?.value_string() {
return Ok(module_path);
} else {
let module_url = instance.get("self/config/module_url")?.value_string()?;
return Ok(format!("{}/{}", module_url, module_name_with_slashes));
}
}
async fn download_module(instance: &mut Instance, name: &str) -> MizeResult<js_sys::ArrayBuffer> {
use wasm_bindgen_futures::JsFuture;
use web_sys::{Request, RequestInit, RequestMode, Response};
let opts = RequestInit::new();
opts.set_method("GET");
opts.set_mode(RequestMode::Cors);
let url = format!("{}/mize_module_{}_bg.wasm", fetch_module(instance, name)?, name);
let request = Request::new_with_str_and_init(&url, &opts).unwrap();
let window = web_sys::window().unwrap();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await.unwrap();
let resp: Response = resp_value.dyn_into().unwrap();
let wasm_bytes: js_sys::ArrayBuffer = JsFuture::from(resp.array_buffer().unwrap()).await.unwrap().dyn_into().unwrap();
Ok(wasm_bytes)
}
#[wasm_bindgen]
pub struct JsInstance {
inner: NonNull<Instance>,
@@ -82,7 +201,6 @@ pub struct JsItemHandle {
#[wasm_bindgen]
pub async fn new_js_instance(config_json_str: String) -> JsInstance {
console_log!("hooooooooooooooo");
panic::set_hook(Box::new(console_error_panic_hook::hook));
@@ -117,6 +235,15 @@ impl JsInstance {
let item = self.inner.as_mut().get(id)?;
Ok(JsItemHandle { instance: self.inner, id: item.id()})
}
}
impl JsInstance {
pub fn inner(&mut self) -> &mut Instance {
unsafe {
self.inner.as_mut()
}
}
}