|
@@ -0,0 +1,103 @@
|
|
|
+package nodes
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "errors"
|
|
|
+ "fmt"
|
|
|
+ "github.com/robertkrimen/otto"
|
|
|
+ "sparrow/pkg/protocol"
|
|
|
+ "sparrow/pkg/ruleEngine"
|
|
|
+ "sparrow/pkg/server"
|
|
|
+)
|
|
|
+
|
|
|
+const jsWrapperPrifixTemplate = `function %s(msgStr, metaDataStr, msgType) {
|
|
|
+ var msg = JSON.parse(msgStr);
|
|
|
+ var metaData = JSON.parse(metaDataStr);
|
|
|
+ return JSON.stringify(%s(msg, metaData, msgType));
|
|
|
+ function %s(%s, %s, %s) {`
|
|
|
+const jsWrapperSuffix = `}}`
|
|
|
+const ruleNodeFuncName = "ruleNodeFunc"
|
|
|
+// FilterJavascriptNode js代码逻辑节点,提供执行Js代码的执行能力,依赖执行结果输出节点的最终判定,脚本返回true或false
|
|
|
+// 默认Filter函数接收三个参数,Filter(msg, metadata, msgType)
|
|
|
+type FilterJavascriptNode struct {
|
|
|
+ vm *otto.Otto
|
|
|
+ config *FilterJavascriptNodeConfig
|
|
|
+}
|
|
|
+
|
|
|
+func (j *FilterJavascriptNode) Init(ctx ruleEngine.Context, config string) error {
|
|
|
+ if config != "" {
|
|
|
+ c := new(FilterJavascriptNodeConfig)
|
|
|
+ err := json.Unmarshal([]byte(config), c)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ j.config = c
|
|
|
+ }
|
|
|
+ j.vm = otto.New()
|
|
|
+ _, err := j.vm.Run(generateRuleNodeScript("filter", j.config.FuncBody))
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (j *FilterJavascriptNode) OnMessage(ctx ruleEngine.Context, message *protocol.Message) error {
|
|
|
+ body := message.Data
|
|
|
+ fmt.Println(body)
|
|
|
+ metaData, err := json.Marshal(message.MetaData)
|
|
|
+ if err != nil {
|
|
|
+ server.Log.Errorf("metadata marshal error:%s", err.Error())
|
|
|
+ next := j.processError(ctx, message, err)
|
|
|
+ ctx.TellError(next, err)
|
|
|
+ return errors.New("metadata marshal error " + err.Error())
|
|
|
+ }
|
|
|
+ fmt.Println(string(metaData))
|
|
|
+ res, err := j.vm.Call("filter", nil, body, string(metaData), message.Type)
|
|
|
+ if err != nil {
|
|
|
+ next := j.processError(ctx, message, err)
|
|
|
+ ctx.TellError(next, err)
|
|
|
+ server.Log.Errorf("vm call filter error:%s", err.Error())
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ result := res.IsBoolean()
|
|
|
+ if result {
|
|
|
+ ctx.TellNext(message, protocol.True)
|
|
|
+ } else {
|
|
|
+ ctx.TellNext(message, protocol.False)
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (j *FilterJavascriptNode) processError(ctx ruleEngine.Context, msg *protocol.Message, err error) *protocol.Message {
|
|
|
+ var metaData map[string]interface{}
|
|
|
+ if msg.MetaData != nil {
|
|
|
+ metaData = msg.MetaData
|
|
|
+ }
|
|
|
+ metaData = make(map[string]interface{})
|
|
|
+ metaData["error"] = err.Error()
|
|
|
+
|
|
|
+ return ctx.TransformMessage(msg, msg.Type, msg.Originator, metaData, msg.Data)
|
|
|
+}
|
|
|
+// FilterJavascriptNodeConfig Js 节点配置
|
|
|
+type FilterJavascriptNodeConfig struct {
|
|
|
+ FuncBody string `json:"func_body"`// 函数体代码
|
|
|
+}
|
|
|
+
|
|
|
+func generateRuleNodeScript(funcName string, scriptBody string, args ...string) string {
|
|
|
+ var msgArg, metaDataArg, msgTypArg string
|
|
|
+ if len(args) == 3 {
|
|
|
+ msgArg = args[0]
|
|
|
+ metaDataArg = args[1]
|
|
|
+ msgTypArg = args[2]
|
|
|
+ } else {
|
|
|
+ msgArg = "msg"
|
|
|
+ msgTypArg = "msgType"
|
|
|
+ metaDataArg = "metadata"
|
|
|
+ }
|
|
|
+ jsContent := fmt.Sprintf(jsWrapperPrifixTemplate, funcName,
|
|
|
+ ruleNodeFuncName, ruleNodeFuncName,msgArg, metaDataArg, msgTypArg)
|
|
|
+ return fmt.Sprintf("%s%s%s", jsContent, scriptBody, jsWrapperSuffix)
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|