1
1
package io .javaoperatorsdk .operator .glue .conditions ;
2
2
3
+ import java .io .ByteArrayOutputStream ;
4
+ import java .io .IOException ;
3
5
import java .time .LocalDateTime ;
4
6
import java .time .temporal .ChronoUnit ;
5
7
import java .util .Map ;
6
8
import java .util .stream .Collectors ;
7
9
8
- import javax .script .*;
9
-
10
10
import org .slf4j .Logger ;
11
11
import org .slf4j .LoggerFactory ;
12
12
17
17
import io .javaoperatorsdk .operator .glue .GlueException ;
18
18
import io .javaoperatorsdk .operator .glue .Utils ;
19
19
import io .javaoperatorsdk .operator .glue .customresource .glue .Glue ;
20
+ import io .javaoperatorsdk .operator .glue .wasm .QuickJsModule ;
20
21
import io .javaoperatorsdk .operator .processing .dependent .workflow .Condition ;
21
22
23
+ import com .dylibso .chicory .runtime .ImportValues ;
24
+ import com .dylibso .chicory .runtime .Instance ;
25
+ import com .dylibso .chicory .wasi .WasiOptions ;
26
+ import com .dylibso .chicory .wasi .WasiPreview1 ;
27
+
28
+ import static java .nio .charset .StandardCharsets .UTF_8 ;
29
+
22
30
public class JavaScripCondition implements Condition <GenericKubernetesResource , Glue > {
23
31
24
32
private static final Logger LOG = LoggerFactory .getLogger (JavaScripCondition .class );
25
33
26
- private static final String RESOURCE_AS_STRING_NAME_SUFFIX = "Str" ;
27
-
28
34
private final String inputScript ;
29
35
30
36
public JavaScripCondition (String inputScript ) {
@@ -35,50 +41,71 @@ public JavaScripCondition(String inputScript) {
35
41
public boolean isMet (DependentResource <GenericKubernetesResource , Glue > dependentResource ,
36
42
Glue glue ,
37
43
Context <Glue > context ) {
38
- try {
44
+ try (var jsStderr = new ByteArrayOutputStream ();
45
+ var wasi = WasiPreview1 .builder ()
46
+ .withOptions (WasiOptions .builder ().withStderr (jsStderr ).build ()).build ()) {
39
47
var start = LocalDateTime .now ();
40
- ScriptEngineManager manager = new ScriptEngineManager ();
41
- ScriptEngine engine = manager .getEngineByName ("js" );
48
+
49
+ var quickjs = Instance .builder (QuickJsModule .load ())
50
+ .withImportValues (ImportValues .builder ().addFunction (wasi .toHostFunctions ()).build ())
51
+ .withMachineFactory (QuickJsModule ::create )
52
+ .build ();
42
53
43
54
StringBuilder finalScript = new StringBuilder ();
44
- addTargetResourceToScript (dependentResource , glue , context , engine , finalScript );
45
- addSecondaryResourceToScript (glue , context , engine , finalScript );
55
+ addTargetResourceToScript (dependentResource , glue , context , finalScript );
56
+ addSecondaryResourceToScript (glue , context , finalScript );
46
57
47
58
finalScript .append ("\n " ).append (inputScript );
48
59
49
- LOG .debug ("Final Condition JS:\n {}" , finalScript );
60
+ // Using stderr to return the result
61
+ String finalJsCode = "console.error(eval(`" + finalScript + "`));" ;
62
+ LOG .debug ("Final Condition JS:\n {}" , finalJsCode );
63
+ byte [] jsCode = finalJsCode .getBytes (UTF_8 );
64
+
65
+ var ptr =
66
+ quickjs .export ("canonical_abi_realloc" )
67
+ .apply (
68
+ 0 , // original_ptr
69
+ 0 , // original_size
70
+ 1 , // alignment
71
+ jsCode .length // new size
72
+ )[0 ];
73
+
74
+ quickjs .memory ().write ((int ) ptr , jsCode );
75
+ var aggregatedCodePtr = quickjs .export ("compile_src" ).apply (ptr , jsCode .length )[0 ];
76
+
77
+ var codePtr = quickjs .memory ().readI32 ((int ) aggregatedCodePtr ); // 32 bit
78
+ var codeLength = quickjs .memory ().readU32 ((int ) aggregatedCodePtr + 4 );
79
+
80
+ quickjs .export ("eval_bytecode" ).apply (codePtr , codeLength );
50
81
51
- CompiledScript script = ((Compilable ) engine ).compile (finalScript .toString ());
52
- var res = (boolean ) script .eval ();
82
+ var res = Boolean .valueOf (jsStderr .toString ().trim ());
53
83
LOG .debug ("JS Condition evaluated as: {} within {}ms" , res ,
54
84
ChronoUnit .MILLIS .between (start , LocalDateTime .now ()));
55
85
return res ;
56
- } catch (ScriptException e ) {
86
+ } catch (IOException e ) {
57
87
throw new GlueException (e );
58
88
}
59
89
}
60
90
61
91
private static void addSecondaryResourceToScript (Glue glue ,
62
92
Context <Glue > context ,
63
- ScriptEngine engine , StringBuilder finalScript ) {
93
+ StringBuilder finalScript ) {
64
94
Map <String , String > namedSecondaryResources =
65
95
nameAndSerializeSecondaryResources (context , glue );
66
96
namedSecondaryResources .forEach ((k , v ) -> {
67
- var stringKey = k + RESOURCE_AS_STRING_NAME_SUFFIX ;
68
- engine .put (stringKey , v );
69
- finalScript .append ("const " ).append (k ).append (" = JSON.parse(" ).append (stringKey )
70
- .append (");\n " );
97
+ finalScript .append ("const " ).append (k ).append (" = JSON.parse('" ).append (v )
98
+ .append ("');\n " );
71
99
});
72
100
}
73
101
74
102
private static void addTargetResourceToScript (
75
103
DependentResource <GenericKubernetesResource , Glue > dependentResource ,
76
104
Glue glue ,
77
- Context <Glue > context , ScriptEngine engine , StringBuilder finalScript ) {
105
+ Context <Glue > context , StringBuilder finalScript ) {
78
106
var target = dependentResource .getSecondaryResource (glue , context );
79
107
target .ifPresent (t -> {
80
- engine .put ("targetStr" , Serialization .asJson (t ));
81
- finalScript .append ("const target = JSON.parse(targetStr);\n " );
108
+ finalScript .append ("const target = JSON.parse('" + Serialization .asJson (t ) + "');\n " );
82
109
});
83
110
}
84
111
0 commit comments