Skip to content

Commit

Permalink
Merge pull request #5 from blocklessnetwork/feature/console_log
Browse files Browse the repository at this point in the history
feature: use the stdout as output when using console.log api.
  • Loading branch information
Joinhack authored Aug 26, 2024
2 parents 8d35f47 + 61fa847 commit 0760cc1
Show file tree
Hide file tree
Showing 14 changed files with 220 additions and 48 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ jobs:
run: cargo build -p javy-core --release --target=wasm32-wasi

- name: Test
run: cargo hack wasi test --workspace --exclude=javy-cli --each-feature -- --nocapture
run: |
cargo wasi test --manifest-path crates/quickjs-wasm-rs/Cargo.toml --all-features -- --nocapture
cargo wasi test --manifest-path crates/apis/Cargo.toml --all-features -- --nocapture
cargo wasi test --manifest-path crates/quickjs-wasm-sys/Cargo.toml --all-features -- --nocapture
cargo wasi test --manifest-path crates/javy/Cargo.toml --all-features -- --nocapture
- name: Lint
run: cargo clippy --workspace --exclude=javy-cli --target=wasm32-wasi --all-targets -- -D warnings
Expand Down
4 changes: 2 additions & 2 deletions crates/apis/src/crypto/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use anyhow::Result;
use javy::{quickjs::JSValue, Runtime};
use javy::quickjs::{JSContextRef, JSValueRef};
use javy::{quickjs::JSValue, Runtime};

use rand::RngCore;
use crate::{APIConfig, JSApiSet};
use rand::RngCore;

pub struct Crypto;

Expand Down
7 changes: 4 additions & 3 deletions crates/apis/src/fetch_io/blockless.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::cmp::Ordering;
use serde_json::{json, Value};
#![allow(dead_code)]
use crate::fetch_io::FetchOptions;
use serde_json::{json, Value};
use std::cmp::Ordering;

pub type Handle = u32;

Expand Down Expand Up @@ -226,4 +227,4 @@ extern "C" {

#[link_name = "http_close"]
pub(crate) fn http_close(handle: u32) -> u32;
}
}
15 changes: 9 additions & 6 deletions crates/apis/src/fetch_io/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
#![allow(dead_code)]
mod blockless;

use std::collections::HashMap;
use anyhow::{anyhow, Result};
use javy::{quickjs::JSValue, Runtime};
use serde_json::{from_slice};
use serde::{Deserialize, Serialize};
use serde_json::from_slice;
use std::collections::HashMap;

use crate::fetch_io::blockless::BlocklessHttp;
use crate::{APIConfig, JSApiSet};
use javy::quickjs::{JSContextRef, JSValueRef};
use crate::fetch_io::blockless::BlocklessHttp;

pub(super) struct FetchIO;

Expand All @@ -20,10 +21,11 @@ pub struct FetchOptions {
impl FetchOptions {
pub fn new(method: &str) -> Self {
FetchOptions {
method: method.into()
method: method.into(),
}
}

#[allow(clippy::inherent_to_string)]
pub fn to_string(&self) -> String {
serde_json::to_string(&self).unwrap()
}
Expand All @@ -45,7 +47,8 @@ impl JSApiSet for FetchIO {
}
}

fn fetchio_request() -> impl FnMut(&JSContextRef, JSValueRef, &[JSValueRef]) -> anyhow::Result<JSValue> {
fn fetchio_request(
) -> impl FnMut(&JSContextRef, JSValueRef, &[JSValueRef]) -> anyhow::Result<JSValue> {
move |_ctx: &JSContextRef, _this: JSValueRef, args: &[JSValueRef]| {
if args.len() != 4 {
return Err(anyhow!("Expecting 4 arguments, received {}", args.len()));
Expand Down Expand Up @@ -77,4 +80,4 @@ fn fetchio_request() -> impl FnMut(&JSContextRef, JSValueRef, &[JSValueRef]) ->

Ok(JSValue::Object(response))
}
}
}
9 changes: 5 additions & 4 deletions crates/apis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,23 @@ use javy::Runtime;
pub use api_config::APIConfig;
#[cfg(feature = "console")]
pub use console::LogStream;

pub use runtime_ext::RuntimeExt;

mod api_config;
#[cfg(feature = "console")]
mod console;
#[cfg(feature = "crypto")]
mod crypto;
#[cfg(feature = "fetch_io")]
mod fetch_io;
#[cfg(feature = "random")]
mod random;
mod runtime_ext;
#[cfg(feature = "stream_io")]
mod stream_io;
#[cfg(feature = "text_encoding")]
mod text_encoding;
#[cfg(feature = "fetch_io")]
mod fetch_io;
#[cfg(feature = "crypto")]
mod crypto;

pub(crate) trait JSApiSet {
fn register(&self, runtime: &Runtime, config: &APIConfig) -> Result<()>;
Expand Down
1 change: 1 addition & 0 deletions crates/cli/benches/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ impl FunctionCase {
Ok(function_case)
}

#[allow(clippy::needless_borrows_for_generic_args)]
pub fn run(&self, linker: &mut Linker<WasiCtx>, mut store: &mut Store<WasiCtx>) -> Result<()> {
let js_module = match &self.precompiled_elf_bytes {
Some(bytes) => unsafe { Module::deserialize(&self.engine, bytes) }?,
Expand Down
3 changes: 3 additions & 0 deletions crates/cli/src/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ fn create_wasm_env() -> Result<(Store<WasiCtx>, Instance, Memory)> {
Ok((store, instance, memory))
}

#[allow(clippy::needless_borrows_for_generic_args)]
fn copy_source_code_into_instance(
js_source_code: &[u8],
mut store: &mut Store<WasiCtx>,
Expand All @@ -48,6 +49,7 @@ fn copy_source_code_into_instance(
Ok((js_source_ptr, js_src_len))
}

#[allow(clippy::needless_borrows_for_generic_args)]
fn call_compile(
js_src_ptr: u32,
js_src_len: u32,
Expand All @@ -61,6 +63,7 @@ fn call_compile(
Ok(ret_ptr)
}

#[allow(clippy::needless_borrows_for_generic_args)]
fn copy_bytecode_from_instance(
ret_ptr: u32,
mut store: &mut Store<WasiCtx>,
Expand Down
38 changes: 26 additions & 12 deletions crates/cli/tests/dylib_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod common;
fn test_dylib() -> Result<()> {
let js_src = "console.log(42);";
let stderr = WritePipe::new_in_memory();
run_js_src(js_src, &stderr)?;
run_js_src(js_src, &stderr, false)?;

let output = stderr.try_into_inner().unwrap().into_inner();
assert_eq!("42\n", str::from_utf8(&output)?);
Expand All @@ -23,7 +23,7 @@ fn test_dylib() -> Result<()> {
fn test_dylib_with_error() -> Result<()> {
let js_src = "function foo() { throw new Error('foo error'); } foo();";
let stderr = WritePipe::new_in_memory();
let result = run_js_src(js_src, &stderr);
let result = run_js_src(js_src, &stderr, true);

assert!(result.is_err());
let output = stderr.try_into_inner().unwrap().into_inner();
Expand All @@ -37,17 +37,21 @@ fn test_dylib_with_error() -> Result<()> {
#[test]
fn test_dylib_with_exported_func() -> Result<()> {
let js_src = "export function foo() { console.log('In foo'); }; console.log('Toplevel');";
let stderr = WritePipe::new_in_memory();
run_invoke(js_src, "foo", &stderr)?;
let stdout = WritePipe::new_in_memory();
run_invoke(js_src, "foo", &stdout)?;

let output = stderr.try_into_inner().unwrap().into_inner();
let output = stdout.try_into_inner().unwrap().into_inner();
assert_eq!("Toplevel\nIn foo\n", str::from_utf8(&output)?);

Ok(())
}

fn run_js_src<T: WasiFile + Clone + 'static>(js_src: &str, stderr: &T) -> Result<()> {
let (instance, mut store) = create_wasm_env(stderr)?;
fn run_js_src<T: WasiFile + Clone + 'static>(
js_src: &str,
stderr: &T,
is_stderr: bool,
) -> Result<()> {
let (instance, mut store) = create_wasm_env(stderr, is_stderr)?;

let eval_bytecode_func =
instance.get_typed_func::<(u32, u32), ()>(&mut store, "eval_bytecode")?;
Expand All @@ -59,9 +63,9 @@ fn run_js_src<T: WasiFile + Clone + 'static>(js_src: &str, stderr: &T) -> Result
fn run_invoke<T: WasiFile + Clone + 'static>(
js_src: &str,
fn_to_invoke: &str,
stderr: &T,
stdout: &T,
) -> Result<()> {
let (instance, mut store) = create_wasm_env(stderr)?;
let (instance, mut store) = create_wasm_env(stdout, false)?;

let invoke_func = instance.get_typed_func::<(u32, u32, u32, u32), ()>(&mut store, "invoke")?;
let (bytecode_ptr, bytecode_len) = compile_src(js_src.as_bytes(), &instance, &mut store)?;
Expand All @@ -75,13 +79,20 @@ fn run_invoke<T: WasiFile + Clone + 'static>(

fn create_wasm_env<T: WasiFile + Clone + 'static>(
stderr: &T,
is_stderr: bool,
) -> Result<(Instance, Store<WasiCtx>)> {
let engine = Engine::default();
let mut linker = Linker::new(&engine);
wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;
let wasi = WasiCtxBuilder::new()
.stderr(Box::new(stderr.clone()))
.build();
let wasi = if is_stderr {
WasiCtxBuilder::new()
.stderr(Box::new(stderr.clone()))
.build()
} else {
WasiCtxBuilder::new()
.stdout(Box::new(stderr.clone()))
.build()
};
let module = common::create_quickjs_provider_module(&engine)?;

let mut store = Store::new(&engine, wasi);
Expand All @@ -90,6 +101,7 @@ fn create_wasm_env<T: WasiFile + Clone + 'static>(
Ok((instance, store))
}

#[allow(clippy::needless_borrows_for_generic_args)]
fn compile_src(
js_src: &[u8],
instance: &Instance,
Expand All @@ -110,6 +122,7 @@ fn compile_src(
Ok((bytecode_ptr, bytecode_len))
}

#[allow(clippy::needless_borrows_for_generic_args)]
fn copy_func_name(
fn_name: &str,
instance: &Instance,
Expand All @@ -123,6 +136,7 @@ fn copy_func_name(
Ok((fn_name_ptr, fn_name_bytes.len().try_into()?))
}

#[allow(clippy::needless_borrows_for_generic_args)]
fn allocate_memory(
instance: &Instance,
mut store: &mut Store<WasiCtx>,
Expand Down
23 changes: 15 additions & 8 deletions crates/cli/tests/dynamic_linking_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mod common;
#[test]
pub fn test_dynamic_linking() -> Result<()> {
let js_src = "console.log(42);";
let log_output = invoke_fn_on_generated_module(js_src, "_start", None)?;
let log_output = invoke_fn_on_generated_module(js_src, "_start", None, false)?;
assert_eq!("42\n", &log_output);
Ok(())
}
Expand All @@ -28,15 +28,16 @@ pub fn test_dynamic_linking_with_func() -> Result<()> {
export foo-bar: func()
}
";
let log_output = invoke_fn_on_generated_module(js_src, "foo-bar", Some((wit, "foo-test")))?;
let log_output =
invoke_fn_on_generated_module(js_src, "foo-bar", Some((wit, "foo-test")), false)?;
assert_eq!("Toplevel\nIn foo\n", &log_output);
Ok(())
}

#[test]
pub fn test_dynamic_linking_with_func_without_flag() -> Result<()> {
let js_src = "export function foo() { console.log('In foo'); }; console.log('Toplevel');";
let res = invoke_fn_on_generated_module(js_src, "foo", None);
let res = invoke_fn_on_generated_module(js_src, "foo", None, true);
assert_eq!(
"failed to find function export `foo`",
res.err().unwrap().to_string()
Expand All @@ -49,7 +50,7 @@ pub fn check_for_new_imports() -> Result<()> {
// If you need to change this test, then you've likely made a breaking change.
let js_src = "console.log(42);";
let wasm = create_dynamically_linked_wasm_module(js_src, None)?;
let (engine, _linker, _store) = create_wasm_env(WritePipe::new_in_memory())?;
let (engine, _linker, _store) = create_wasm_env(WritePipe::new_in_memory(), false)?;
let module = Module::from_binary(&engine, &wasm)?;
for import in module.imports() {
match (import.module(), import.name(), import.ty()) {
Expand Down Expand Up @@ -78,7 +79,7 @@ pub fn check_for_new_imports_for_exports() -> Result<()> {
}
";
let wasm = create_dynamically_linked_wasm_module(js_src, Some((wit, "foo-test")))?;
let (engine, _linker, _store) = create_wasm_env(WritePipe::new_in_memory())?;
let (engine, _linker, _store) = create_wasm_env(WritePipe::new_in_memory(), false)?;
let module = Module::from_binary(&engine, &wasm)?;
for import in module.imports() {
match (import.module(), import.name(), import.ty()) {
Expand Down Expand Up @@ -110,7 +111,7 @@ pub fn test_dynamic_linking_with_arrow_fn() -> Result<()> {
}
";
let log_output =
invoke_fn_on_generated_module(js_src, "default", Some((wit, "exported-arrow")))?;
invoke_fn_on_generated_module(js_src, "default", Some((wit, "exported-arrow")), false)?;
assert_eq!("42\n", log_output);
Ok(())
}
Expand Down Expand Up @@ -166,11 +167,12 @@ fn invoke_fn_on_generated_module(
js_src: &str,
func: &str,
wit: Option<(&str, &str)>,
is_stderr: bool,
) -> Result<String> {
let js_wasm = create_dynamically_linked_wasm_module(js_src, wit)?;

let stderr = WritePipe::new_in_memory();
let (engine, mut linker, mut store) = create_wasm_env(stderr.clone())?;
let (engine, mut linker, mut store) = create_wasm_env(stderr.clone(), is_stderr)?;
let quickjs_provider_module = common::create_quickjs_provider_module(&engine)?;
let js_module = Module::from_binary(&engine, &js_wasm)?;

Expand All @@ -192,11 +194,16 @@ fn invoke_fn_on_generated_module(

fn create_wasm_env(
stderr: WritePipe<Cursor<Vec<u8>>>,
is_stderr: bool,
) -> Result<(Engine, Linker<WasiCtx>, Store<WasiCtx>)> {
let engine = Engine::new(Config::new().wasm_multi_memory(true))?;
let mut linker = Linker::new(&engine);
wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;
let wasi = WasiCtxBuilder::new().stderr(Box::new(stderr)).build();
let wasi = if is_stderr {
WasiCtxBuilder::new().stderr(Box::new(stderr)).build()
} else {
WasiCtxBuilder::new().stdout(Box::new(stderr)).build()
};
let store = Store::new(&engine, wasi);
Ok((engine, linker, store))
}
Loading

0 comments on commit 0760cc1

Please sign in to comment.