Skip to content

Commit 944e703

Browse files
add js dyn module function to otoroshi workflows in workflows.scala
1 parent 87d31ff commit 944e703

1 file changed

Lines changed: 106 additions & 1 deletion

File tree

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,110 @@
11
package com.cloud.apim.otoroshi.plugins.jsdynmodules
22

3-
class workflows {
3+
import io.otoroshi.wasm4s.scaladsl.{WasmFunctionParameters, WasmSource, WasmSourceKind}
4+
import otoroshi.env.Env
5+
import otoroshi.next.workflow._
6+
import otoroshi.utils.syntax.implicits._
7+
import otoroshi.wasm.WasmConfig
8+
import otoroshi_plugins.com.cloud.apim.plugins.jsdynmodules.JsModulePlugin
9+
import play.api.libs.json._
410

11+
import scala.concurrent.{ExecutionContext, Future}
12+
13+
object WorkflowFunctionsInitializer {
14+
def initDefaults(): Unit = {
15+
WorkflowFunction.registerFunction("extensions.com.cloud-apim.js-dynamic-modules-extension.call_function", new RunFunctionFunction())
16+
}
17+
}
18+
19+
class RunFunctionFunction extends WorkflowFunction {
20+
21+
override def documentationName: String = "extensions.com.cloud-apim.js-dynamic-modules-extension.call_function"
22+
override def documentationDisplayName: String = "Call javascript function"
23+
override def documentationIcon: String = "fas fa-code"
24+
override def documentationDescription: String = "This function calls a javascript function in QuickJS in a wasm vm"
25+
override def documentationInputSchema: Option[JsObject] = Some(Json.obj(
26+
"type" -> "object",
27+
"required" -> Seq("code", "arguments"),
28+
"properties" -> Json.obj(
29+
"code" -> Json.obj("type" -> "string", "description" -> "The function code"),
30+
"arguments" -> Json.obj("type" -> "string", "description" -> "The function arguments")
31+
)
32+
))
33+
override def documentationFormSchema: Option[JsObject] = Some(Json.obj(
34+
"code" -> Json.obj(
35+
"type" -> "any",
36+
"description" -> "The function code",
37+
"props" -> Json.obj(
38+
"height" -> "300px",
39+
"language" -> "javascript",
40+
"config" -> Json.obj(
41+
"lineNumbers" -> true
42+
)
43+
)
44+
),
45+
"arguments" -> Json.obj(
46+
"type" -> "any",
47+
"props" -> Json.obj(
48+
"height" -> "300px",
49+
"language" -> "javascript",
50+
"config" -> Json.obj(
51+
"lineNumbers" -> true
52+
)
53+
),
54+
"label" -> "Arguments"
55+
)
56+
))
57+
override def documentationCategory: Option[String] = Some("Cloud APIM - Js dynamic modules extension")
58+
override def documentationOutputSchema: Option[JsObject] = Some(Json.obj(
59+
"type" -> "any",
60+
"description" -> "The function result"
61+
))
62+
override def documentationExample: Option[JsObject] = Some(Json.obj(
63+
"kind" -> "call",
64+
"function" -> "extensions.com.cloud-apim.llm-extension.tool_function_call",
65+
"args" -> Json.obj(
66+
"code" -> "exports.main = function(ctx) { ... }",
67+
"arguments" -> "{ ... }"
68+
)
69+
))
70+
71+
override def callWithRun(args: JsObject)(implicit env: Env, ec: ExecutionContext, wfr: WorkflowRun): Future[Either[WorkflowError, JsValue]] = {
72+
val code = args.select("code").asString
73+
val arguments = args.select("arguments").asOpt[JsObject].map(_.stringify)
74+
.orElse(args.select("arguments").asOpt[JsArray].map(_.stringify))
75+
.orElse(args.select("arguments").asOpt[JsNumber].map(_.stringify))
76+
.orElse(args.select("arguments").asOpt[JsBoolean].map(_.stringify))
77+
.orElse(args.select("arguments").asOpt[String])
78+
.getOrElse("")
79+
val pluginConfig = WasmConfig(source = WasmSource(WasmSourceKind.Local, JsModulePlugin.wasmPluginId, Json.obj()))
80+
env.wasmIntegration.wasmVmFor(pluginConfig).flatMap {
81+
case None => WorkflowError("Unable to find js runtime").leftf
82+
case Some((vm, localConfig)) =>
83+
vm.call(
84+
WasmFunctionParameters.ExtismFuntionCall(
85+
"cloud_apim_module_plugin_execute_user_function",
86+
Json.obj(
87+
"code" -> code,
88+
"env" -> Json.obj(),
89+
"module" -> "workflow_function.js",
90+
"externalApiUrl" -> JsNull,
91+
"externalApiHeaders" -> JsNull,
92+
"function_args" -> arguments,
93+
"memory" -> wfr.memory.json
94+
).stringify
95+
),
96+
None
97+
).flatMap {
98+
case Right(res) =>
99+
val response = Json.parse(res._1)
100+
response.rightf
101+
case Left(value) => WorkflowError("Js exec error", Json.obj("js_error" -> value).some).leftf
102+
}.andThen { case _ =>
103+
vm.release()
104+
}
105+
}.recover {
106+
case t: Throwable =>
107+
WorkflowError("Js recover error", Json.obj("js_error" -> t.getMessage).some).left
108+
}
109+
}
5110
}

0 commit comments

Comments
 (0)