Stream: git-wasmtime

Topic: wasmtime / issue #8670 wasm trap: cannot enter component ...


view this post on Zulip Wasmtime GitHub notifications bot (May 21 2024 at 06:58):

redoC-A2k opened issue #8670:

hey there how can I sort of clone a wasm in execution the issue is I call the one of the imported function (1st function) from guest on host ( wasm is in execution as of now)
Now that imported function from guest to wasm calls another function which is exported by host to guest but this function ( exported function on host) again needs to call different (let's call it 2nd function) imported function from guest and this is the issue .
During this whole process wasm is in execution and how can I call the 2nd function ?

I tried storing reactor(component) and store in static variable , reactor works fine as it only requires reference while function calling but issue is in case of store while calling imported function I need to provide mutable reference to store . Which I can't as at a time I can't have two mutable reference . For sharing mutable reference - I created a static option containing Store and passed the mutable reference to function like so

let result: Result<http_types::Response, anyhow::Error> =
                guest.call_handle_request(&mut *store, &request).await; (1st function) (in main function where I instantiate component)
let result = guest.call_jsonnet_call_native_func(&mut *store, &self.0, "")
                        .await (2nd function) (in some other exported function which component calls as a result of calling above imported function)

But in above case I am getting error
wasm trap: cannot enter component instance

I tried creating new store but then I get some different error , if I use that store with reference of Reactor .

Please help me , I don't want to use core wasm modules . Nor I think I will be able to break the wasm module in two components (as I my wasm module is basically quickjs runtime along with js code the wasm is generated by cargo building to target wasm32-wasi the quickjs_wasm_rs context (javy approach) .

view this post on Zulip Wasmtime GitHub notifications bot (May 21 2024 at 06:58):

redoC-A2k commented on issue #8670:

If needed I can provide more detail

view this post on Zulip Wasmtime GitHub notifications bot (May 21 2024 at 07:05):

redoC-A2k edited issue #8670:

hey there how can I sort of clone a wasm in execution the issue is I call the one of the imported function (1st function) from guest on host ( wasm is in execution as of now)
Now that imported function from guest to wasm calls another function which is exported by host to guest but this function ( exported function on host) again needs to call different (let's call it 2nd function) imported function from guest and this is the issue .
During this whole process wasm is in execution and how can I call the 2nd function ?

I tried storing reactor(component) and store in static variable , reactor works fine as it only requires reference while function calling but issue is in case of store while calling imported function I need to provide mutable reference to store . Which I can't as at a time I can't have two mutable reference . For sharing mutable reference - I created a static option containing Store and passed the mutable reference to function like so

let result: Result<http_types::Response, anyhow::Error> =
                guest.call_handle_request(&mut *store, &request).await; (1st function) (in main function where I instantiate component)
let result = guest.call_jsonnet_call_native_func(&mut *store, &self.0, "")
                        .await (2nd function) (in some other exported function which component calls as a result of calling above imported function)

But in above case I am getting error
wasm trap: cannot enter component instance

I tried creating new store but then I get some different error , if I use that store with reference of Reactor .

Please help me , I don't want to use core wasm modules . Nor I think I will be able to break the wasm module in two components (as I my wasm module is basically quickjs runtime along with js code the wasm is generated by cargo building to target wasm32-wasi the quickjs_wasm_rs context (javy approach, fermyon spin approach) .

view this post on Zulip Wasmtime GitHub notifications bot (May 21 2024 at 14:51):

alexcrichton commented on issue #8670:

Thanks for the report! What you're running into here is the relatively strict rules around reentrance in the component model. Currently once a component calls an import, provided by the host, the host can't reenter the component until the import has finished. This means that your use case as-is isn't supported with the component model (at least given my understanding). In the Canonical ABI document this corresponds to the may_enter boolean.

Could you describe a bit more what you're trying to achieve at a higher level though? There might be an alternative solution to you perhaps.

view this post on Zulip Wasmtime GitHub notifications bot (May 22 2024 at 13:58):

redoC-A2k commented on issue #8670:

Sure , I will be extermely thankful if you can help in achieving my use-case
So basically ( start reading from 4th point ... points above it describes just how we do guest host communication) -
In the lib.rs at host side (my host is a hyper server which instantiate guest component and pass the serialized request it)

  1. I define two static variables -
pub static mut REACTOR: Option<Arc<wit::Reactor>> = None;
// pub static mut STORE: Option<Mutex<Store<Host>>> = None;
pub static mut STORE: Option<Store<Host>> = None;
  1. For a request this run function is called -
    async fn run(&self, parts: &Parts, body: String) -> anyhow::Result<WasmOutput> {

        let mut linker = Linker::new(self.engine());
        // wasmtime_wasi::add_to_linker(&mut linker, |ctx| ctx)?;
        bindings::cli::environment::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add environment");
        bindings::cli::exit::add_to_linker(&mut linker, |x| x).expect("Unable to add cli");
        bindings::io::error::add_to_linker(&mut linker, |x| x).expect("Unable to add io error");
        // bindings::sync::io::streams::add_to_linker(&mut linker, |x| x)
        //     .expect("Unable to add io streams");
        bindings::io::streams::add_to_linker(&mut linker, |x| x).expect("Unable to add io streams");
        bindings::cli::stdin::add_to_linker(&mut linker, |x| x).expect("Unable to add cli stdin");
        bindings::cli::stdout::add_to_linker(&mut linker, |x| x).expect("Unable to add cli stdout");
        bindings::cli::stderr::add_to_linker(&mut linker, |x| x).expect("Unable to add cli stderr");
        bindings::cli::terminal_input::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add cli terminal input");
        bindings::cli::terminal_output::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add cli terminal output");
        bindings::cli::terminal_stdin::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add cli terminal stdin");
        bindings::cli::terminal_stdout::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add cli terminal stdout");
        bindings::cli::terminal_stderr::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add cli terminal stderr");
        bindings::clocks::monotonic_clock::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add clocks monotonic clock");
        bindings::clocks::wall_clock::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add clocks wallclock");
        // bindings::sync::filesystem::types::add_to_linker(&mut linker, |x| x)
        //     .expect("Unable to add filesystem types");
        bindings::filesystem::types::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add filesystem types");
        bindings::filesystem::preopens::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add filesystem preopens");
        bindings::random::random::add_to_linker(&mut linker, |x| x).expect("Unable to add random");

        let wasi = WasiCtxBuilder::new()
            .inherit_stdout()
            .inherit_stderr()
            .build();

        let table: ResourceTable = ResourceTable::new();

        // Create a new store with the WASI context.
        let mut store = Store::new(
            self.engine(),
            Host {
                table,
                wasi,
                client: None,
            },
        );

        unsafe {
            STORE.replace(store);
        }

        let wasm_input = WasmInput::new(parts, body);
        let request = inbound_http::Request {
            method: match wasm_input.method {
                io::Method::GET => http_types::Method::Get,
                io::Method::POST => http_types::Method::Post,
                io::Method::PUT => http_types::Method::Put,
                io::Method::DELETE => http_types::Method::Delete,
                io::Method::PATCH => http_types::Method::Patch,
                io::Method::HEAD => http_types::Method::Head,
                io::Method::OPTIONS => http_types::Method::Options,
            },
            uri: wasm_input.uri,
            headers: wasm_input.headers,
            params: wasm_input.params,
            body: wasm_input.body,
        };

        wit::Reactor::add_to_linker(&mut linker, |x| x)?;
        debug!("Instantiated component");
        unsafe {

            let store = STORE.as_mut().unwrap();
            let (reactor, instance) =
                wit::Reactor::instantiate_async(&mut *store, self.component(), &linker).await?;

            REACTOR.replace(Arc::new(reactor));
            let reactor = REACTOR.clone().unwrap();
            let guest = reactor.arakoo_edgechains_inbound_http();
            let result: Result<http_types::Response, anyhow::Error> =
                guest.call_handle_request(&mut *store, &request).await;
            debug!("Calling guest handle completed");
            let mut wasm_output = WasmOutput::new();
            // println!("Result of guest calling: {:?}", &result);
            match result {
                Ok(res) => {
                    wasm_output.status = res.status;
                    wasm_output.status_text = res.status_text;
                    let mut headers_map = HashMap::new();
                    for (key, val) in res.headers.unwrap().iter() {
                        headers_map.insert(key.to_owned(), val.to_owned());
                    }
                    wasm_output.headers = headers_map;
                    let body_vec = res.body.unwrap();
                    if body_vec.len() > 0 {
                        wasm_output.body = Some(String::from_utf8(body_vec).unwrap());
                    }
                }
                Err(err) => println!("Error occured : {:?}", err),
            };


            Ok(wasm_output)
        }
    }
  1. The guest wasm is basically the embedded qjs runtime and js code
    handle_request function

fn handle_request(req: wit::Request) -> wit::Response {
        // TODO: log on env variable basis
        // println!("{:?}", req);
        let context = **CONTEXT.get().unwrap();
        let mut serializer =
            javy::quickjs::Serializer::from_context(context).expect("Unable to create serializer");
        let handler = **HANDLER.get().unwrap();
        let request = HttpRequest {
            method: match req.method {
                wit::Method::Get => "GET".to_string(),
                wit::Method::Post => "POST".to_string(),
                wit::Method::Put => "PUT".to_string(),
                wit::Method::Delete => "DELETE".to_string(),
                wit::Method::Patch => "PATCH".to_string(),
                wit::Method::Head => "HEAD".to_string(),
                wit::Method::Options => "OPTIONS".to_string(),
            },
            uri: req.uri,
            headers: req
                .headers
                .iter()
                .map(|(k, v)| Ok((k.as_str().to_owned(), v.as_str().to_owned())))
                .collect::<Result<HashMap<String, String>>>()
                .unwrap(),
            params: req
                .params
                .iter()
                .map(|(k, v)| Ok((k.as_str().to_owned(), v.as_str().to_owned())))
                .collect::<Result<HashMap<String, String>>>()
                .unwrap(),
            body: req.body.map(|bytes| ByteBuf::from::<Vec<u8>>(bytes)),
        };
        // let hono_event =
        // hono_event.serialize(&mut serializer).unwrap();
        request
            .serialize(&mut serializer)
            .expect("unable to serialize httprequest");
        let request_value = serializer.value;
        // println!("body of httpRequest : {:?}", from_qjs_value(request_value).unwrap());
        let global = GLOBAL.get().unwrap();
        let request_to_event = global
            .get_property("requestToEvent")
            .expect("Unable to get requestToEvent");
        let event = request_to_event
            .call(global, &[request_value])
            .expect("Unable to call requestToEvent");
        let event_request = event
            .get_property("request")
            .expect("Unable to get request from event");
        let promise = handler
            .call(global, &[event_request, event])
            .expect("Unable to call handler");

        let on_resolve = ON_RESOLVE.get().unwrap().clone();
        let on_reject = ON_REJECT.get().unwrap().clone();
        let then_func = promise.get_property("then").unwrap();
        if then_func.is_function() {
            then_func
                .call(
                    &promise,
                    &[on_resolve.deref().clone(), on_reject.deref().clone()],
                )
                .unwrap();
        } else {
            RESPONSE
                .lock()
                .unwrap()
                .replace(from_qjs_value(promise).unwrap());
        }

        context
            .execute_pending()
            .expect("Unable to execute pending tasks");

        // let response = to_qjs_value(context, &RESPONSE.lock().unwrap().take().unwrap()).unwrap();
        let response = RESPONSE.lock().unwrap().take().unwrap();

        // let deserializer = &mut Deserializer::from(response);
        // let response = HttpResponse::deserialize(deserializer).unwrap();
        // println!("Http Response {:?}", response);
        if let JSValue::Object(obj) = response {
            let status_code_ref = to_qjs_value(context, obj.get("status").unwrap()).unwrap();
            let status_code = status
[message truncated]

view this post on Zulip Wasmtime GitHub notifications bot (May 22 2024 at 14:03):

redoC-A2k edited a comment on issue #8670:

Sure , I will be extermely thankful if you can help in achieving my use-case
So basically ( start reading from 4th point ... points above it describes just how we do guest host communication) -
In the lib.rs at host side (my host is a hyper server which instantiate guest component and pass the serialized request it)

  1. I define two static variables -
pub static mut REACTOR: Option<Arc<wit::Reactor>> = None;
// pub static mut STORE: Option<Mutex<Store<Host>>> = None;
pub static mut STORE: Option<Store<Host>> = None;
  1. For a request this run function is called -
    async fn run(&self, parts: &Parts, body: String) -> anyhow::Result<WasmOutput> {

        let mut linker = Linker::new(self.engine());
        // wasmtime_wasi::add_to_linker(&mut linker, |ctx| ctx)?;
        bindings::cli::environment::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add environment");
        bindings::cli::exit::add_to_linker(&mut linker, |x| x).expect("Unable to add cli");
        bindings::io::error::add_to_linker(&mut linker, |x| x).expect("Unable to add io error");
        // bindings::sync::io::streams::add_to_linker(&mut linker, |x| x)
        //     .expect("Unable to add io streams");
        bindings::io::streams::add_to_linker(&mut linker, |x| x).expect("Unable to add io streams");
        bindings::cli::stdin::add_to_linker(&mut linker, |x| x).expect("Unable to add cli stdin");
        bindings::cli::stdout::add_to_linker(&mut linker, |x| x).expect("Unable to add cli stdout");
        bindings::cli::stderr::add_to_linker(&mut linker, |x| x).expect("Unable to add cli stderr");
        bindings::cli::terminal_input::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add cli terminal input");
        bindings::cli::terminal_output::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add cli terminal output");
        bindings::cli::terminal_stdin::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add cli terminal stdin");
        bindings::cli::terminal_stdout::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add cli terminal stdout");
        bindings::cli::terminal_stderr::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add cli terminal stderr");
        bindings::clocks::monotonic_clock::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add clocks monotonic clock");
        bindings::clocks::wall_clock::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add clocks wallclock");
        // bindings::sync::filesystem::types::add_to_linker(&mut linker, |x| x)
        //     .expect("Unable to add filesystem types");
        bindings::filesystem::types::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add filesystem types");
        bindings::filesystem::preopens::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add filesystem preopens");
        bindings::random::random::add_to_linker(&mut linker, |x| x).expect("Unable to add random");

        let wasi = WasiCtxBuilder::new()
            .inherit_stdout()
            .inherit_stderr()
            .build();

        let table: ResourceTable = ResourceTable::new();

        // Create a new store with the WASI context.
        let mut store = Store::new(
            self.engine(),
            Host {
                table,
                wasi,
                client: None,
            },
        );

        unsafe {
            STORE.replace(store);
        }

        let wasm_input = WasmInput::new(parts, body);
        let request = inbound_http::Request {
            method: match wasm_input.method {
                io::Method::GET => http_types::Method::Get,
                io::Method::POST => http_types::Method::Post,
                io::Method::PUT => http_types::Method::Put,
                io::Method::DELETE => http_types::Method::Delete,
                io::Method::PATCH => http_types::Method::Patch,
                io::Method::HEAD => http_types::Method::Head,
                io::Method::OPTIONS => http_types::Method::Options,
            },
            uri: wasm_input.uri,
            headers: wasm_input.headers,
            params: wasm_input.params,
            body: wasm_input.body,
        };

        wit::Reactor::add_to_linker(&mut linker, |x| x)?;
        debug!("Instantiated component");
        unsafe {

            let store = STORE.as_mut().unwrap();
            let (reactor, instance) =
                wit::Reactor::instantiate_async(&mut *store, self.component(), &linker).await?;

            REACTOR.replace(Arc::new(reactor));
            let reactor = REACTOR.clone().unwrap();
            let guest = reactor.arakoo_edgechains_inbound_http();
            let result: Result<http_types::Response, anyhow::Error> =
                guest.call_handle_request(&mut *store, &request).await;
            debug!("Calling guest handle completed");
            let mut wasm_output = WasmOutput::new();
            // println!("Result of guest calling: {:?}", &result);
            match result {
                Ok(res) => {
                    wasm_output.status = res.status;
                    wasm_output.status_text = res.status_text;
                    let mut headers_map = HashMap::new();
                    for (key, val) in res.headers.unwrap().iter() {
                        headers_map.insert(key.to_owned(), val.to_owned());
                    }
                    wasm_output.headers = headers_map;
                    let body_vec = res.body.unwrap();
                    if body_vec.len() > 0 {
                        wasm_output.body = Some(String::from_utf8(body_vec).unwrap());
                    }
                }
                Err(err) => println!("Error occured : {:?}", err),
            };


            Ok(wasm_output)
        }
    }
  1. The guest wasm is basically the embedded qjs runtime and js code
    handle_request function

fn handle_request(req: wit::Request) -> wit::Response {
        // TODO: log on env variable basis
        // println!("{:?}", req);
        let context = **CONTEXT.get().unwrap();
        let mut serializer =
            javy::quickjs::Serializer::from_context(context).expect("Unable to create serializer");
        let handler = **HANDLER.get().unwrap();
        let request = HttpRequest {
            method: match req.method {
                wit::Method::Get => "GET".to_string(),
                wit::Method::Post => "POST".to_string(),
                wit::Method::Put => "PUT".to_string(),
                wit::Method::Delete => "DELETE".to_string(),
                wit::Method::Patch => "PATCH".to_string(),
                wit::Method::Head => "HEAD".to_string(),
                wit::Method::Options => "OPTIONS".to_string(),
            },
            uri: req.uri,
            headers: req
                .headers
                .iter()
                .map(|(k, v)| Ok((k.as_str().to_owned(), v.as_str().to_owned())))
                .collect::<Result<HashMap<String, String>>>()
                .unwrap(),
            params: req
                .params
                .iter()
                .map(|(k, v)| Ok((k.as_str().to_owned(), v.as_str().to_owned())))
                .collect::<Result<HashMap<String, String>>>()
                .unwrap(),
            body: req.body.map(|bytes| ByteBuf::from::<Vec<u8>>(bytes)),
        };
        // let hono_event =
        // hono_event.serialize(&mut serializer).unwrap();
        request
            .serialize(&mut serializer)
            .expect("unable to serialize httprequest");
        let request_value = serializer.value;
        // println!("body of httpRequest : {:?}", from_qjs_value(request_value).unwrap());
        let global = GLOBAL.get().unwrap();
        let request_to_event = global
            .get_property("requestToEvent")
            .expect("Unable to get requestToEvent");
        let event = request_to_event
            .call(global, &[request_value])
            .expect("Unable to call requestToEvent");
        let event_request = event
            .get_property("request")
            .expect("Unable to get request from event");
        let promise = handler
            .call(global, &[event_request, event])
            .expect("Unable to call handler");

        let on_resolve = ON_RESOLVE.get().unwrap().clone();
        let on_reject = ON_REJECT.get().unwrap().clone();
        let then_func = promise.get_property("then").unwrap();
        if then_func.is_function() {
            then_func
                .call(
                    &promise,
                    &[on_resolve.deref().clone(), on_reject.deref().clone()],
                )
                .unwrap();
        } else {
            RESPONSE
                .lock()
                .unwrap()
                .replace(from_qjs_value(promise).unwrap());
        }

        context
            .execute_pending()
            .expect("Unable to execute pending tasks");

        // let response = to_qjs_value(context, &RESPONSE.lock().unwrap().take().unwrap()).unwrap();
        let response = RESPONSE.lock().unwrap().take().unwrap();

        // let deserializer = &mut Deserializer::from(response);
        // let response = HttpResponse::deserialize(deserializer).unwrap();
        // println!("Http Response {:?}", response);
        if let JSValue::Object(obj) = response {
            let status_code_ref = to_qjs_value(context, obj.get("status").unwrap()).unwrap();
            let status_co
[message truncated]

view this post on Zulip Wasmtime GitHub notifications bot (May 22 2024 at 14:45):

redoC-A2k edited a comment on issue #8670:

Sure , I will be extermely thankful if you can help in achieving my use-case
So basically ( start reading from 4th point ... points above it describes just how we do guest host communication) -
In the lib.rs at host side (my host is a hyper server which instantiate guest component and pass the serialized request it)

  1. I define two static variables -
pub static mut REACTOR: Option<Arc<wit::Reactor>> = None;
// pub static mut STORE: Option<Mutex<Store<Host>>> = None;
pub static mut STORE: Option<Store<Host>> = None;
  1. For a request this run function is called -
    async fn run(&self, parts: &Parts, body: String) -> anyhow::Result<WasmOutput> {

        let mut linker = Linker::new(self.engine());
        // wasmtime_wasi::add_to_linker(&mut linker, |ctx| ctx)?;
        bindings::cli::environment::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add environment");
        bindings::cli::exit::add_to_linker(&mut linker, |x| x).expect("Unable to add cli");
        bindings::io::error::add_to_linker(&mut linker, |x| x).expect("Unable to add io error");
        // bindings::sync::io::streams::add_to_linker(&mut linker, |x| x)
        //     .expect("Unable to add io streams");
        bindings::io::streams::add_to_linker(&mut linker, |x| x).expect("Unable to add io streams");
        bindings::cli::stdin::add_to_linker(&mut linker, |x| x).expect("Unable to add cli stdin");
        bindings::cli::stdout::add_to_linker(&mut linker, |x| x).expect("Unable to add cli stdout");
        bindings::cli::stderr::add_to_linker(&mut linker, |x| x).expect("Unable to add cli stderr");
        bindings::cli::terminal_input::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add cli terminal input");
        bindings::cli::terminal_output::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add cli terminal output");
        bindings::cli::terminal_stdin::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add cli terminal stdin");
        bindings::cli::terminal_stdout::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add cli terminal stdout");
        bindings::cli::terminal_stderr::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add cli terminal stderr");
        bindings::clocks::monotonic_clock::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add clocks monotonic clock");
        bindings::clocks::wall_clock::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add clocks wallclock");
        // bindings::sync::filesystem::types::add_to_linker(&mut linker, |x| x)
        //     .expect("Unable to add filesystem types");
        bindings::filesystem::types::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add filesystem types");
        bindings::filesystem::preopens::add_to_linker(&mut linker, |x| x)
            .expect("Unable to add filesystem preopens");
        bindings::random::random::add_to_linker(&mut linker, |x| x).expect("Unable to add random");

        let wasi = WasiCtxBuilder::new()
            .inherit_stdout()
            .inherit_stderr()
            .build();

        let table: ResourceTable = ResourceTable::new();

        // Create a new store with the WASI context.
        let mut store = Store::new(
            self.engine(),
            Host {
                table,
                wasi,
                client: None,
            },
        );

        unsafe {
            STORE.replace(store);
        }

        let wasm_input = WasmInput::new(parts, body);
        let request = inbound_http::Request {
            method: match wasm_input.method {
                io::Method::GET => http_types::Method::Get,
                io::Method::POST => http_types::Method::Post,
                io::Method::PUT => http_types::Method::Put,
                io::Method::DELETE => http_types::Method::Delete,
                io::Method::PATCH => http_types::Method::Patch,
                io::Method::HEAD => http_types::Method::Head,
                io::Method::OPTIONS => http_types::Method::Options,
            },
            uri: wasm_input.uri,
            headers: wasm_input.headers,
            params: wasm_input.params,
            body: wasm_input.body,
        };

        wit::Reactor::add_to_linker(&mut linker, |x| x)?;
        debug!("Instantiated component");
        unsafe {

            let store = STORE.as_mut().unwrap();
            let (reactor, instance) =
                wit::Reactor::instantiate_async(&mut *store, self.component(), &linker).await?;

            REACTOR.replace(Arc::new(reactor));
            let reactor = REACTOR.clone().unwrap();
            let guest = reactor.arakoo_edgechains_inbound_http();
            let result: Result<http_types::Response, anyhow::Error> =
                guest.call_handle_request(&mut *store, &request).await;
            debug!("Calling guest handle completed");
            let mut wasm_output = WasmOutput::new();
            // println!("Result of guest calling: {:?}", &result);
            match result {
                Ok(res) => {
                    wasm_output.status = res.status;
                    wasm_output.status_text = res.status_text;
                    let mut headers_map = HashMap::new();
                    for (key, val) in res.headers.unwrap().iter() {
                        headers_map.insert(key.to_owned(), val.to_owned());
                    }
                    wasm_output.headers = headers_map;
                    let body_vec = res.body.unwrap();
                    if body_vec.len() > 0 {
                        wasm_output.body = Some(String::from_utf8(body_vec).unwrap());
                    }
                }
                Err(err) => println!("Error occured : {:?}", err),
            };


            Ok(wasm_output)
        }
    }
  1. The guest wasm is basically the embedded qjs runtime and js code
    handle_request function

fn handle_request(req: wit::Request) -> wit::Response {
        // TODO: log on env variable basis
        // println!("{:?}", req);
        let context = **CONTEXT.get().unwrap();
        let mut serializer =
            javy::quickjs::Serializer::from_context(context).expect("Unable to create serializer");
        let handler = **HANDLER.get().unwrap();
        let request = HttpRequest {
            method: match req.method {
                wit::Method::Get => "GET".to_string(),
                wit::Method::Post => "POST".to_string(),
                wit::Method::Put => "PUT".to_string(),
                wit::Method::Delete => "DELETE".to_string(),
                wit::Method::Patch => "PATCH".to_string(),
                wit::Method::Head => "HEAD".to_string(),
                wit::Method::Options => "OPTIONS".to_string(),
            },
            uri: req.uri,
            headers: req
                .headers
                .iter()
                .map(|(k, v)| Ok((k.as_str().to_owned(), v.as_str().to_owned())))
                .collect::<Result<HashMap<String, String>>>()
                .unwrap(),
            params: req
                .params
                .iter()
                .map(|(k, v)| Ok((k.as_str().to_owned(), v.as_str().to_owned())))
                .collect::<Result<HashMap<String, String>>>()
                .unwrap(),
            body: req.body.map(|bytes| ByteBuf::from::<Vec<u8>>(bytes)),
        };
        // let hono_event =
        // hono_event.serialize(&mut serializer).unwrap();
        request
            .serialize(&mut serializer)
            .expect("unable to serialize httprequest");
        let request_value = serializer.value;
        // println!("body of httpRequest : {:?}", from_qjs_value(request_value).unwrap());
        let global = GLOBAL.get().unwrap();
        let request_to_event = global
            .get_property("requestToEvent")
            .expect("Unable to get requestToEvent");
        let event = request_to_event
            .call(global, &[request_value])
            .expect("Unable to call requestToEvent");
        let event_request = event
            .get_property("request")
            .expect("Unable to get request from event");
        let promise = handler
            .call(global, &[event_request, event])
            .expect("Unable to call handler");

        let on_resolve = ON_RESOLVE.get().unwrap().clone();
        let on_reject = ON_REJECT.get().unwrap().clone();
        let then_func = promise.get_property("then").unwrap();
        if then_func.is_function() {
            then_func
                .call(
                    &promise,
                    &[on_resolve.deref().clone(), on_reject.deref().clone()],
                )
                .unwrap();
        } else {
            RESPONSE
                .lock()
                .unwrap()
                .replace(from_qjs_value(promise).unwrap());
        }

        context
            .execute_pending()
            .expect("Unable to execute pending tasks");

        // let response = to_qjs_value(context, &RESPONSE.lock().unwrap().take().unwrap()).unwrap();
        let response = RESPONSE.lock().unwrap().take().unwrap();

        // let deserializer = &mut Deserializer::from(response);
        // let response = HttpResponse::deserialize(deserializer).unwrap();
        // println!("Http Response {:?}", response);
        if let JSValue::Object(obj) = response {
            let status_code_ref = to_qjs_value(context, obj.get("status").unwrap()).unwrap();
            let status_co
[message truncated]

view this post on Zulip Wasmtime GitHub notifications bot (May 22 2024 at 15:07):

dicej commented on issue #8670:

I commented on this scenario in https://github.com/dicej/isyswasfa/issues/4#issuecomment-2125015257. In short, I think this kind of thing _could_ be supported with component model async by deferring the would-be-reentering call to the top-level event loop in the host and connecting it back to the import call via e.g. a oneshot channel. I'll keep that use case in mind as part of my Wasmtime async implementation work.

view this post on Zulip Wasmtime GitHub notifications bot (May 23 2024 at 01:16):

redoC-A2k commented on issue #8670:

What can I do now ? What I want to do is that possible with core wasm modules ? Or any other solution to solve my use case ?

view this post on Zulip Wasmtime GitHub notifications bot (May 23 2024 at 01:17):

redoC-A2k edited a comment on issue #8670:

What can I do now ? What I want to do is that possible with core wasm modules ? Or any other solution to solve my use case ?
@dicej @alexcrichton

view this post on Zulip Wasmtime GitHub notifications bot (May 23 2024 at 01:18):

redoC-A2k edited a comment on issue #8670:

What can I do now ? What I want to do is that possible with core wasm modules ? Or any other solution to solve my use case ?
@dicej

view this post on Zulip Wasmtime GitHub notifications bot (May 23 2024 at 10:04):

redoC-A2k edited a comment on issue #8670:

What can I do now ? What I want to do is that possible with core wasm modules ? Or any other solution to solve my use case ?
@dicej @alexcrichton

view this post on Zulip Wasmtime GitHub notifications bot (May 23 2024 at 15:09):

dicej commented on issue #8670:

@redoC-A2k I'll admit I haven't read through all the code you posted line-by-line, so maybe I'm missing something that should be obvious. Why is the guest calling a host function whose only job is to call a guest function? Can't the guest just call the guest function directly? Is there a way you can refactor this so any guest calls are direct without involving the host at all?

Maybe you need the host to do something privileged that the guest can't do on its own? Or you need the host to decide which guest function to call for some reason? In the latter case, could you treat the host call as a "trampoline" function which returns a value to the guest that tells the guest which guest function to call next? Keep in mind that recursive calls can always be flattened into iterative calls, and that might be a useful workaround here.

view this post on Zulip Wasmtime GitHub notifications bot (Jun 17 2024 at 20:17):

alexcrichton closed issue #8670:

hey there how can I sort of clone a wasm in execution the issue is I call the one of the imported function (1st function) from guest on host ( wasm is in execution as of now)
Now that imported function from guest to wasm calls another function which is exported by host to guest but this function ( exported function on host) again needs to call different (let's call it 2nd function) imported function from guest and this is the issue .
During this whole process wasm is in execution and how can I call the 2nd function ?

I tried storing reactor(component) and store in static variable , reactor works fine as it only requires reference while function calling but issue is in case of store while calling imported function I need to provide mutable reference to store . Which I can't as at a time I can't have two mutable reference . For sharing mutable reference - I created a static option containing Store and passed the mutable reference to function like so

let result: Result<http_types::Response, anyhow::Error> =
                guest.call_handle_request(&mut *store, &request).await; (1st function) (in main function where I instantiate component)
let result = guest.call_jsonnet_call_native_func(&mut *store, &self.0, "")
                        .await (2nd function) (in some other exported function which component calls as a result of calling above imported function)

But in above case I am getting error
wasm trap: cannot enter component instance

I tried creating new store but then I get some different error , if I use that store with reference of Reactor .

Please help me , I don't want to use core wasm modules . Nor I think I will be able to break the wasm module in two components (as I my wasm module is basically quickjs runtime along with js code the wasm is generated by cargo building to target wasm32-wasi the quickjs_wasm_rs context (javy approach, fermyon spin approach) .

view this post on Zulip Wasmtime GitHub notifications bot (Jun 17 2024 at 20:17):

alexcrichton commented on issue #8670:

I believe that the question here more-or-less has been answered and/or the discussion has sort of petered out at this point. I'm going to close this but am happy to reopen if there's more.


Last updated: Dec 23 2024 at 13:07 UTC