diff --git a/pom.xml b/pom.xml index 12cf56a..ec2f060 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,7 @@ 6.6.8 3.27.1 2.43.0 + 1.0.0 @@ -42,6 +43,13 @@ pom import + + com.dylibso.chicory + bom + ${chicory.version} + pom + import + @@ -73,6 +81,14 @@ generator-annotations ${fabric8-client.version} + + com.dylibso.chicory + runtime + + + com.dylibso.chicory + wasi + org.awaitility awaitility @@ -88,23 +104,6 @@ io.quarkus quarkus-container-image-jib - - org.graalvm.polyglot - polyglot - ${graalvm.version} - - - org.graalvm.js - js-scriptengine - ${graalvm.version} - - - org.graalvm.polyglot - js-community - ${graalvm.version} - pom - runtime - org.bouncycastle bcpkix-jdk18on @@ -207,6 +206,23 @@ + + com.dylibso.chicory + aot-maven-plugin-experimental + ${chicory.version} + + + quickJs + + wasm-aot-gen + + + io.javaoperatorsdk.operator.glue.wasm.QuickJs + src/main/resources/wasm/quickjs-provider.wasm + + + + diff --git a/src/main/java/io/javaoperatorsdk/operator/glue/conditions/JavaScripCondition.java b/src/main/java/io/javaoperatorsdk/operator/glue/conditions/JavaScripCondition.java index 60c8ce4..a5bc608 100644 --- a/src/main/java/io/javaoperatorsdk/operator/glue/conditions/JavaScripCondition.java +++ b/src/main/java/io/javaoperatorsdk/operator/glue/conditions/JavaScripCondition.java @@ -1,12 +1,12 @@ package io.javaoperatorsdk.operator.glue.conditions; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.Map; import java.util.stream.Collectors; -import javax.script.*; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,14 +17,20 @@ import io.javaoperatorsdk.operator.glue.GlueException; import io.javaoperatorsdk.operator.glue.Utils; import io.javaoperatorsdk.operator.glue.customresource.glue.Glue; +import io.javaoperatorsdk.operator.glue.wasm.QuickJsModule; import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition; +import com.dylibso.chicory.runtime.ImportValues; +import com.dylibso.chicory.runtime.Instance; +import com.dylibso.chicory.wasi.WasiOptions; +import com.dylibso.chicory.wasi.WasiPreview1; + +import static java.nio.charset.StandardCharsets.UTF_8; + public class JavaScripCondition implements Condition { private static final Logger LOG = LoggerFactory.getLogger(JavaScripCondition.class); - private static final String RESOURCE_AS_STRING_NAME_SUFFIX = "Str"; - private final String inputScript; public JavaScripCondition(String inputScript) { @@ -35,50 +41,71 @@ public JavaScripCondition(String inputScript) { public boolean isMet(DependentResource dependentResource, Glue glue, Context context) { - try { + try (var jsStderr = new ByteArrayOutputStream(); + var wasi = WasiPreview1.builder() + .withOptions(WasiOptions.builder().withStderr(jsStderr).build()).build()) { var start = LocalDateTime.now(); - ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine engine = manager.getEngineByName("js"); + + var quickjs = Instance.builder(QuickJsModule.load()) + .withImportValues(ImportValues.builder().addFunction(wasi.toHostFunctions()).build()) + .withMachineFactory(QuickJsModule::create) + .build(); StringBuilder finalScript = new StringBuilder(); - addTargetResourceToScript(dependentResource, glue, context, engine, finalScript); - addSecondaryResourceToScript(glue, context, engine, finalScript); + addTargetResourceToScript(dependentResource, glue, context, finalScript); + addSecondaryResourceToScript(glue, context, finalScript); finalScript.append("\n").append(inputScript); - LOG.debug("Final Condition JS:\n{}", finalScript); + // Using stderr to return the result + String finalJsCode = "console.error(eval(`" + finalScript + "`));"; + LOG.debug("Final Condition JS:\n{}", finalJsCode); + byte[] jsCode = finalJsCode.getBytes(UTF_8); + + var ptr = + quickjs.export("canonical_abi_realloc") + .apply( + 0, // original_ptr + 0, // original_size + 1, // alignment + jsCode.length // new size + )[0]; + + quickjs.memory().write((int) ptr, jsCode); + var aggregatedCodePtr = quickjs.export("compile_src").apply(ptr, jsCode.length)[0]; + + var codePtr = quickjs.memory().readI32((int) aggregatedCodePtr); // 32 bit + var codeLength = quickjs.memory().readU32((int) aggregatedCodePtr + 4); + + quickjs.export("eval_bytecode").apply(codePtr, codeLength); - CompiledScript script = ((Compilable) engine).compile(finalScript.toString()); - var res = (boolean) script.eval(); + var res = Boolean.valueOf(jsStderr.toString().trim()); LOG.debug("JS Condition evaluated as: {} within {}ms", res, ChronoUnit.MILLIS.between(start, LocalDateTime.now())); return res; - } catch (ScriptException e) { + } catch (IOException e) { throw new GlueException(e); } } private static void addSecondaryResourceToScript(Glue glue, Context context, - ScriptEngine engine, StringBuilder finalScript) { + StringBuilder finalScript) { Map namedSecondaryResources = nameAndSerializeSecondaryResources(context, glue); namedSecondaryResources.forEach((k, v) -> { - var stringKey = k + RESOURCE_AS_STRING_NAME_SUFFIX; - engine.put(stringKey, v); - finalScript.append("const ").append(k).append(" = JSON.parse(").append(stringKey) - .append(");\n"); + finalScript.append("const ").append(k).append(" = JSON.parse('").append(v) + .append("');\n"); }); } private static void addTargetResourceToScript( DependentResource dependentResource, Glue glue, - Context context, ScriptEngine engine, StringBuilder finalScript) { + Context context, StringBuilder finalScript) { var target = dependentResource.getSecondaryResource(glue, context); target.ifPresent(t -> { - engine.put("targetStr", Serialization.asJson(t)); - finalScript.append("const target = JSON.parse(targetStr);\n"); + finalScript.append("const target = JSON.parse('" + Serialization.asJson(t) + "');\n"); }); } diff --git a/src/main/resources/wasm/quickjs-provider.wasm b/src/main/resources/wasm/quickjs-provider.wasm new file mode 100644 index 0000000..abcdf4e Binary files /dev/null and b/src/main/resources/wasm/quickjs-provider.wasm differ diff --git a/src/test/java/io/javaoperatorsdk/operator/glue/JavaScripConditionTest.java b/src/test/java/io/javaoperatorsdk/operator/glue/JavaScripConditionTest.java index dcd1e15..37b4028 100644 --- a/src/test/java/io/javaoperatorsdk/operator/glue/JavaScripConditionTest.java +++ b/src/test/java/io/javaoperatorsdk/operator/glue/JavaScripConditionTest.java @@ -40,7 +40,7 @@ void setup() { void javaScriptSimpleConditionTest() { var condition = new JavaScripCondition(""" - x = 1; + const x = 1; x<2; """);