mirror of
https://gitee.com/XM-GO/PandaX.git
synced 2026-05-05 03:21:30 +08:00
规则链
This commit is contained in:
@@ -2,15 +2,12 @@ package rule_engine
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/sirupsen/logrus"
|
||||
"pandax/pkg/rule_engine/manifest"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
"pandax/pkg/rule_engine/nodes"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ruleChainInstance is rulechain's runtime instance that manage all nodes in this chain,
|
||||
type ruleChainInstance struct {
|
||||
firstRuleNodeId string
|
||||
nodes map[string]nodes.Node
|
||||
@@ -40,37 +37,13 @@ func newInstanceWithManifest(m *manifest.Manifest) (*ruleChainInstance, []error)
|
||||
firstRuleNodeId: m.FirstRuleNodeId,
|
||||
nodes: nodes,
|
||||
}
|
||||
|
||||
for _, edge := range m.Edges {
|
||||
originalNode, found := r.nodes[edge.SourceNodeId]
|
||||
if !found {
|
||||
err := fmt.Errorf("original node '%s' no exist in", originalNode.Name())
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
targetNode, found := r.nodes[edge.TargetNodeId]
|
||||
if !found {
|
||||
err := fmt.Errorf("target node '%s' no exist in rulechain", targetNode.Name())
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
types := make([]string, 0)
|
||||
if _, ok := edge.Properties["lineType"]; !ok {
|
||||
types = append(types, "True")
|
||||
} else {
|
||||
types = strings.Split(edge.Properties["lineType"].(string), "/")
|
||||
}
|
||||
for _, ty := range types {
|
||||
originalNode.AddLinkedNode(ty, targetNode)
|
||||
}
|
||||
}
|
||||
return r, errs
|
||||
}
|
||||
|
||||
// StartRuleChain
|
||||
// StartRuleChain TODO 是否需要添加context
|
||||
func (c *ruleChainInstance) StartRuleChain(context context.Context, message message.Message) error {
|
||||
if node, found := c.nodes[c.firstRuleNodeId]; found {
|
||||
go node.Handle(message)
|
||||
node.Handle(message)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package rule_engine
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
"pandax/pkg/rule_engine/nodes"
|
||||
@@ -12,18 +13,21 @@ func TestNewRuleChainInstance(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, errs := NewRuleChainInstance(buf)
|
||||
instance, errs := NewRuleChainInstance(buf)
|
||||
if len(errs) > 0 {
|
||||
t.Error(errs[0])
|
||||
}
|
||||
|
||||
metadata := message.NewDefaultMetadata(map[string]interface{}{"deviceName": "aa", "namespace": "default", "test": "aa"})
|
||||
msg := message.NewMessageWithDetail("1", nodes.DEVICE, message.EventTelemetryType, map[string]interface{}{"temperature": 60}, metadata)
|
||||
t.Log("开始执行力流程")
|
||||
instance.StartRuleChain(context.Background(), msg)
|
||||
}
|
||||
|
||||
func TestScriptEngine(t *testing.T) {
|
||||
metadata := message.NewDefaultMetadata(map[string]interface{}{"device": "aa"})
|
||||
msg := message.NewMessageWithDetail("1", message.MessageTypeConnectEvent, map[string]interface{}{"aa": 5}, metadata)
|
||||
scriptEngine := nodes.NewScriptEngine()
|
||||
const script = `
|
||||
function Switch(msg, metadata, msgType) {
|
||||
msg := message.NewMessageWithDetail("1", "device", message.EventUpEventType, map[string]interface{}{"aa": 5}, metadata)
|
||||
const baseScript = `
|
||||
function nextRelation(metadata, msg) {
|
||||
return ['one','nine'];
|
||||
}
|
||||
@@ -34,9 +38,9 @@ func TestScriptEngine(t *testing.T) {
|
||||
return ['two'];
|
||||
}
|
||||
return nextRelation(metadata, msg);
|
||||
}
|
||||
`
|
||||
SwitchResults, err := scriptEngine.ScriptOnSwitch(msg, script)
|
||||
scriptEngine := nodes.NewScriptEngine(msg, "Switch", baseScript)
|
||||
SwitchResults, err := scriptEngine.ScriptOnSwitch()
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -46,16 +50,15 @@ func TestScriptEngine(t *testing.T) {
|
||||
|
||||
func TestScriptOnMessage(t *testing.T) {
|
||||
metadata := message.NewDefaultMetadata(map[string]interface{}{"device": "aa"})
|
||||
msg := message.NewMessageWithDetail("1", message.MessageTypeConnectEvent, map[string]interface{}{"aa": 5}, metadata)
|
||||
scriptEngine := nodes.NewScriptEngine()
|
||||
const script = `
|
||||
function Transform(msg, metadata, msgType) {
|
||||
msg := message.NewMessageWithDetail("1", "device", message.EventUpEventType, map[string]interface{}{"aa": 5}, metadata)
|
||||
|
||||
const baseScript = `
|
||||
msg.bb = "33"
|
||||
metadata.event = 55
|
||||
return {msg: msg, metadata: metadata, msgType: msgType};
|
||||
}
|
||||
`
|
||||
ScriptOnMessageResults, err := scriptEngine.ScriptOnMessage(msg, script)
|
||||
scriptEngine := nodes.NewScriptEngine(msg, "Transform", baseScript)
|
||||
ScriptOnMessageResults, err := scriptEngine.ScriptOnMessage()
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
||||
@@ -1,129 +1,121 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "d2cc123c-d0d7-4830-8547-21d5e52b4011",
|
||||
"id": "input",
|
||||
"type": "InputNode",
|
||||
"x": 120,
|
||||
"y": 340,
|
||||
"properties": {
|
||||
"debugMode": false,
|
||||
"status": false
|
||||
},
|
||||
"zIndex": 1013,
|
||||
"x": 300,
|
||||
"y": 200,
|
||||
"properties": {},
|
||||
"text": {
|
||||
"x": 130,
|
||||
"y": 340,
|
||||
"value": "输入"
|
||||
"x": 310,
|
||||
"y": 200,
|
||||
"value": "input"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "6c497a23-ece2-41fa-927d-9e2e9a1c7316",
|
||||
"type": "MyNode",
|
||||
"x": 400,
|
||||
"y": 340,
|
||||
"id": "cf717a24-2917-444f-9927-74a0d486ad7a",
|
||||
"type": "LogNode",
|
||||
"x": 820,
|
||||
"y": 200,
|
||||
"properties": {
|
||||
"debugMode": false,
|
||||
"status": false
|
||||
"name": "log",
|
||||
"script": "function ToString(msg, metadata, msgType) {\n return '\\nIncoming message:\\n' + JSON.stringify(msg) + \n '\\nIncoming metadata:\\n' + JSON.stringify(metadata);\n\n }\n "
|
||||
},
|
||||
"zIndex": 1002,
|
||||
"text": {
|
||||
"x": 410,
|
||||
"y": 340,
|
||||
"value": "测试节点"
|
||||
"x": 830,
|
||||
"y": 200,
|
||||
"value": "log"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "7235c088-73e0-4683-982a-77b0fd31313d",
|
||||
"type": "MyNode",
|
||||
"x": 660,
|
||||
"y": 340,
|
||||
"id": "c56b90cc-64fc-4782-8d9e-b0b24dabc876",
|
||||
"type": "MessageGeneratorNode",
|
||||
"x": 520,
|
||||
"y": 40,
|
||||
"properties": {
|
||||
"debugMode": false,
|
||||
"status": false
|
||||
"name": "ada",
|
||||
"messageCount": 2,
|
||||
"periodSecond": 5,
|
||||
"script": "function Generate(msg, metadata, msgType) {\n var msg = { temp: 42, humidity: 77 };\nvar metadata = { data: 40 };\nvar msgType = \"telemetry\";\n\nreturn { msg: msg, metadata: metadata, msgType: msgType };\n }\n "
|
||||
},
|
||||
"zIndex": 1005,
|
||||
"text": {
|
||||
"x": 670,
|
||||
"y": 340,
|
||||
"value": "测试节点"
|
||||
"x": 530,
|
||||
"y": 40,
|
||||
"value": "generator"
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "b6c8b0c4-1481-40d3-b345-780f96efa909",
|
||||
"type": "bezier-link",
|
||||
"sourceNodeId": "d2cc123c-d0d7-4830-8547-21d5e52b4011",
|
||||
"targetNodeId": "6c497a23-ece2-41fa-927d-9e2e9a1c7316",
|
||||
"id": "ca4c7e4b-2ffa-4f72-83d0-456d9db72add",
|
||||
"type": "node-link",
|
||||
"sourceNodeId": "input",
|
||||
"targetNodeId": "c56b90cc-64fc-4782-8d9e-b0b24dabc876",
|
||||
"startPoint": {
|
||||
"x": 180,
|
||||
"y": 340
|
||||
"x": 350,
|
||||
"y": 200
|
||||
},
|
||||
"endPoint": {
|
||||
"x": 340,
|
||||
"y": 340
|
||||
"x": 460,
|
||||
"y": 40
|
||||
},
|
||||
"properties": {
|
||||
"lineType": "True"
|
||||
},
|
||||
"zIndex": 1003,
|
||||
"properties": {},
|
||||
"pointsList": [
|
||||
{
|
||||
"x": 180,
|
||||
"y": 340
|
||||
"x": 350,
|
||||
"y": 200
|
||||
},
|
||||
{
|
||||
"x": 280,
|
||||
"y": 340
|
||||
"x": 450,
|
||||
"y": 200
|
||||
},
|
||||
{
|
||||
"x": 240,
|
||||
"y": 340
|
||||
"x": 360,
|
||||
"y": 40
|
||||
},
|
||||
{
|
||||
"x": 340,
|
||||
"y": 340
|
||||
"x": 460,
|
||||
"y": 40
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "1e38236e-716b-44e7-8d96-6424f63fdacc",
|
||||
"type": "bezier-link",
|
||||
"sourceNodeId": "6c497a23-ece2-41fa-927d-9e2e9a1c7316",
|
||||
"targetNodeId": "7235c088-73e0-4683-982a-77b0fd31313d",
|
||||
"id": "feeb016c-c52c-48ed-8d2c-fde36439da7d",
|
||||
"type": "node-link",
|
||||
"sourceNodeId": "c56b90cc-64fc-4782-8d9e-b0b24dabc876",
|
||||
"targetNodeId": "cf717a24-2917-444f-9927-74a0d486ad7a",
|
||||
"startPoint": {
|
||||
"x": 460,
|
||||
"y": 340
|
||||
"x": 580,
|
||||
"y": 40
|
||||
},
|
||||
"endPoint": {
|
||||
"x": 600,
|
||||
"y": 340
|
||||
"x": 770,
|
||||
"y": 200
|
||||
},
|
||||
"properties": {
|
||||
"lineType": "Next"
|
||||
"type": "Success"
|
||||
},
|
||||
"text": {
|
||||
"x": 530,
|
||||
"y": 340,
|
||||
"value": "Next"
|
||||
"x": 675,
|
||||
"y": 120,
|
||||
"value": "Success"
|
||||
},
|
||||
"zIndex": 1006,
|
||||
"pointsList": [
|
||||
{
|
||||
"x": 460,
|
||||
"y": 340
|
||||
"x": 580,
|
||||
"y": 40
|
||||
},
|
||||
{
|
||||
"x": 560,
|
||||
"y": 340
|
||||
"x": 680,
|
||||
"y": 40
|
||||
},
|
||||
{
|
||||
"x": 500,
|
||||
"y": 340
|
||||
"x": 670,
|
||||
"y": 200
|
||||
},
|
||||
{
|
||||
"x": 600,
|
||||
"y": 340
|
||||
"x": 770,
|
||||
"y": 200
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,20 +3,39 @@ package message
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sirupsen/logrus"
|
||||
"time"
|
||||
)
|
||||
|
||||
//消息类型
|
||||
const (
|
||||
EventConnectType = "connect"
|
||||
EventDisConnectType = "disconnect"
|
||||
EventUpEventType = "event"
|
||||
EventAlarmType = "alarm"
|
||||
EventTelemetryType = "telemetry"
|
||||
EventAttributesType = "attributes"
|
||||
)
|
||||
|
||||
// 数据类型Originator
|
||||
const (
|
||||
DEVICE = "DEVICE"
|
||||
GATEWAY = "GATEWAY"
|
||||
)
|
||||
|
||||
// Message ...
|
||||
type Message interface {
|
||||
GetId() string
|
||||
GetTs() time.Time
|
||||
GetOriginator() string
|
||||
GetUserId() string
|
||||
GetType() string
|
||||
GetMsg() map[string]interface{}
|
||||
GetMsgLogs() []MesLog
|
||||
GetMetadata() Metadata
|
||||
GetAllMap() map[string]interface{} //msg 和 Metadata的合并
|
||||
SetType(string)
|
||||
SetMsg(map[string]interface{})
|
||||
SetOriginator(string)
|
||||
SetUserId(string)
|
||||
SetMetadata(Metadata)
|
||||
MarshalBinary() ([]byte, error)
|
||||
}
|
||||
@@ -29,58 +48,69 @@ type Metadata interface {
|
||||
GetValues() map[string]interface{}
|
||||
}
|
||||
|
||||
// Predefined message types
|
||||
const (
|
||||
EventConnectType = "connect"
|
||||
EventDisConnectType = "disconnect"
|
||||
EventUpEventType = "event"
|
||||
EventAlarmType = "alarm"
|
||||
EventTelemetryType = "telemetry"
|
||||
EventAttributesType = "attributes"
|
||||
)
|
||||
|
||||
// NewMessage ...
|
||||
func NewMessage() Message {
|
||||
return &defaultMessage{
|
||||
id: uuid.New().String(),
|
||||
ts: time.Now(),
|
||||
msg: map[string]interface{}{},
|
||||
mesLog: make([]MesLog, 0),
|
||||
Id: uuid.New().String(),
|
||||
Ts: time.Now(),
|
||||
Msg: map[string]interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
type defaultMessage struct {
|
||||
id string //uuid
|
||||
ts time.Time //时间戳
|
||||
msgType string //消息类型, attributes(参数),telemetry(遥测),Connect连接事件
|
||||
originator string //数据发布者 设备 规则链
|
||||
userId string //客户Id UUID
|
||||
deviceId string //设备Id UUID
|
||||
msg map[string]interface{} //数据 数据结构JSON 设备原始数据 msg
|
||||
metadata Metadata //消息的元数据 包括,设备名称,设备类型,命名空间,时间戳等
|
||||
mesLog []MesLog
|
||||
Id string //uuid 消息Id
|
||||
Ts time.Time //时间戳
|
||||
MsgType string //消息类型, attributes(参数),telemetry(遥测),Connect连接事件
|
||||
Originator string //数据发布者 设备 规则链
|
||||
UserId string //客户Id UUID 设备发布人
|
||||
Msg map[string]interface{} //数据 数据结构JSON 设备原始数据 msg
|
||||
Metadata Metadata //消息的元数据 包括,设备名称,设备类型,命名空间,时间戳等
|
||||
}
|
||||
|
||||
// NewMessageWithDetail ...
|
||||
func NewMessageWithDetail(originator string, messageType string, msg map[string]interface{}, metadata Metadata) Message {
|
||||
func NewMessageWithDetail(userId, originator string, messageType string, msg map[string]interface{}, metadata Metadata) Message {
|
||||
return &defaultMessage{
|
||||
originator: originator,
|
||||
msgType: messageType,
|
||||
msg: msg,
|
||||
metadata: metadata,
|
||||
mesLog: make([]MesLog, 0),
|
||||
Id: uuid.New().String(),
|
||||
Ts: time.Now(),
|
||||
UserId: userId,
|
||||
Originator: originator,
|
||||
MsgType: messageType,
|
||||
Msg: msg,
|
||||
Metadata: metadata,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *defaultMessage) GetOriginator() string { return t.originator }
|
||||
func (t *defaultMessage) GetType() string { return t.msgType }
|
||||
func (t *defaultMessage) GetMsg() map[string]interface{} { return t.msg }
|
||||
func (t *defaultMessage) GetMsgLogs() []MesLog { return t.mesLog }
|
||||
func (t *defaultMessage) GetMetadata() Metadata { return t.metadata }
|
||||
func (t *defaultMessage) SetType(msgType string) { t.msgType = msgType }
|
||||
func (t *defaultMessage) SetMsg(msg map[string]interface{}) { t.msg = msg }
|
||||
func (t *defaultMessage) SetOriginator(originator string) { t.originator = originator }
|
||||
func (t *defaultMessage) SetMetadata(metadata Metadata) { t.metadata = metadata }
|
||||
func (t *defaultMessage) GetId() string { return t.Id }
|
||||
func (t *defaultMessage) GetTs() time.Time { return t.Ts }
|
||||
func (t *defaultMessage) GetOriginator() string { return t.Originator }
|
||||
func (t *defaultMessage) GetUserId() string { return t.UserId }
|
||||
func (t *defaultMessage) GetType() string { return t.MsgType }
|
||||
func (t *defaultMessage) GetMsg() map[string]interface{} { return t.Msg }
|
||||
func (t *defaultMessage) GetMetadata() Metadata { return t.Metadata }
|
||||
func (t *defaultMessage) GetAllMap() map[string]interface{} {
|
||||
data := make(map[string]interface{})
|
||||
for msgKey, msgValue := range t.GetMsg() {
|
||||
for metaKey, metaValue := range t.GetMetadata().GetValues() {
|
||||
if msgKey == metaKey {
|
||||
data[msgKey] = metaValue
|
||||
} else {
|
||||
if _, ok := data[msgKey]; !ok {
|
||||
data[msgKey] = msgValue
|
||||
}
|
||||
if _, ok := data[metaKey]; !ok {
|
||||
data[metaKey] = metaValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
func (t *defaultMessage) SetType(msgType string) { t.MsgType = msgType }
|
||||
func (t *defaultMessage) SetMsg(msg map[string]interface{}) { t.Msg = msg }
|
||||
func (t *defaultMessage) SetOriginator(originator string) { t.Originator = originator }
|
||||
func (t *defaultMessage) SetUserId(userId string) { t.UserId = userId }
|
||||
func (t *defaultMessage) SetMetadata(metadata Metadata) { t.Metadata = metadata }
|
||||
|
||||
func (t *defaultMessage) MarshalBinary() ([]byte, error) {
|
||||
return json.Marshal(t)
|
||||
}
|
||||
@@ -112,7 +142,7 @@ func (t *defaultMetadata) Keys() []string {
|
||||
|
||||
func (t *defaultMetadata) GetKeyValue(key string) interface{} {
|
||||
if _, found := t.values[key]; !found {
|
||||
logrus.Fatalf("no key '%s' in metadata", key)
|
||||
return nil
|
||||
}
|
||||
return t.values[key]
|
||||
}
|
||||
@@ -127,11 +157,3 @@ func (t *defaultMetadata) GetValues() map[string]interface{} {
|
||||
func (t *defaultMetadata) SetValues(values map[string]interface{}) {
|
||||
t.values = values
|
||||
}
|
||||
|
||||
type MesLog struct {
|
||||
NodeName string `json:"nodeName"`
|
||||
startTime time.Time `json:"startTime"`
|
||||
endTime time.Time `json:"endTime"`
|
||||
result string `json:"result"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"pandax/pkg/rule_engine/message"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
)
|
||||
|
||||
const ClearAlarmNodeName = "ClearAlarmNode"
|
||||
@@ -13,17 +11,13 @@ type clearAlarmNodeFactory struct{}
|
||||
|
||||
type clearAlarmNode struct {
|
||||
bareNode
|
||||
DetailBuilderScript string `json:"detailBuilderScript" yaml:"detailBuilderScript"`
|
||||
AlarmType string `json:"alarmType" yaml:"alarmType"`
|
||||
AlarmSeverity string `json:"alarmSeverity" yaml:"alarmSeverity"`
|
||||
Propagate string `json:"propagate" yaml:"propagate"`
|
||||
AlarmStartTime *time.Time `json:"alarmStartTime" yaml:"alarmStartTime"`
|
||||
AlarmEndTime *time.Time `json:"alarmEndTime" yaml:"alarmEndTime"`
|
||||
Script string `json:"script" yaml:"script"`
|
||||
AlarmType string `json:"alarmType" yaml:"alarmType"`
|
||||
}
|
||||
|
||||
func (f clearAlarmNodeFactory) Name() string { return ClearAlarmNodeName }
|
||||
func (f clearAlarmNodeFactory) Category() string { return NODE_CATEGORY_ACTION }
|
||||
func (f clearAlarmNodeFactory) Labels() []string { return []string{"Created", "Updated", "Failure"} }
|
||||
func (f clearAlarmNodeFactory) Labels() []string { return []string{"Cleared", "Failure"} }
|
||||
func (f clearAlarmNodeFactory) Create(id string, meta Metadata) (Node, error) {
|
||||
node := &clearAlarmNode{
|
||||
bareNode: newBareNode(f.Name(), id, meta, f.Labels()),
|
||||
@@ -33,5 +27,16 @@ func (f clearAlarmNodeFactory) Create(id string, meta Metadata) (Node, error) {
|
||||
|
||||
func (n *clearAlarmNode) Handle(msg message.Message) error {
|
||||
logrus.Infof("%s handle message '%s'", n.Name(), msg.GetType())
|
||||
cleared := n.GetLinkedNode("Cleared")
|
||||
failure := n.GetLinkedNode("Failure")
|
||||
|
||||
scriptEngine := NewScriptEngine(msg, "Details", n.Script)
|
||||
details, err := scriptEngine.ScriptAlarmDetails()
|
||||
if err != nil {
|
||||
return failure.Handle(msg)
|
||||
}
|
||||
// TODO 编写创建告警信息
|
||||
logrus.Info(details)
|
||||
cleared.Handle(msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
)
|
||||
|
||||
type createAlarmNode struct {
|
||||
bareNode
|
||||
DetailBuilderScript string `json:"detailBuilderScript" yaml:"detailBuilderScript"`
|
||||
AlarmType string `json:"alarmType" yaml:"alarmType"`
|
||||
AlarmSeverity string `json:"alarmSeverity" yaml:"alarmSeverity"`
|
||||
Propagate string `json:"propagate" yaml:"propagate"`
|
||||
AlarmStartTime string `json:"alarmStartTime" yaml:"alarmStartTime"`
|
||||
AlarmEndTime string `json:"alarmEndTime" yaml:"alarmEndTime"`
|
||||
Script string `json:"script" yaml:"script"`
|
||||
AlarmType string `json:"alarmType" yaml:"alarmType"`
|
||||
AlarmSeverity int64 `json:"alarmSeverity" yaml:"alarmSeverity"`
|
||||
Propagate string `json:"propagate" yaml:"propagate"`
|
||||
/* AlarmStartTime string `json:"alarmStartTime" yaml:"alarmStartTime"`
|
||||
AlarmEndTime string `json:"alarmEndTime" yaml:"alarmEndTime"`*/
|
||||
}
|
||||
|
||||
type createAlarmNodeFactory struct{}
|
||||
@@ -33,11 +31,19 @@ func (n *createAlarmNode) Handle(msg message.Message) error {
|
||||
logrus.Infof("%s handle message '%s'", n.Name(), msg.GetType())
|
||||
|
||||
node1 := n.GetLinkedNode("Created")
|
||||
node2 := n.GetLinkedNode("Updated")
|
||||
//node2 := n.GetLinkedNode("Updated")
|
||||
node3 := n.GetLinkedNode("Failure")
|
||||
if node1 == nil || node2 == nil || node3 == nil {
|
||||
return fmt.Errorf("no valid label linked node in %s", n.Name())
|
||||
|
||||
scriptEngine := NewScriptEngine(msg, "Details", n.Script)
|
||||
details, err := scriptEngine.ScriptAlarmDetails()
|
||||
if err != nil {
|
||||
if node3 != nil {
|
||||
return node3.Handle(msg)
|
||||
}
|
||||
}
|
||||
// TODO 创建告警
|
||||
logrus.Info(details)
|
||||
node1.Handle(msg)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ const DelayNodeName = "DelayNode"
|
||||
|
||||
type delayNode struct {
|
||||
bareNode
|
||||
PeriodTs int `json:"periodTs" yaml:"periodTs" jpath:"periodTs"`
|
||||
MaxPendingMessages int `json:"maxPendingMessages" yaml:"maxPendingMessages" jpath:"maxPendingMessages"`
|
||||
PeriodTs int `json:"periodTs" yaml:"periodTs" jpath:"periodTs"` //周期时间
|
||||
MaxPendingMessages int `json:"maxPendingMessages" yaml:"maxPendingMessages" jpath:"maxPendingMessages"` //最大等待消息数
|
||||
messageQueue []message.Message `jpath:"-"`
|
||||
delayTimer *time.Timer `jpath:"-"`
|
||||
lock sync.Mutex `jpath:"-"`
|
||||
@@ -48,7 +48,7 @@ func (n *delayNode) Handle(msg message.Message) error {
|
||||
if n.delayTimer == nil {
|
||||
n.messageQueue = append(n.messageQueue, msg)
|
||||
n.delayTimer = time.NewTimer(time.Duration(n.PeriodTs) * time.Second)
|
||||
// start timecallback goroutine
|
||||
|
||||
go func(n *delayNode) error {
|
||||
defer n.delayTimer.Stop()
|
||||
for {
|
||||
@@ -64,7 +64,6 @@ func (n *delayNode) Handle(msg message.Message) error {
|
||||
}(n)
|
||||
return nil
|
||||
}
|
||||
// the delay timer had already been created, just queue message
|
||||
n.lock.Lock()
|
||||
defer n.lock.Unlock()
|
||||
if len(n.messageQueue) == n.MaxPendingMessages {
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/sirupsen/logrus"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
"time"
|
||||
)
|
||||
|
||||
type messageGeneratorNode struct {
|
||||
bareNode
|
||||
DetailBuilderScript string `json:"detail_builder_script" yaml:"detail_builder_script"`
|
||||
FrequenceInSecond int32 `json:"frequency" yaml:"frequency"`
|
||||
Script string `json:"script" yaml:"script"`
|
||||
PeriodSecond int64 `json:"periodSecond" yaml:"periodSecond"` //周期
|
||||
MessageCount int64 `json:"messageCount" yaml:"messageCount"`
|
||||
}
|
||||
|
||||
type messageGeneratorNodeFactory struct{}
|
||||
|
||||
func (f messageGeneratorNodeFactory) Name() string { return "GeneratorNode" }
|
||||
func (f messageGeneratorNodeFactory) Name() string { return "MessageGeneratorNode" }
|
||||
func (f messageGeneratorNodeFactory) Category() string { return NODE_CATEGORY_ACTION }
|
||||
func (f messageGeneratorNodeFactory) Labels() []string { return []string{"Created", "Updated"} }
|
||||
func (f messageGeneratorNodeFactory) Labels() []string { return []string{"Success", "Failure"} }
|
||||
func (f messageGeneratorNodeFactory) Create(id string, meta Metadata) (Node, error) {
|
||||
node := &messageGeneratorNode{
|
||||
bareNode: newBareNode(f.Name(), id, meta, f.Labels()),
|
||||
@@ -27,11 +28,36 @@ func (f messageGeneratorNodeFactory) Create(id string, meta Metadata) (Node, err
|
||||
func (n *messageGeneratorNode) Handle(msg message.Message) error {
|
||||
logrus.Infof("%s handle message '%s'", n.Name(), msg.GetType())
|
||||
|
||||
createdLabelNode := n.GetLinkedNode("Created")
|
||||
updatedLabelNode := n.GetLinkedNode("Updated")
|
||||
if createdLabelNode == nil || updatedLabelNode == nil {
|
||||
return fmt.Errorf("no valid label linked node in %s", n.Name())
|
||||
}
|
||||
successLabelNode := n.GetLinkedNode("Success")
|
||||
failureLabelNode := n.GetLinkedNode("Failure")
|
||||
|
||||
ticker := time.NewTicker(time.Duration(n.PeriodSecond) * time.Second)
|
||||
count := 0
|
||||
|
||||
go func() {
|
||||
for {
|
||||
<-ticker.C
|
||||
count++
|
||||
if int64(count) == n.MessageCount {
|
||||
ticker.Stop()
|
||||
return
|
||||
}
|
||||
scriptEngine := NewScriptEngine(msg, "Generate", n.Script)
|
||||
generate, err := scriptEngine.ScriptGenerate()
|
||||
if err != nil {
|
||||
if failureLabelNode != nil {
|
||||
go failureLabelNode.Handle(msg)
|
||||
}
|
||||
return
|
||||
}
|
||||
msg.SetMsg(generate["msg"].(map[string]interface{}))
|
||||
msg.SetType(generate["msgType"].(string))
|
||||
msg.SetMetadata(message.NewDefaultMetadata(generate["metadata"].(map[string]interface{})))
|
||||
if successLabelNode != nil {
|
||||
go successLabelNode.Handle(msg)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"pandax/apps/visual/entity"
|
||||
"pandax/apps/visual/services"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
)
|
||||
|
||||
@@ -27,15 +27,31 @@ func (n *logNode) Handle(msg message.Message) error {
|
||||
successLableNode := n.GetLinkedNode("Success")
|
||||
failureLableNode := n.GetLinkedNode("Failure")
|
||||
|
||||
scriptEngine := NewScriptEngine()
|
||||
logMessage, err := scriptEngine.ScriptToString(msg, n.Script)
|
||||
|
||||
if successLableNode == nil || failureLableNode == nil {
|
||||
return fmt.Errorf("no valid label linked node in %s", n.Name())
|
||||
}
|
||||
scriptEngine := NewScriptEngine(msg, "ToString", n.Script)
|
||||
logMessage, err := scriptEngine.ScriptToString()
|
||||
if err != nil {
|
||||
return failureLableNode.Handle(msg)
|
||||
if failureLableNode != nil {
|
||||
return failureLableNode.Handle(msg)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
log.Println(logMessage)
|
||||
return successLableNode.Handle(msg)
|
||||
services.VisualRuleChainMsgLogModelDao.Insert(entity.VisualRuleChainMsgLog{
|
||||
MessageId: msg.GetId(),
|
||||
MsgType: msg.GetType(),
|
||||
DeviceName: msg.GetMetadata().GetValues()["deviceName"].(string),
|
||||
Ts: msg.GetTs(),
|
||||
Content: logMessage,
|
||||
})
|
||||
if err != nil {
|
||||
if failureLableNode != nil {
|
||||
return failureLableNode.Handle(msg)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if successLableNode != nil {
|
||||
return successLableNode.Handle(msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"log"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
)
|
||||
|
||||
type MyNode struct {
|
||||
bareNode
|
||||
}
|
||||
|
||||
type myNodeFactory struct{}
|
||||
|
||||
func (f myNodeFactory) Name() string { return "MyNode" }
|
||||
func (f myNodeFactory) Category() string { return NODE_CATEGORY_ACTION }
|
||||
func (f myNodeFactory) Labels() []string { return []string{"Next", "Next2"} }
|
||||
func (f myNodeFactory) Create(id string, meta Metadata) (Node, error) {
|
||||
node := &MyNode{
|
||||
bareNode: newBareNode(f.Name(), id, meta, f.Labels()),
|
||||
}
|
||||
return decodePath(meta, node)
|
||||
}
|
||||
|
||||
func (n *MyNode) Handle(msg message.Message) error {
|
||||
nextLableNode := n.GetLinkedNode("Next")
|
||||
|
||||
log.Println(nextLableNode.Name())
|
||||
return nil
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
)
|
||||
|
||||
@@ -22,13 +21,33 @@ func (f saveAttributesNodeFactory) Create(id string, meta Metadata) (Node, error
|
||||
}
|
||||
|
||||
func (n *SaveAttributesNode) Handle(msg message.Message) error {
|
||||
successLableNode := n.GetLinkedNode("Success")
|
||||
failureLableNode := n.GetLinkedNode("Failure")
|
||||
if successLableNode == nil || failureLableNode == nil {
|
||||
return fmt.Errorf("no valid label linked node in %s", n.Name())
|
||||
successLabelNode := n.GetLinkedNode("Success")
|
||||
failureLabelNode := n.GetLinkedNode("Failure")
|
||||
if msg.GetType() != message.EventAttributesType {
|
||||
if failureLabelNode != nil {
|
||||
return failureLabelNode.Handle(msg)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if msg.GetType() != "POST_ATTRIBUTES_REQUEST" {
|
||||
return failureLableNode.Handle(msg)
|
||||
//deviceName := msg.GetMetadata().GetValues()["deviceName"].(string)
|
||||
//namespace := msg.GetMetadata().GetValues()["namespace"].(string)
|
||||
//marshal, err := json.Marshal(msg.GetMsg())
|
||||
|
||||
//if err != nil {
|
||||
// if failureLabelNode != nil {
|
||||
// return failureLabelNode.Handle(msg)
|
||||
// } else {
|
||||
// return nil
|
||||
// }
|
||||
//}
|
||||
|
||||
// todo 添加设备上报参数
|
||||
|
||||
if successLabelNode != nil {
|
||||
return successLabelNode.Handle(msg)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -19,7 +19,24 @@ func (f saveTimeSeriesNodeFactory) Create(id string, meta Metadata) (Node, error
|
||||
|
||||
func (n *SaveTimeSeriesNode) Handle(msg message.Message) error {
|
||||
successLableNode := n.GetLinkedNode("Success")
|
||||
//failureLableNode := n.GetLinkedNode("Failure")
|
||||
failureLableNode := n.GetLinkedNode("Failure")
|
||||
if msg.GetType() != message.EventTelemetryType {
|
||||
if failureLableNode != nil {
|
||||
return failureLableNode.Handle(msg)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
/*deviceName := msg.GetMetadata().GetValues()["deviceName"].(string)
|
||||
namespace := msg.GetMetadata().GetValues()["namespace"].(string)
|
||||
marshal, err := json.Marshal(msg.GetMsg())*/
|
||||
|
||||
// todo 添加设备上报遥测
|
||||
|
||||
if successLableNode != nil {
|
||||
return successLableNode.Handle(msg)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return successLableNode.Handle(msg)
|
||||
}
|
||||
|
||||
@@ -1,17 +1,26 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/XM-GO/PandaKit/httpclient"
|
||||
"github.com/sirupsen/logrus"
|
||||
"net/url"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
"time"
|
||||
)
|
||||
|
||||
type externalDingNode struct {
|
||||
bareNode
|
||||
WebHook string `json:"webHook" yaml:"webHook"`
|
||||
Secret string `json:"secret"`
|
||||
MsgType string `json:"msgType" yaml:"msgType"`
|
||||
Content string `json:"content" yaml:"content"`
|
||||
IsAtAll bool `json:"isAtAll" yaml:"isAtAll"`
|
||||
atMobiles []string `json:"atMobiles" yaml:"atMobiles"`
|
||||
AtMobiles []string `json:"atMobiles" yaml:"atMobiles"`
|
||||
}
|
||||
|
||||
type externalDingNodeFactory struct{}
|
||||
@@ -29,5 +38,47 @@ func (f externalDingNodeFactory) Create(id string, meta Metadata) (Node, error)
|
||||
func (n *externalDingNode) Handle(msg message.Message) error {
|
||||
logrus.Infof("%s handle message '%s'", n.Name(), msg.GetType())
|
||||
|
||||
successLabelNode := n.GetLinkedNode("Success")
|
||||
failureLabelNode := n.GetLinkedNode("Failure")
|
||||
//获取消息
|
||||
template, err := ParseTemplate(n.Content, msg.GetAllMap())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sendData := map[string]interface{}{
|
||||
"msgtype": "text",
|
||||
"text": map[string]string{"content": template},
|
||||
}
|
||||
if n.IsAtAll {
|
||||
sendData["at"] = map[string]interface{}{"isAtAll": n.IsAtAll}
|
||||
} else {
|
||||
sendData["at"] = map[string]interface{}{"atMobiles": n.AtMobiles}
|
||||
}
|
||||
marshal, _ := json.Marshal(sendData)
|
||||
|
||||
timestamp := time.Now().UnixMilli()
|
||||
sign := getSign(timestamp, n.Secret)
|
||||
|
||||
url := fmt.Sprintf("%s×tamp=%d&sign=%s", n.WebHook, timestamp, sign)
|
||||
|
||||
postJson := httpclient.NewRequest(url).Header("Content-Type", "application/json").PostJson(string(marshal))
|
||||
if postJson.StatusCode != 200 {
|
||||
if failureLabelNode != nil {
|
||||
return failureLabelNode.Handle(msg)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if successLabelNode != nil {
|
||||
return successLabelNode.Handle(msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getSign(timestamp int64, secret string) string {
|
||||
stringToSign := fmt.Sprintf("%d\n%s", timestamp, secret)
|
||||
hash := hmac.New(sha256.New, []byte(secret))
|
||||
hash.Write([]byte(stringToSign))
|
||||
signData := hash.Sum(nil)
|
||||
return url.QueryEscape(base64.StdEncoding.EncodeToString(signData))
|
||||
}
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/Shopify/sarama"
|
||||
"github.com/sirupsen/logrus"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type externalKafkaNode struct {
|
||||
bareNode
|
||||
Server string `json:"server" yaml:"server"`
|
||||
Topic string `json:"topic" yaml:"topic"`
|
||||
KafkaCli string
|
||||
Server string `json:"server" yaml:"server"` //kafka集群 "10.130.138.164:9092,10.130.138.165:9093"
|
||||
Topic string `json:"topic" yaml:"topic"` //topic
|
||||
KeyPattern string `json:"keyPattern" yaml:"keyPattern"` //metadataKey or messageKey
|
||||
ProducesBatchSize int64 `json:"producesBatchSize" yaml:"producesBatchSize"`
|
||||
OtherProperties map[string]interface{} `json:"otherProperties"` //发送的其他参数
|
||||
KafkaCli sarama.SyncProducer
|
||||
}
|
||||
|
||||
type externalKafkaNodeFactory struct{}
|
||||
@@ -21,11 +28,58 @@ func (f externalKafkaNodeFactory) Create(id string, meta Metadata) (Node, error)
|
||||
node := &externalKafkaNode{
|
||||
bareNode: newBareNode(f.Name(), id, meta, f.Labels()),
|
||||
}
|
||||
return decodePath(meta, node)
|
||||
_, err := decodePath(meta, node)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
config := sarama.NewConfig()
|
||||
config.Producer.Return.Successes = true
|
||||
config.Producer.Timeout = 5 * time.Second
|
||||
config.Producer.MaxMessageBytes = int(node.ProducesBatchSize)
|
||||
p, err := sarama.NewSyncProducer(strings.Split(node.Server, ","), config)
|
||||
if err != nil {
|
||||
logrus.Errorf("sarama.NewSyncProducer err, message=%s \n", err)
|
||||
return node, err
|
||||
}
|
||||
node.KafkaCli = p
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (n *externalKafkaNode) Handle(msg message.Message) error {
|
||||
logrus.Infof("%s handle message '%s'", n.Name(), msg.GetType())
|
||||
defer n.KafkaCli.Close()
|
||||
successLabelNode := n.GetLinkedNode("Success")
|
||||
failureLabelNode := n.GetLinkedNode("Failure")
|
||||
value := sarama.ByteEncoder("")
|
||||
if n.KeyPattern == "metadataKey" {
|
||||
marshal, err := json.Marshal(msg.GetMetadata().GetValues())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value = marshal
|
||||
} else {
|
||||
marshal, err := json.Marshal(msg.GetMsg())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value = marshal
|
||||
}
|
||||
|
||||
kafkaM := &sarama.ProducerMessage{
|
||||
Topic: n.Topic,
|
||||
Value: value,
|
||||
}
|
||||
_, _, err := n.KafkaCli.SendMessage(kafkaM)
|
||||
if err != nil {
|
||||
if failureLabelNode != nil {
|
||||
return failureLabelNode.Handle(msg)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if successLabelNode != nil {
|
||||
return successLabelNode.Handle(msg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ import (
|
||||
type externalMqttNode struct {
|
||||
bareNode
|
||||
TopicPattern string `json:"topicPattern"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Host string `json:"host"`
|
||||
Port string `json:"port"`
|
||||
ConnectTimeoutSec int `json:"connectTimeoutSec"`
|
||||
@@ -28,38 +30,55 @@ func (f externalMqttNodeFactory) Name() string { return "MqttNode" }
|
||||
func (f externalMqttNodeFactory) Category() string { return NODE_CATEGORY_EXTERNAL }
|
||||
func (f externalMqttNodeFactory) Labels() []string { return []string{"Success", "Failure"} }
|
||||
func (f externalMqttNodeFactory) Create(id string, meta Metadata) (Node, error) {
|
||||
|
||||
node := &externalMqttNode{
|
||||
bareNode: newBareNode(f.Name(), id, meta, f.Labels()),
|
||||
}
|
||||
_, err := decodePath(meta, node)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
broker := fmt.Sprintf("tcp://%s:%s", node.Host, node.Port)
|
||||
opts := mqtt.NewClientOptions().AddBroker(broker)
|
||||
opts.SetClientID(node.ClientId)
|
||||
if node.ClientId != "" {
|
||||
opts.SetClientID(node.ClientId)
|
||||
}
|
||||
opts.SetCleanSession(node.CleanSession)
|
||||
opts.SetConnectTimeout(time.Duration(node.ConnectTimeoutSec) * time.Second)
|
||||
if node.Username != "" {
|
||||
opts.SetUsername(node.Username)
|
||||
}
|
||||
if node.Password != "" {
|
||||
opts.SetPassword(node.Password)
|
||||
}
|
||||
node.MqttCli = mqtt.NewClient(opts)
|
||||
|
||||
if token := node.MqttCli.Connect(); token.Wait() && token.Error() != nil {
|
||||
logrus.WithError(token.Error())
|
||||
return nil, token.Error()
|
||||
}
|
||||
return decodePath(meta, node)
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (n *externalMqttNode) Handle(msg message.Message) error {
|
||||
logrus.Infof("%s handle message '%s'", n.Name(), msg.GetType())
|
||||
|
||||
defer n.MqttCli.Disconnect(1000)
|
||||
successLabelNode := n.GetLinkedNode("Success")
|
||||
failureLabelNode := n.GetLinkedNode("Failure")
|
||||
topic := n.TopicPattern //need fix add msg.metadata in it
|
||||
sendmqttmsg, err := json.Marshal(msg.GetMsg())
|
||||
if err != nil {
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
token := n.MqttCli.Publish(topic, 1, false, sendmqttmsg)
|
||||
if token.Wait() && token.Error() != nil {
|
||||
fmt.Println(token.Error())
|
||||
return failureLabelNode.Handle(msg)
|
||||
if failureLabelNode != nil {
|
||||
return failureLabelNode.Handle(msg)
|
||||
} else {
|
||||
return token.Error()
|
||||
}
|
||||
}
|
||||
return successLabelNode.Handle(msg)
|
||||
if successLabelNode != nil {
|
||||
return successLabelNode.Handle(msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -37,12 +37,23 @@ func (f externalNatsNodeFactory) Create(id string, meta Metadata) (Node, error)
|
||||
|
||||
func (n *externalNatsNode) Handle(msg message.Message) error {
|
||||
logrus.Infof("%s handle message '%s'", n.Name(), msg.GetType())
|
||||
defer n.client.Close()
|
||||
successLabelNode := n.GetLinkedNode("Success")
|
||||
failureLabelNode := n.GetLinkedNode("Failure")
|
||||
err := n.client.Publish(n.Subject, []byte(n.Body))
|
||||
template, err := ParseTemplate(n.Body, msg.GetAllMap())
|
||||
if err != nil {
|
||||
n.client.Close()
|
||||
return failureLabelNode.Handle(msg)
|
||||
return err
|
||||
}
|
||||
return successLabelNode.Handle(msg)
|
||||
err = n.client.Publish(n.Subject, []byte(template))
|
||||
if err != nil {
|
||||
if failureLabelNode != nil {
|
||||
return failureLabelNode.Handle(msg)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if successLabelNode != nil {
|
||||
return successLabelNode.Handle(msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/XM-GO/PandaKit/httpclient"
|
||||
"github.com/sirupsen/logrus"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
)
|
||||
@@ -9,7 +12,7 @@ type externalRestapiNode struct {
|
||||
bareNode
|
||||
RestEndpointUrlPattern string `json:"restEndpointUrlPattern" yaml:"restEndpointUrlPattern"`
|
||||
RequestMethod string `json:"requestMethod" yaml:"requestMethod"`
|
||||
headers map[string]string `json:"headers" yaml:"headers"`
|
||||
Headers map[string]string `json:"headers" yaml:"headers"`
|
||||
}
|
||||
|
||||
type externalRestapiNodeFactory struct{}
|
||||
@@ -26,6 +29,73 @@ func (f externalRestapiNodeFactory) Create(id string, meta Metadata) (Node, erro
|
||||
|
||||
func (n *externalRestapiNode) Handle(msg message.Message) error {
|
||||
logrus.Infof("%s handle message '%s'", n.Name(), msg.GetType())
|
||||
|
||||
successLableNode := n.GetLinkedNode("Success")
|
||||
failureLableNode := n.GetLinkedNode("Failure")
|
||||
if n.RequestMethod == "GET" {
|
||||
resp := httpclient.NewRequest(n.RestEndpointUrlPattern).Get()
|
||||
if resp.StatusCode != 200 {
|
||||
return errors.New("网络请求失败")
|
||||
}
|
||||
var response map[string]interface{}
|
||||
err := json.Unmarshal(resp.Body, &response)
|
||||
if err != nil && failureLableNode != nil {
|
||||
return failureLableNode.Handle(msg)
|
||||
} else {
|
||||
if successLableNode != nil {
|
||||
metadata := msg.GetMetadata()
|
||||
for key, value := range response {
|
||||
metadata.SetKeyValue(key, value)
|
||||
}
|
||||
msg.SetMetadata(metadata)
|
||||
return successLableNode.Handle(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
if n.RequestMethod == "POST" {
|
||||
binary, _ := msg.MarshalBinary()
|
||||
req := httpclient.NewRequest(n.RestEndpointUrlPattern)
|
||||
for key, value := range n.Headers {
|
||||
req.Header(key, value)
|
||||
}
|
||||
resp := req.PostJson(string(binary))
|
||||
if resp.StatusCode != 200 {
|
||||
if failureLableNode != nil {
|
||||
return failureLableNode.Handle(msg)
|
||||
}
|
||||
} else {
|
||||
if successLableNode != nil {
|
||||
return successLableNode.Handle(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
/*if n.RequestMethod == "PUT" {
|
||||
binary, _ := msg.MarshalBinary()
|
||||
req := httpclient.NewRequest(n.RestEndpointUrlPattern)
|
||||
for key,value := range n.Headers {
|
||||
req.Header(key,value)
|
||||
}
|
||||
_, err := http.HttpPut(n.RestEndpointUrlPattern, n.Headers, nil, binary)
|
||||
if err != nil {
|
||||
if failureLableNode != nil {
|
||||
return failureLableNode.Handle(msg)
|
||||
}
|
||||
} else {
|
||||
if successLableNode != nil {
|
||||
return successLableNode.Handle(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
if n.RequestMethod == "DELETE" {
|
||||
_, err := http.HttpDelete(n.RestEndpointUrlPattern)
|
||||
if err != nil {
|
||||
if failureLableNode != nil {
|
||||
return failureLableNode.Handle(msg)
|
||||
}
|
||||
} else {
|
||||
if successLableNode != nil {
|
||||
return successLableNode.Handle(msg)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"pandax/apps/visual/services"
|
||||
"pandax/pkg/rule_engine/manifest"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type externalRuleChainNode struct {
|
||||
@@ -13,13 +18,11 @@ type externalRuleChainNode struct {
|
||||
type externalRuleChainNodeFactory struct{}
|
||||
|
||||
func (f externalRuleChainNodeFactory) Name() string { return "RuleChainNode" }
|
||||
func (f externalRuleChainNodeFactory) Category() string { return NODE_CATEGORY_EXTERNAL }
|
||||
func (f externalRuleChainNodeFactory) Labels() []string { return []string{"Success", "Failure"} }
|
||||
func (f externalRuleChainNodeFactory) Category() string { return NODE_CATEGORY_FLOWS }
|
||||
func (f externalRuleChainNodeFactory) Labels() []string { return []string{} }
|
||||
func (f externalRuleChainNodeFactory) Create(id string, meta Metadata) (Node, error) {
|
||||
labels := []string{"Success", "Failure"}
|
||||
|
||||
node := &externalRuleChainNode{
|
||||
bareNode: newBareNode(f.Name(), id, meta, labels),
|
||||
bareNode: newBareNode(f.Name(), id, meta, f.Labels()),
|
||||
}
|
||||
|
||||
return decodePath(meta, node)
|
||||
@@ -27,6 +30,21 @@ func (f externalRuleChainNodeFactory) Create(id string, meta Metadata) (Node, er
|
||||
|
||||
func (n *externalRuleChainNode) Handle(msg message.Message) error {
|
||||
logrus.Infof("%s handle message '%s'", n.Name(), msg.GetType())
|
||||
|
||||
data := services.VisualRuleChainModelDao.FindOne(n.RuleId)
|
||||
if data == nil {
|
||||
return errors.New(fmt.Sprintf("节点 %s ,获取规则链失败", n.Name()))
|
||||
}
|
||||
m, err := manifest.New([]byte(data.RuleDataJson))
|
||||
if err != nil {
|
||||
logrus.WithError(err).Errorf("invalidi manifest file")
|
||||
return err
|
||||
}
|
||||
nodes, err := GetNodes(m)
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("节点 %s ,构建节点失败", n.Name()))
|
||||
}
|
||||
if node, found := nodes[m.FirstRuleNodeId]; found {
|
||||
go node.Handle(msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/sirupsen/logrus"
|
||||
"net/smtp"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
"strings"
|
||||
|
||||
"github.com/jordan-wright/email"
|
||||
)
|
||||
|
||||
type externalSendEmailNode struct {
|
||||
bareNode
|
||||
From string `json:"from" yaml:"from"`
|
||||
To string `json:"to" yaml:"to"`
|
||||
Cc string `json:"cc" yaml:"cc"`
|
||||
Bcc string `json:"bcc" yaml:"bcc"`
|
||||
Subject string `json:"subject" yaml:"subject"`
|
||||
Body string `json:"body" yaml:"body"`
|
||||
Host string `json:"host"` // 服务器地址
|
||||
Port int `json:"port"` // 服务器端口
|
||||
From string `json:"from"` // 邮箱账号
|
||||
Nickname string `json:"nickname"` // 发件人
|
||||
Secret string `json:"secret"` // 邮箱密码
|
||||
IsSSL bool `json:"isSsl"` // 是否开启ssl
|
||||
|
||||
To string `json:"to"` //收件人
|
||||
Subject string `json:"subject"` //主题
|
||||
Body string `json:"body"` //内容
|
||||
}
|
||||
|
||||
type externalSendEmailNodeFactory struct{}
|
||||
@@ -21,10 +31,14 @@ func (f externalSendEmailNodeFactory) Name() string { return "SendEmailNode"
|
||||
func (f externalSendEmailNodeFactory) Category() string { return NODE_CATEGORY_EXTERNAL }
|
||||
func (f externalSendEmailNodeFactory) Labels() []string { return []string{"Success", "Failure"} }
|
||||
func (f externalSendEmailNodeFactory) Create(id string, meta Metadata) (Node, error) {
|
||||
labels := []string{"Success", "Failure"}
|
||||
|
||||
node := &externalSendEmailNode{
|
||||
bareNode: newBareNode(f.Name(), id, meta, labels),
|
||||
bareNode: newBareNode(f.Name(), id, meta, f.Labels()),
|
||||
/*Host: email.Host,
|
||||
Port: email.Port,
|
||||
Nickname: email.Nickname,
|
||||
Secret: email.Secret,
|
||||
IsSSL: email.IsSSL,*/
|
||||
}
|
||||
return decodePath(meta, node)
|
||||
}
|
||||
@@ -33,19 +47,48 @@ func (n *externalSendEmailNode) Handle(msg message.Message) error {
|
||||
logrus.Infof("%s handle message '%s'", n.Name(), msg.GetType())
|
||||
|
||||
successLabelNode := n.GetLinkedNode("Success")
|
||||
//failureLabelNode := n.GetLinkedNode("Failure")
|
||||
failureLabelNode := n.GetLinkedNode("Failure")
|
||||
|
||||
/*dialer := runtime.NewDialer(runtime.EMAIL)
|
||||
variables := map[string]string{
|
||||
"from": n.From,
|
||||
"to": n.To,
|
||||
"cc": n.Cc,
|
||||
"bcc": n.Bcc,
|
||||
"subject": n.Subject,
|
||||
"body": n.Body,
|
||||
tos := strings.Split(n.To, ",")
|
||||
if tos[len(tos)-1] == "" { // 判断切片的最后一个元素是否为空,为空则移除
|
||||
tos = tos[:len(tos)-1]
|
||||
}
|
||||
if err := dialer.DialAndSend(msg.GetMetadata(), variables); err != nil {
|
||||
return failureLabelNode.Handle(msg)
|
||||
}*/
|
||||
return successLabelNode.Handle(msg)
|
||||
err := n.send(tos, msg)
|
||||
if err != nil {
|
||||
if failureLabelNode != nil {
|
||||
return failureLabelNode.Handle(msg)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if successLabelNode != nil {
|
||||
return successLabelNode.Handle(msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *externalSendEmailNode) send(to []string, msg message.Message) error {
|
||||
|
||||
auth := smtp.PlainAuth("", m.From, m.Secret, m.Host)
|
||||
e := email.NewEmail()
|
||||
if m.Nickname != "" {
|
||||
e.From = fmt.Sprintf("%s <%s>", m.Nickname, m.From)
|
||||
} else {
|
||||
e.From = m.From
|
||||
}
|
||||
e.To = to
|
||||
e.Subject = m.Subject
|
||||
template, err := ParseTemplate(m.Body, msg.GetMetadata().GetValues())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.HTML = []byte(template)
|
||||
hostAddr := fmt.Sprintf("%s:%d", m.Host, m.Port)
|
||||
if m.IsSSL {
|
||||
err = e.SendWithTLS(hostAddr, auth, &tls.Config{ServerName: m.Host})
|
||||
} else {
|
||||
err = e.Send(hostAddr, auth)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -7,6 +7,12 @@ import (
|
||||
|
||||
type externalSendSmsNode struct {
|
||||
bareNode
|
||||
SecretId string `json:"secretId" yaml:"secretId"`
|
||||
SecretKey string `json:"secretKey" yaml:"secretKey"`
|
||||
SdkAppId string `json:"sdkAppId" yaml:"sdkAppId"` //应用Id(腾讯) 或 签名名称(阿里)
|
||||
PhoneNumber string `json:"phoneNumber" yaml:"phoneNumber"` //发送到手机号
|
||||
TemplateId string `json:"templateId" yaml:"templateId"` //短信模板Id
|
||||
TemplateParam map[string]interface{} `json:"templateParam" yaml:"templateParam"` //模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,若无模板参数,则设置为空*/
|
||||
}
|
||||
|
||||
type externalSendSmsNodeFactory struct{}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/XM-GO/PandaKit/httpclient"
|
||||
"github.com/sirupsen/logrus"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
)
|
||||
@@ -11,7 +13,7 @@ type externalWechatNode struct {
|
||||
MsgType string `json:"msgType" yaml:"msgType"`
|
||||
Content string `json:"content" yaml:"content"`
|
||||
IsAtAll bool `json:"isAtAll" yaml:"isAtAll"`
|
||||
atMobiles []string `json:"atMobiles" yaml:"atMobiles"`
|
||||
AtMobiles []string `json:"atMobiles" yaml:"atMobiles"`
|
||||
}
|
||||
|
||||
type externalWechatNodeFactory struct{}
|
||||
@@ -29,5 +31,29 @@ func (f externalWechatNodeFactory) Create(id string, meta Metadata) (Node, error
|
||||
func (n *externalWechatNode) Handle(msg message.Message) error {
|
||||
logrus.Infof("%s handle message '%s'", n.Name(), msg.GetType())
|
||||
|
||||
successLabelNode := n.GetLinkedNode("Success")
|
||||
failureLabelNode := n.GetLinkedNode("Failure")
|
||||
template, err := ParseTemplate(n.Content, msg.GetAllMap())
|
||||
sendData := map[string]interface{}{
|
||||
"msgtype": "text",
|
||||
"text": map[string]interface{}{"content": template},
|
||||
}
|
||||
if n.IsAtAll {
|
||||
sendData["text"].(map[string]interface{})["mentioned_mobile_list"] = []string{"@all"}
|
||||
} else {
|
||||
sendData["text"].(map[string]interface{})["mentioned_mobile_list"] = n.AtMobiles
|
||||
}
|
||||
marshal, _ := json.Marshal(sendData)
|
||||
postJson := httpclient.NewRequest(n.WebHook).Header("Content-Type", "application/json").PostJson(string(marshal))
|
||||
if postJson.StatusCode != 200 {
|
||||
if failureLabelNode != nil {
|
||||
return failureLabelNode.Handle(msg)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if successLabelNode != nil {
|
||||
return successLabelNode.Handle(msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/sirupsen/logrus"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
)
|
||||
|
||||
const (
|
||||
DEVICE = "DEVICE"
|
||||
GATEWAY = "GATEWAY"
|
||||
)
|
||||
|
||||
//检查关联关系
|
||||
//该消息来自与哪个实体或到那个实体
|
||||
type deviceTypeSwitchNode struct {
|
||||
@@ -21,7 +15,9 @@ type deviceTypeSwitchNodeFactory struct{}
|
||||
|
||||
func (f deviceTypeSwitchNodeFactory) Name() string { return "DeviceTypeSwitchNode" }
|
||||
func (f deviceTypeSwitchNodeFactory) Category() string { return NODE_CATEGORY_FILTER }
|
||||
func (f deviceTypeSwitchNodeFactory) Labels() []string { return []string{DEVICE, GATEWAY} }
|
||||
func (f deviceTypeSwitchNodeFactory) Labels() []string {
|
||||
return []string{message.DEVICE, message.GATEWAY}
|
||||
}
|
||||
func (f deviceTypeSwitchNodeFactory) Create(id string, meta Metadata) (Node, error) {
|
||||
node := &deviceTypeSwitchNode{
|
||||
bareNode: newBareNode(f.Name(), id, meta, f.Labels()),
|
||||
@@ -32,15 +28,18 @@ func (f deviceTypeSwitchNodeFactory) Create(id string, meta Metadata) (Node, err
|
||||
func (n *deviceTypeSwitchNode) Handle(msg message.Message) error {
|
||||
logrus.Infof("%s handle message '%s'", n.Name(), msg.GetType())
|
||||
|
||||
deviceLabelNode := n.GetLinkedNode(DEVICE)
|
||||
gatewayLabelNode := n.GetLinkedNode(GATEWAY)
|
||||
deviceLabelNode := n.GetLinkedNode(message.DEVICE)
|
||||
gatewayLabelNode := n.GetLinkedNode(message.GATEWAY)
|
||||
|
||||
if deviceLabelNode == nil && gatewayLabelNode == nil {
|
||||
return fmt.Errorf("no device and gateway label linked node in %s", n.Name())
|
||||
if msg.GetMetadata().GetKeyValue("deviceType") == message.DEVICE {
|
||||
if deviceLabelNode != nil {
|
||||
return deviceLabelNode.Handle(msg)
|
||||
}
|
||||
}
|
||||
|
||||
if msg.GetMetadata().GetKeyValue("deviceType") == DEVICE {
|
||||
return deviceLabelNode.Handle(msg)
|
||||
if msg.GetMetadata().GetKeyValue("deviceType") == message.GATEWAY {
|
||||
if gatewayLabelNode != nil {
|
||||
return gatewayLabelNode.Handle(msg)
|
||||
}
|
||||
}
|
||||
return gatewayLabelNode.Handle(msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package nodes
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"log"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
)
|
||||
|
||||
@@ -36,7 +35,6 @@ func (n *messageTypeSwitchNode) Handle(msg message.Message) error {
|
||||
|
||||
nodes := n.GetLinkedNodes()
|
||||
messageType := msg.GetType()
|
||||
log.Println("开始执行messageTypeSwitchNode")
|
||||
for label, node := range nodes {
|
||||
if messageType == label {
|
||||
return node.Handle(msg)
|
||||
|
||||
@@ -2,7 +2,6 @@ package nodes
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"log"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
)
|
||||
|
||||
@@ -30,9 +29,8 @@ func (n *scriptFilterNode) Handle(msg message.Message) error {
|
||||
|
||||
trueLabelNode := n.GetLinkedNode("True")
|
||||
falseLabelNode := n.GetLinkedNode("False")
|
||||
scriptEngine := NewScriptEngine()
|
||||
isTrue, error := scriptEngine.ScriptOnFilter(msg, n.Script)
|
||||
log.Println(isTrue)
|
||||
scriptEngine := NewScriptEngine(msg, "Filter", n.Script)
|
||||
isTrue, error := scriptEngine.ScriptOnFilter()
|
||||
if isTrue == true && error == nil && trueLabelNode != nil {
|
||||
return trueLabelNode.Handle(msg)
|
||||
} else {
|
||||
@@ -40,5 +38,6 @@ func (n *scriptFilterNode) Handle(msg message.Message) error {
|
||||
return falseLabelNode.Handle(msg)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package nodes
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"log"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
)
|
||||
|
||||
@@ -36,17 +35,16 @@ func (f switchFilterNodeFactory) Create(id string, meta Metadata) (Node, error)
|
||||
func (n *switchFilterNode) Handle(msg message.Message) error {
|
||||
logrus.Infof("%s handle message '%s'", n.Name(), msg.GetType())
|
||||
|
||||
scriptEngine := NewScriptEngine()
|
||||
SwitchResults, err := scriptEngine.ScriptOnSwitch(msg, n.Script)
|
||||
log.Println("开始执行switchFilterNode", SwitchResults)
|
||||
scriptEngine := NewScriptEngine(msg, "Switch", n.Script)
|
||||
SwitchResults, err := scriptEngine.ScriptOnSwitch()
|
||||
if err != nil {
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
nodes := n.GetLinkedNodes()
|
||||
for label, node := range nodes {
|
||||
for _, switchresult := range SwitchResults {
|
||||
if label == switchresult {
|
||||
node.Handle(msg)
|
||||
go node.Handle(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,4 @@ func init() {
|
||||
RegisterFactory(externalSendSmsNodeFactory{})
|
||||
RegisterFactory(externalRuleChainNodeFactory{})
|
||||
|
||||
RegisterFactory(myNodeFactory{})
|
||||
|
||||
}
|
||||
|
||||
@@ -58,6 +58,6 @@ func (c *nodeMetadata) With(key string, val interface{}) Metadata {
|
||||
}
|
||||
|
||||
func (c *nodeMetadata) DecodePath(rawVal interface{}) error {
|
||||
//return tool.Map2Struct(c.keypairs, rawVal)
|
||||
//return utils.Map2Struct(c.keypairs, rawVal)
|
||||
return mapstructure.Decode(c.keypairs, rawVal)
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ func (n *bareNode) GetLinkedNode(label string) Node {
|
||||
if node, found := n.nodes[label]; found {
|
||||
return node
|
||||
}
|
||||
logrus.Errorf("no label '%s' in node '%s'", label, n.name)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -73,6 +72,7 @@ func GetNodes(m *manifest.Manifest) (map[string]Node, error) {
|
||||
metadata := NewMetadataWithValues(n.Properties)
|
||||
node, err := NewNode(n.Type, n.Id, metadata)
|
||||
if err != nil {
|
||||
logrus.Errorf("new node '%s' failure", n.Id)
|
||||
continue
|
||||
}
|
||||
if _, found := nodes[n.Id]; found {
|
||||
|
||||
@@ -1,36 +1,45 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dop251/goja"
|
||||
"github.com/sirupsen/logrus"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
)
|
||||
|
||||
type ScriptEngine interface {
|
||||
ScriptOnMessage(msg message.Message, script string) (message.Message, error)
|
||||
//used by filter_switch_node
|
||||
ScriptOnSwitch(msg message.Message, script string) ([]string, error)
|
||||
//used by filter_script_node
|
||||
ScriptOnFilter(msg message.Message, script string) (bool, error)
|
||||
ScriptToString(msg message.Message, script string) (string, error)
|
||||
ScriptOnMessage() (message.Message, error)
|
||||
ScriptOnSwitch() ([]string, error)
|
||||
ScriptOnFilter() (bool, error)
|
||||
ScriptToString() (string, error)
|
||||
ScriptAlarmDetails() (map[string]interface{}, error)
|
||||
ScriptGenerate() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
type baseScriptEngine struct {
|
||||
Fun string
|
||||
Script string
|
||||
Msg message.Message
|
||||
}
|
||||
|
||||
func NewScriptEngine() ScriptEngine {
|
||||
return &baseScriptEngine{}
|
||||
func NewScriptEngine(msg message.Message, fun string, script string) ScriptEngine {
|
||||
return &baseScriptEngine{
|
||||
Fun: fun,
|
||||
Script: fmt.Sprintf("function %s(msg, metadata, msgType) { %s }", fun, script),
|
||||
Msg: msg,
|
||||
}
|
||||
}
|
||||
|
||||
func (bse *baseScriptEngine) ScriptOnMessage(msg message.Message, script string) (message.Message, error) {
|
||||
func (bse *baseScriptEngine) ScriptOnMessage() (message.Message, error) {
|
||||
msg := bse.Msg
|
||||
vm := goja.New()
|
||||
_, err := vm.RunString(script)
|
||||
_, err := vm.RunString(bse.Script)
|
||||
if err != nil {
|
||||
logrus.Info("JS代码有问题")
|
||||
return nil, err
|
||||
}
|
||||
var fn func(map[string]interface{}, map[string]interface{}, string) map[string]interface{}
|
||||
err = vm.ExportTo(vm.Get("Transform"), &fn)
|
||||
err = vm.ExportTo(vm.Get(bse.Fun), &fn)
|
||||
if err != nil {
|
||||
logrus.Info("Js函数映射到 Go 函数失败!")
|
||||
return nil, err
|
||||
@@ -40,19 +49,18 @@ func (bse *baseScriptEngine) ScriptOnMessage(msg message.Message, script string)
|
||||
msg.SetMetadata(message.NewDefaultMetadata(datas["metadata"].(map[string]interface{})))
|
||||
msg.SetType(datas["msgType"].(string))
|
||||
return msg, nil
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (bse *baseScriptEngine) ScriptOnSwitch(msg message.Message, script string) ([]string, error) {
|
||||
func (bse *baseScriptEngine) ScriptOnSwitch() ([]string, error) {
|
||||
msg := bse.Msg
|
||||
vm := goja.New()
|
||||
_, err := vm.RunString(script)
|
||||
_, err := vm.RunString(bse.Script)
|
||||
if err != nil {
|
||||
logrus.Info("JS代码有问题")
|
||||
return nil, err
|
||||
}
|
||||
var fn func(map[string]interface{}, map[string]interface{}, string) []string
|
||||
err = vm.ExportTo(vm.Get("Switch"), &fn)
|
||||
err = vm.ExportTo(vm.Get(bse.Fun), &fn)
|
||||
if err != nil {
|
||||
logrus.Info("Js函数映射到 Go 函数失败!")
|
||||
return nil, err
|
||||
@@ -61,15 +69,16 @@ func (bse *baseScriptEngine) ScriptOnSwitch(msg message.Message, script string)
|
||||
return datas, nil
|
||||
}
|
||||
|
||||
func (bse *baseScriptEngine) ScriptOnFilter(msg message.Message, script string) (bool, error) {
|
||||
func (bse *baseScriptEngine) ScriptOnFilter() (bool, error) {
|
||||
msg := bse.Msg
|
||||
vm := goja.New()
|
||||
_, err := vm.RunString(script)
|
||||
_, err := vm.RunString(bse.Script)
|
||||
if err != nil {
|
||||
logrus.Info("JS代码有问题")
|
||||
return false, err
|
||||
}
|
||||
var fn func(map[string]interface{}, map[string]interface{}, string) bool
|
||||
err = vm.ExportTo(vm.Get("Filter"), &fn)
|
||||
err = vm.ExportTo(vm.Get(bse.Fun), &fn)
|
||||
if err != nil {
|
||||
logrus.Info("Js函数映射到 Go 函数失败!")
|
||||
return false, err
|
||||
@@ -78,7 +87,56 @@ func (bse *baseScriptEngine) ScriptOnFilter(msg message.Message, script string)
|
||||
return datas, nil
|
||||
}
|
||||
|
||||
func (bse *baseScriptEngine) ScriptToString(msg message.Message, script string) (string, error) {
|
||||
|
||||
return "", nil
|
||||
func (bse *baseScriptEngine) ScriptToString() (string, error) {
|
||||
msg := bse.Msg
|
||||
vm := goja.New()
|
||||
_, err := vm.RunString(bse.Script)
|
||||
if err != nil {
|
||||
logrus.Info("JS代码有问题")
|
||||
return "", err
|
||||
}
|
||||
var fn func(map[string]interface{}, map[string]interface{}, string) string
|
||||
err = vm.ExportTo(vm.Get(bse.Fun), &fn)
|
||||
if err != nil {
|
||||
logrus.Info("Js函数映射到 Go 函数失败!")
|
||||
return "", err
|
||||
}
|
||||
data := fn(msg.GetMsg(), msg.GetMetadata().GetValues(), msg.GetType())
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (bse *baseScriptEngine) ScriptAlarmDetails() (map[string]interface{}, error) {
|
||||
msg := bse.Msg
|
||||
vm := goja.New()
|
||||
_, err := vm.RunString(bse.Script)
|
||||
if err != nil {
|
||||
logrus.Info("JS代码有问题")
|
||||
return nil, err
|
||||
}
|
||||
var fn func(map[string]interface{}, map[string]interface{}, string) map[string]interface{}
|
||||
err = vm.ExportTo(vm.Get(bse.Fun), &fn)
|
||||
if err != nil {
|
||||
logrus.Info("Js函数映射到 Go 函数失败!")
|
||||
return nil, err
|
||||
}
|
||||
datas := fn(msg.GetMsg(), msg.GetMetadata().GetValues(), msg.GetType())
|
||||
return datas, nil
|
||||
}
|
||||
|
||||
func (bse *baseScriptEngine) ScriptGenerate() (map[string]interface{}, error) {
|
||||
msg := bse.Msg
|
||||
vm := goja.New()
|
||||
_, err := vm.RunString(bse.Script)
|
||||
if err != nil {
|
||||
logrus.Info("JS代码有问题")
|
||||
return nil, err
|
||||
}
|
||||
var fn func(map[string]interface{}, map[string]interface{}, string) map[string]interface{}
|
||||
err = vm.ExportTo(vm.Get(bse.Fun), &fn)
|
||||
if err != nil {
|
||||
logrus.Info("Js函数映射到 Go 函数失败!")
|
||||
return nil, err
|
||||
}
|
||||
datas := fn(msg.GetMsg(), msg.GetMetadata().GetValues(), msg.GetType())
|
||||
return datas, nil
|
||||
}
|
||||
|
||||
19
pkg/rule_engine/nodes/template_engine.go
Normal file
19
pkg/rule_engine/nodes/template_engine.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func ParseTemplate(content string, data map[string]interface{}) (string, error) {
|
||||
tmpl, err := template.New("template").Parse(content)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
buffer := &bytes.Buffer{}
|
||||
err = tmpl.Execute(buffer, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return buffer.String(), nil
|
||||
}
|
||||
@@ -3,12 +3,13 @@ package nodes
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"pandax/pkg/rule_engine/message"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type transformDeleteKeyNode struct {
|
||||
bareNode
|
||||
FormType string `json:"formType" yaml:"formType"` //msg metadata
|
||||
Keys []string `json:"keys" yaml:"keys"`
|
||||
FormType string `json:"formType" yaml:"formType"` //msg metadata
|
||||
Keys string `json:"keys" yaml:"keys"`
|
||||
}
|
||||
type transformDeleteKeyNodeFactory struct{}
|
||||
|
||||
@@ -27,9 +28,10 @@ func (n *transformDeleteKeyNode) Handle(msg message.Message) error {
|
||||
|
||||
successLabelNode := n.GetLinkedNode("Success")
|
||||
failureLabelNode := n.GetLinkedNode("Failure")
|
||||
keys := strings.Split(n.Keys, ",")
|
||||
if n.FormType == "msg" {
|
||||
data := msg.GetMsg()
|
||||
for _, key := range n.Keys {
|
||||
for _, key := range keys {
|
||||
if _, found := data[key]; found {
|
||||
delete(data, key)
|
||||
msg.SetMsg(data)
|
||||
@@ -37,7 +39,7 @@ func (n *transformDeleteKeyNode) Handle(msg message.Message) error {
|
||||
}
|
||||
} else if n.FormType == "metadata" {
|
||||
data := msg.GetMetadata()
|
||||
for _, key := range n.Keys {
|
||||
for _, key := range keys {
|
||||
if data.GetKeyValue(key) != nil {
|
||||
values := data.GetValues()
|
||||
delete(values, key)
|
||||
@@ -45,8 +47,12 @@ func (n *transformDeleteKeyNode) Handle(msg message.Message) error {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
failureLabelNode.Handle(msg)
|
||||
if failureLabelNode != nil {
|
||||
return failureLabelNode.Handle(msg)
|
||||
}
|
||||
}
|
||||
|
||||
return successLabelNode.Handle(msg)
|
||||
if successLabelNode != nil {
|
||||
return successLabelNode.Handle(msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ type transformRenameKeyNode struct {
|
||||
Keys []KeyName `json:"keys" yaml:"keys"`
|
||||
}
|
||||
type KeyName struct {
|
||||
oldName string `json:"oldName" yaml:"oldName"`
|
||||
newName string `json:"newName" yaml:"newName"`
|
||||
OldName string `json:"oldName" yaml:"oldName"`
|
||||
NewName string `json:"newName" yaml:"newName"`
|
||||
}
|
||||
type transformRenameKeyNodeFactory struct{}
|
||||
|
||||
@@ -20,7 +20,7 @@ func (f transformRenameKeyNodeFactory) Name() string { return "RenameKeyNode
|
||||
func (f transformRenameKeyNodeFactory) Category() string { return NODE_CATEGORY_TRANSFORM }
|
||||
func (f transformRenameKeyNodeFactory) Labels() []string { return []string{"Success", "Failure"} }
|
||||
func (f transformRenameKeyNodeFactory) Create(id string, meta Metadata) (Node, error) {
|
||||
node := &transformScriptNode{
|
||||
node := &transformRenameKeyNode{
|
||||
bareNode: newBareNode(f.Name(), id, meta, f.Labels()),
|
||||
}
|
||||
return decodePath(meta, node)
|
||||
@@ -34,25 +34,29 @@ func (n *transformRenameKeyNode) Handle(msg message.Message) error {
|
||||
if n.FormType == "msg" {
|
||||
data := msg.GetMsg()
|
||||
for _, key := range n.Keys {
|
||||
if _, found := data[key.oldName]; found {
|
||||
data[key.newName] = data[key.oldName]
|
||||
delete(data, key.oldName)
|
||||
if _, found := data[key.OldName]; found {
|
||||
data[key.NewName] = data[key.OldName]
|
||||
delete(data, key.OldName)
|
||||
msg.SetMsg(data)
|
||||
}
|
||||
}
|
||||
} else if n.FormType == "metadata" {
|
||||
data := msg.GetMetadata()
|
||||
for _, key := range n.Keys {
|
||||
if data.GetKeyValue(key.oldName) != nil {
|
||||
if data.GetKeyValue(key.OldName) != nil {
|
||||
values := data.GetValues()
|
||||
values[key.newName] = values[key.oldName]
|
||||
delete(values, key.oldName)
|
||||
values[key.NewName] = values[key.OldName]
|
||||
delete(values, key.OldName)
|
||||
msg.SetMetadata(message.NewDefaultMetadata(values))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
failureLabelNode.Handle(msg)
|
||||
if failureLabelNode != nil {
|
||||
return failureLabelNode.Handle(msg)
|
||||
}
|
||||
}
|
||||
|
||||
return successLabelNode.Handle(msg)
|
||||
if successLabelNode != nil {
|
||||
return successLabelNode.Handle(msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -16,9 +16,8 @@ func (f transformScriptNodeFactory) Name() string { return "ScriptNode" }
|
||||
func (f transformScriptNodeFactory) Category() string { return NODE_CATEGORY_TRANSFORM }
|
||||
func (f transformScriptNodeFactory) Labels() []string { return []string{"Success", "Failure"} }
|
||||
func (f transformScriptNodeFactory) Create(id string, meta Metadata) (Node, error) {
|
||||
labels := []string{"Success", "Failure"}
|
||||
node := &transformScriptNode{
|
||||
bareNode: newBareNode(f.Name(), id, meta, labels),
|
||||
bareNode: newBareNode(f.Name(), id, meta, f.Labels()),
|
||||
}
|
||||
return decodePath(meta, node)
|
||||
}
|
||||
@@ -29,10 +28,17 @@ func (n *transformScriptNode) Handle(msg message.Message) error {
|
||||
successLabelNode := n.GetLinkedNode("Success")
|
||||
failureLabelNode := n.GetLinkedNode("Failure")
|
||||
|
||||
scriptEngine := NewScriptEngine()
|
||||
newMessage, err := scriptEngine.ScriptOnMessage(msg, n.Script)
|
||||
scriptEngine := NewScriptEngine(msg, "Transform", n.Script)
|
||||
newMessage, err := scriptEngine.ScriptOnMessage()
|
||||
if err != nil {
|
||||
return failureLabelNode.Handle(msg)
|
||||
if failureLabelNode != nil {
|
||||
return failureLabelNode.Handle(msg)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return successLabelNode.Handle(newMessage)
|
||||
if successLabelNode != nil {
|
||||
return successLabelNode.Handle(newMessage)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
1
pkg/rule_engine/tool/email.go
Normal file
1
pkg/rule_engine/tool/email.go
Normal file
@@ -0,0 +1 @@
|
||||
package tool
|
||||
1
pkg/rule_engine/tool/kafka.go
Normal file
1
pkg/rule_engine/tool/kafka.go
Normal file
@@ -0,0 +1 @@
|
||||
package tool
|
||||
1
pkg/rule_engine/tool/mq.go
Normal file
1
pkg/rule_engine/tool/mq.go
Normal file
@@ -0,0 +1 @@
|
||||
package tool
|
||||
1
pkg/rule_engine/tool/mqtt.go
Normal file
1
pkg/rule_engine/tool/mqtt.go
Normal file
@@ -0,0 +1 @@
|
||||
package tool
|
||||
1
pkg/rule_engine/tool/rest_api.go
Normal file
1
pkg/rule_engine/tool/rest_api.go
Normal file
@@ -0,0 +1 @@
|
||||
package tool
|
||||
1
pkg/rule_engine/tool/sms.go
Normal file
1
pkg/rule_engine/tool/sms.go
Normal file
@@ -0,0 +1 @@
|
||||
package tool
|
||||
Reference in New Issue
Block a user