Pārlūkot izejas kodu

refactor(uiMeta): remove base options and base properties

Signed-off-by: ngjaying <ngjaying@gmail.com>
ngjaying 3 gadi atpakaļ
vecāks
revīzija
29db4f8f3f
4 mainītis faili ar 14 papildinājumiem un 418 dzēšanām
  1. 0 106
      etc/sinks/options.json
  2. 0 147
      etc/sinks/properties.json
  3. 14 141
      plugins/sinkMeta.go
  4. 0 24
      plugins/sinkMeta_test.go

+ 0 - 106
etc/sinks/options.json

@@ -1,106 +0,0 @@
-{
-	"helpUrl": {
-		"en_US": "https://github.com/lf-edge/ekuiper/blob/master/docs/en/rules/overview.md",
-		"zh_CN": "https://github.com/lf-edge/ekuiper/blob/master/docs/zh/rules/overview.md"
-	},
-	"properties": [{
-		"name": "isEventTime",
-		"default":false, 
-		"optional": true,
-		"control": "radio",
-		"type": "bool",
-		"hint": {
-			"en_US": "Whether to use event time or processing time as the timestamp for an event. If event time is used, the timestamp will be extracted from the payload. The timestamp filed must be specified by the stream definition.",
-			"zh_CN": "使用事件时间还是将时间用作事件的时间戳。 如果使用事件时间,则将从有效负载中提取时间戳。 必须通过 stream 定义指定时间戳记。"
-		},
-		"label": {
-			"en_US": "IsEventTime",
-			"zh_CN": "是否使用时间事件"
-		}
-	}, {
-		"name": "lateTolerance",
-		"default": 0,
-		"optional": true,
-		"control": "text",
-		"type": "int",
-		"hint": {
-			"en_US": "When working with event-time windowing, it can happen that elements arrive late. LateTolerance can specify by how much time(unit is millisecond) elements can be late before they are dropped. By default, the value is 0 which means late elements are dropped.",
-			"zh_CN": "在使用事件时间窗口时,可能会出现元素延迟到达的情况。 LateTolerance 可以指定在删除元素之前可以延迟多少时间(单位为 ms)。 默认情况下,该值为0,表示后期元素将被删除。"
-		},
-		"label": {
-			"en_US": "LateTolerance",
-			"zh_CN": "延迟多少毫秒"
-		}
-	}, {
-		"name": "concurrency",
-		"default": 1,
-		"optional": true,
-		"control": "text",
-		"type": "int",
-		"hint": {
-			"en_US": "A rule is processed by several phases of plans according to the sql statement. This option will specify how many instances will be run for each plan. If the value is bigger than 1, the order of the messages may not be retained.",
-			"zh_CN": "一条规则运行时会根据 sql 语句分解成多个 plan 运行。该参数设置每个 plan 运行的线程数。该参数值大于1时,消息处理顺序可能无法保证。"
-		},
-		"label": {
-			"en_US": "Concurrency",
-			"zh_CN": "线程数"
-		}
-	}, {
-		"name": "bufferLength",
-		"default":1024,
-		"optional": true,
-		"control": "text",
-		"type": "int",
-		"hint": {
-			"en_US": "Specify how many messages can be buffered in memory for each plan. If the buffered messages exceed the limit, the plan will block message receiving until the buffered messages have been sent out so that the buffered size is less than the limit. A bigger value will accommodate more throughput but will also take up more memory footprint.",
-			"zh_CN": "指定每个 plan 可缓存消息数。若缓存消息数超过此限制,plan 将阻塞消息接收,直到缓存消息被消费使得缓存消息数目小于限制为止。此选项值越大,则消息吞吐能力越强,但是内存占用也会越多。"
-		},
-		"label": {
-			"en_US": "BufferLength",
-			"zh_CN": "缓存大小"
-		}
-	}, {
-		"name": "sendMetaToSink",
-		"default":false,
-		"optional": true,
-		"control": "radio",
-		"type": "bool",
-		"hint": {
-			"en_US": "Specify whether the meta data of an event will be sent to the sink. If true, the sink can get te meta data information.",
-			"zh_CN": "指定是否将事件的元数据发送到目标。 如果为 true,则目标可以获取元数据信息。"
-		},
-		"label": {
-			"en_US": "SendMetaToSink",
-			"zh_CN": "是否发送元数据"
-		}
-	}, {
-		"name": "qos",
-		"default":0,
-		"optional": true,
-		"control": "select",
-		"type": "list_int",
-    "values":[0,1,2],
-		"hint": {
-			"en_US": "Specify the qos of the stream. The options are 0: At most once; 1: At least once and 2: Exactly once. If qos is bigger than 0, the checkpoint mechanism will be activated to save states periodically so that the rule can be resumed from errors.",
-			"zh_CN": "指定流的 qos。 值为0对应最多一次; 1对应至少一次,2对应恰好一次。 如果 qos 大于0,将激活检查点机制以定期保存状态,以便可以从错误中恢复规则。"
-		},
-		"label": {
-			"en_US": "Qos",
-			"zh_CN": "流的 qos"
-		}
-	}, {
-		"name": "checkpointInterval",
-		"default":300000,
-		"optional": true,
-		"control": "text",
-		"type": "int",
-		"hint": {
-			"en_US": "Specify the time interval in milliseconds to trigger a checkpoint. This is only effective when qos is bigger than 0.",
-			"zh_CN": "指定触发检查点的时间间隔(单位为 ms)。 仅当 qos 大于0时才有效。"
-		},
-		"label": {
-			"en_US": "Intervals",
-			"zh_CN": "检查点间隔毫秒数"
-		}
-	}]
-}

+ 0 - 147
etc/sinks/properties.json

@@ -1,147 +0,0 @@
-{
-	"helpUrl": {
-		"en_US": "https://github.com/lf-edge/ekuiper/blob/master/docs/en/rules/overview.md",
-		"zh_CN": "https://github.com/lf-edge/ekuiper/blob/master/docs/zh/rules/overview.md"
-	},
-	"properties": [{
-		"name": "concurrency",
-		"default":1,
-		"optional":true,
-		"control": "text",
-		"type": "int",
-		"hint": {
-			"en_US": "Specify how many instances of the sink will be run. If the value is bigger than 1, the order of the messages may not be retained.",
-			"zh_CN": "设置运行的线程数。该参数值大于1时,消息发出的顺序可能无法保证。"
-		},
-		"label": {
-			"en_US": "Concurrency",
-			"zh_CN": "线程数"
-		}
-	}, {
-		"name": "bufferLength",
-		"default": 1024,
-		"optional":true,
-		"type": "int",
-		"control": "text",
-		"hint": {
-			"en_US": "Specify how many messages can be buffered in memory. If the buffered messages exceed the limit, the sink will block message receiving until the buffered messages have been sent out so that the buffered size is less than the limit.",
-			"zh_CN": "设置可缓存消息数目。若缓存消息数超过此限制,sink将阻塞消息接收,直到缓存消息被消费使得缓存消息数目小于限制为止。"
-		},
-		"label": {
-			"en_US": "Buffer length",
-			"zh_CN": "缓存大小"
-		}
-	}, {
-		"name": "runAsync",
-		"default": false,
-		"optional":true,
-		"type": "bool",
-		"control": "radio",
-		"hint": {
-			"en_US": "Whether the sink will run asynchronously for better performance. If it is true, the sink result order is not promised.",
-			"zh_CN": "设置是否异步运行输出操作以提升性能。请注意,异步运行的情况下,输出结果顺序不能保证。"
-		},
-		"label": {
-			"en_US": "Run async",
-			"zh_CN": "是否异步运行"
-		}
-	}, {
-		"name": "retryInterval",
-		"default": 1000,
-		"optional":true,
-		"type": "int",
-		"control": "text",
-		"hint": {
-			"en_US": "Specify how many milliseconds will the sink retry to send data out if the previous send failed. If the specified value <= 0, then it will not retry.",
-			"zh_CN": "设置信息发送失败后重试等待时间,单位为毫秒。如果该值的设置 <= 0,那么不会尝试重新发送。"
-		},
-		"label": {
-			"en_US": "Retry interval",
-			"zh_CN": "失败重试间隔毫秒"
-		}
-	}, {
-		"name": "retryCount",
-		"default": 3,
-		"optional":true,
-		"type": "int",
-		"control": "text",
-		"hint": {
-			"en_US": "Specify how many will the sink retry to send data out if the previous send failed. If the specified value <= 0, then it will not retry.",
-			"zh_CN": "设置信息发送失败后重试次数,如果该值的设置 <= 0,那么不会尝试重新发送。"
-		},
-		"label": {
-			"en_US": "Retry count",
-			"zh_CN": "失败重试次数"
-		}
-	}, {
-		"name": "cacheLength",
-		"default": 1024,
-		"optional":true,
-		"type": "int",
-		"control": "text",
-		"hint": {
-			"en_US": "Specify how many messages can be cached. The cached messages will be resent to external system until the data sent out successfully. The cached message will be sent in order except in runAsync or concurrent mode. The cached message will be saved to disk in fixed intervals.",
-			"zh_CN": "设置最大消息缓存数量。缓存的消息会一直保留直到消息发送成功。缓存消息将按顺序发送,除非运行在异步或者并发模式下。缓存消息会定期存储到磁盘中。"
-		},
-		"label": {
-			"en_US": "Cache length",
-			"zh_CN": "最大消息缓存数量"
-		}
-	}, {
-		"name": "cacheSaveInterval",
-		"default": 1024,
-		"optional":true,
-		"type": "int",
-		"control": "text",
-		"hint": {
-			"en_US": "Specify the interval to save cached message to the disk. Notice that, if the rule is closed in plan, all the cached messages will be saved at close. A larger value can reduce the saving overhead but may lose more cache messages when the system is interrupted in error.",
-			"zh_CN": "设置缓存存储间隔时间,单位为毫秒。需要注意的是,当规则关闭时,缓存会自动存储。该值越大,则缓存保存开销越小,但系统意外退出时缓存丢失的风险变大。"
-		},
-		"label": {
-			"en_US": "Cache save interval",
-			"zh_CN": "缓存间隔毫秒"
-		}
-	}, {
-		"name": "omitIfEmpty",
-		"default":false, 
-		"optional": true,
-		"type": "bool",
-		"control": "radio",
-		"hint": {
-			"en_US": "If the configuration item is set to true, when SELECT result is empty, then the result will not feed to sink operator.",
-			"zh_CN": "如果选择结果为空,则忽略输出。"
-		},
-		"label": {
-			"en_US": "Omit if content is empty",
-			"zh_CN": "是否忽略输出"
-		}
-	}, {
-		"name": "sendSingle",
-		"default":true, 
-		"optional": true,
-		"type": "bool",
-		"control": "radio",
-		"hint": {
-			"en_US": "The output messages are received as an array. This is indicate whether to send the results one by one. If false, the output message will be {\"result\":\"${the string of received message}\"}. For example, {\"result\":\"[{\"count\":30},\"\"count\":20}]\"}. Otherwise, the result message will be sent one by one with the actual field name. For the same example as above, it will send {\"count\":30}, then send {\"count\":20} to the RESTful endpoint.Default to false.",
-			"zh_CN": "输出消息以数组形式接收,该属性意味着是否将结果一一发送。 如果为 false,则输出消息将为{\"result\":\"${the string of received message}\"}。 例如,{\"result\":\"[{\"count\":30},\"\"count\":20}]\"}。否则,结果消息将与实际字段名称一一对应发送。 对于与上述相同的示例,它将发送 {\"count\":30},然后发送{\"count\":20} 到 RESTful 端点。默认为 false。"
-		},
-		"label": {
-			"en_US": "Send single",
-			"zh_CN": "将结果数据按条发送"
-		}
-	}, {
-		"name": "dataTemplate",
-		"default":"", 
-		"optional": true,
-		"type": "string",
-		"control": "textarea",
-		"hint": {
-			"en_US": "The golang template format string to specify the output data format. The input of the template is the sink message which is always an array of map. If no data template is specified, the raw input will be the data.",
-			"zh_CN": "Golang 模板格式字符串,用于指定输出数据格式。 模板的输入是目标消息,该消息始终是 map 数组。 如果未指定数据模板,则将数据作为原始输入。"
-		},
-		"label": {
-			"en_US": "Data template",
-			"zh_CN": "数据模版"
-		}
-	}]
-}

+ 14 - 141
plugins/sinkMeta.go

@@ -3,18 +3,14 @@ package plugins
 import (
 	"fmt"
 	"github.com/emqx/kuiper/common"
-	"github.com/emqx/kuiper/xstream/api"
 	"io/ioutil"
 	"path"
-	"reflect"
 	"strings"
 )
 
 const (
-	baseProperty = `properties`
-	baseOption   = `options`
-	sink         = `sink`
-	source       = `source`
+	sink   = `sink`
+	source = `source`
 )
 
 type (
@@ -76,12 +72,10 @@ type (
 	uiSink struct {
 		About  *about   `json:"about"`
 		Libs   []string `json:"libs"`
-		Fields []field  `json:"properties"` // mutable, so each sink must have its own copy
+		Fields []field  `json:"properties"`
 	}
 	uiSinks struct {
-		CustomProperty map[string]uiSink `json:"customProperty"`
-		BaseProperty   map[string]uiSink `json:"baseProperty"`
-		BaseOption     uiSink            `json:"baseOption"`
+		CustomProperty map[string]*uiSink `json:"customProperty"`
 		language       string
 	}
 )
@@ -158,7 +152,7 @@ func newUiSink(fi *fileSink) (*uiSink, error) {
 	return ui, err
 }
 
-var g_sinkMetadata map[string]*uiSink //map[fileName]
+var g_sinkMetadata map[string]*uiSink //immutable
 func (m *Manager) readSinkMetaDir() error {
 	g_sinkMetadata = make(map[string]*uiSink)
 	confDir, err := common.GetConfLoc()
@@ -200,14 +194,12 @@ func (m *Manager) readSinkMetaFile(filePath string) error {
 	if nil != err {
 		return fmt.Errorf("filePath:%s err:%v", filePath, err)
 	}
-	if pluginName != baseProperty && pluginName != baseOption {
-		if nil == metadata.About {
-			return fmt.Errorf("not found about of %s", finame)
-		} else if isInternalSink(finame) {
-			metadata.About.Installed = true
-		} else {
-			_, metadata.About.Installed = m.registry.Get(SINK, pluginName)
-		}
+	if nil == metadata.About {
+		return fmt.Errorf("not found about of %s", finame)
+	} else if isInternalSink(finame) {
+		metadata.About.Installed = true
+	} else {
+		_, metadata.About.Installed = m.registry.Get(SINK, pluginName)
 	}
 	g_sinkMetadata[finame], err = newUiSink(metadata)
 	if nil != err {
@@ -225,130 +217,14 @@ func (us *uiSinks) setCustomProperty(pluginName string) error {
 		return fmt.Errorf(`%s%s`, getMsg(us.language, sink, "not_found_plugin"), pluginName)
 	}
 	if 0 == len(us.CustomProperty) {
-		us.CustomProperty = make(map[string]uiSink)
-	}
-	us.CustomProperty[pluginName] = data.clone()
-	return nil
-}
-
-func (us *uiSinks) setBasePropertry(pluginName string) error {
-	sinkMetadata := g_sinkMetadata
-	data := sinkMetadata[baseProperty+".json"]
-	if nil == data {
-		return fmt.Errorf(`%s%s`, getMsg(us.language, sink, "not_found_plugin"), baseProperty)
-	}
-	if 0 == len(us.BaseProperty) {
-		us.BaseProperty = make(map[string]uiSink)
+		us.CustomProperty = make(map[string]*uiSink)
 	}
-	us.BaseProperty[pluginName] = data.clone()
-	return nil
-}
-
-func (us *uiSinks) setBaseOption() error {
-	sinkMetadata := g_sinkMetadata
-	data := sinkMetadata[baseOption+".json"]
-	if nil == data {
-		return fmt.Errorf(`%s%s`, getMsg(us.language, sink, "not_found_plugin"), baseOption)
-	}
-	us.BaseOption = data.clone()
+	us.CustomProperty[pluginName] = data
 	return nil
 }
 
 func (us *uiSinks) hintWhenNewSink(pluginName string) (err error) {
-	err = us.setCustomProperty(pluginName)
-	if nil != err {
-		return err
-	}
-	err = us.setBasePropertry(pluginName)
-	if nil != err {
-		return err
-	}
-	err = us.setBaseOption()
-	return err
-}
-
-func (us *uiSinks) modifyCustom(uiFields []field, ruleFields map[string]interface{}) (err error) {
-	for i, ui := range uiFields {
-		ruleVal := ruleFields[ui.Name]
-		if nil == ruleVal {
-			continue
-		}
-		if reflect.Map == reflect.TypeOf(ruleVal).Kind() && "object" != ui.Type {
-			var auxRuleFields map[string]interface{}
-			if err := common.MapToStruct(ruleVal, &auxRuleFields); nil != err {
-				return fmt.Errorf(`%s%v %s`, getMsg(us.language, sink, "type_conversion_fail"), err, ui.Name)
-			}
-			var auxUiFields []field
-			if err := common.MapToStruct(ui.Default, &auxUiFields); nil != err {
-				return fmt.Errorf(`%s%v %s`, getMsg(us.language, sink, "type_conversion_fail"), err, ui.Name)
-			}
-			uiFields[i].Default = auxUiFields
-			if err := us.modifyCustom(auxUiFields, auxRuleFields); nil != err {
-				return err
-			}
-		} else {
-			uiFields[i].Default = ruleVal
-		}
-	}
-	return nil
-}
-
-func (u *uiSink) clone() (c uiSink) {
-	c.About = u.About
-	c.Libs = u.Libs
-	c.Fields = make([]field, len(u.Fields))
-	for i, f := range u.Fields {
-		c.Fields[i] = f
-	}
-	return
-}
-
-func (u *uiSink) modifyBase(mapFields map[string]interface{}) {
-	for i, field := range u.Fields {
-		fieldVal := mapFields[field.Name]
-		if nil != fieldVal {
-			u.Fields[i].Default = fieldVal
-		}
-	}
-}
-
-func (us *uiSinks) modifyProperty(pluginName string, mapFields map[string]interface{}) (err error) {
-	custom, ok := us.CustomProperty[pluginName]
-	if !ok {
-		return fmt.Errorf(`%s%s`, getMsg(us.language, sink, "not_found_plugin"), pluginName)
-	}
-	if err = us.modifyCustom(custom.Fields, mapFields); nil != err {
-		return err
-	}
-
-	base, ok := us.BaseProperty[pluginName]
-	if !ok {
-		return fmt.Errorf(`%s%s`, getMsg(us.language, sink, "not_found_plugin"), pluginName)
-	}
-	base.modifyBase(mapFields)
-	return nil
-}
-
-func (us *uiSinks) modifyOption(option *api.RuleOption) {
-	baseOption := us.BaseOption
-	for i, field := range baseOption.Fields {
-		switch field.Name {
-		case `isEventTime`:
-			baseOption.Fields[i].Default = option.IsEventTime
-		case `lateTol`:
-			baseOption.Fields[i].Default = option.LateTol
-		case `concurrency`:
-			baseOption.Fields[i].Default = option.Concurrency
-		case `bufferLength`:
-			baseOption.Fields[i].Default = option.BufferLength
-		case `sendMetaToSink`:
-			baseOption.Fields[i].Default = option.SendMetaToSink
-		case `qos`:
-			baseOption.Fields[i].Default = option.Qos
-		case `checkpointInterval`:
-			baseOption.Fields[i].Default = option.CheckpointInterval
-		}
-	}
+	return us.setCustomProperty(pluginName)
 }
 
 func GetSinkMeta(pluginName, language string) (ptrSinkProperty *uiSinks, err error) {
@@ -366,9 +242,6 @@ type pluginfo struct {
 func GetSinks() (sinks []*pluginfo) {
 	sinkMeta := g_sinkMetadata
 	for fileName, v := range sinkMeta {
-		if fileName == baseProperty+".json" || fileName == baseOption+".json" {
-			continue
-		}
 		node := new(pluginfo)
 		node.Name = strings.TrimSuffix(fileName, `.json`)
 		node.About = v.About

+ 0 - 24
plugins/sinkMeta_test.go

@@ -21,28 +21,10 @@ func TestHintWhenModifySink(t *testing.T) {
 			},
 		},
 	}
-	opMeta := &uiSink{
-		Fields: []field{
-			{
-				Name:    "isEventTime",
-				Default: false,
-			},
-		},
-	}
-	baseMeta := &uiSink{
-		Fields: []field{
-			{
-				Name:    "bufferLength",
-				Default: 911,
-			},
-		},
-	}
 
 	g_sinkMetadata = make(map[string]*uiSink)
 	g_sinkMetadata["taos.json"] = taosMeta
 	g_sinkMetadata["log.json"] = logMeta
-	g_sinkMetadata["properties.json"] = baseMeta
-	g_sinkMetadata["options.json"] = opMeta
 
 	oldSink := new(uiSinks)
 	err := oldSink.hintWhenNewSink("taos")
@@ -50,12 +32,6 @@ func TestHintWhenModifySink(t *testing.T) {
 		t.Error(err)
 	}
 
-	if false != oldSink.BaseOption.Fields[0].Default {
-		t.Errorf("fail")
-	}
-	if 911 != oldSink.BaseProperty["taos"].Fields[0].Default {
-		t.Errorf("fail")
-	}
 	if "911.911.911.911" != oldSink.CustomProperty["taos"].Fields[0].Default {
 		t.Errorf("fail")
 	}